Skip to content

Commit 38c149b

Browse files
committed
feat: on-demand rendering
1 parent f191b10 commit 38c149b

File tree

2 files changed

+84
-4
lines changed

2 files changed

+84
-4
lines changed

packages/webgal/src/Core/controller/stage/pixi/PixiController.ts

Lines changed: 82 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,12 @@ export default class PixiStage {
8888
public frameDuration = 16.67;
8989
public notUpdateBacklogEffects = false;
9090
public readonly figureContainer: PIXI.Container;
91-
public figureObjects: Array<IStageObject> = [];
91+
public figureObjects = this.createReactiveList<IStageObject>([]);
9292
public stageWidth = SCREEN_CONSTANTS.width;
9393
public stageHeight = SCREEN_CONSTANTS.height;
9494
public assetLoader = new PIXI.Loader();
9595
public readonly backgroundContainer: PIXI.Container;
96-
public backgroundObjects: Array<IStageObject> = [];
96+
public backgroundObjects = this.createReactiveList<IStageObject>([]);
9797
public mainStageObject: IStageObject;
9898
/**
9999
* 添加 Spine 立绘
@@ -104,11 +104,15 @@ export default class PixiStage {
104104
public addSpineFigure = addSpineFigureImpl.bind(this);
105105
public addSpineBg = addSpineBgImpl.bind(this);
106106
// 注册到 Ticker 上的函数
107-
private stageAnimations: Array<IStageAnimationObject> = [];
107+
private stageAnimations = this.createReactiveList<IStageAnimationObject>([]);
108108
private loadQueue: { url: string; callback: () => void; name?: string }[] = [];
109109
private live2dFigureRecorder: Array<ILive2DRecord> = [];
110110
// 锁定变换对象(对象可能正在执行动画,不能应用变换)
111111
private lockTransformTarget: Array<string> = [];
112+
// 手动请求渲染防抖标记
113+
private isRenderPending = false;
114+
// 更新 ticker 状态的防抖标记
115+
private isTickerUpdatePending = false;
112116

113117
/**
114118
* 暂时没用上,以后可能用
@@ -121,6 +125,7 @@ export default class PixiStage {
121125
const app = new PIXI.Application({
122126
backgroundAlpha: 0,
123127
preserveDrawingBuffer: true,
128+
autoStart: false,
124129
});
125130
// @ts-ignore
126131

@@ -194,7 +199,22 @@ export default class PixiStage {
194199
this.callLoader();
195200
};
196201
reload();
197-
this.initialize().then(() => {});
202+
this.initialize().then(() => { });
203+
this.requestRender();
204+
}
205+
206+
public requestRender() {
207+
if (this.isRenderPending) return;
208+
this.isRenderPending = true;
209+
210+
Promise.resolve().then(() => {
211+
requestAnimationFrame(() => {
212+
this.isRenderPending = false;
213+
if (!this.currentApp?.ticker.started) {
214+
this.currentApp?.render();
215+
}
216+
});
217+
});
198218
}
199219

200220
public getFigureObjects() {
@@ -346,6 +366,7 @@ export default class PixiStage {
346366
return;
347367
}
348368
sprite.texture = texture;
369+
this.requestRender();
349370
});
350371
}
351372

@@ -374,6 +395,7 @@ export default class PixiStage {
374395
return;
375396
}
376397
sprite.texture = texture;
398+
this.requestRender();
377399
});
378400
}
379401

@@ -436,6 +458,7 @@ export default class PixiStage {
436458

437459
// 挂载
438460
thisBgContainer.addChild(bgSprite);
461+
this.requestRender();
439462
}
440463
}, 0);
441464
};
@@ -610,6 +633,7 @@ export default class PixiStage {
610633
}
611634
thisFigureContainer.pivot.set(0, this.stageHeight / 2);
612635
thisFigureContainer.addChild(figureSprite);
636+
this.requestRender();
613637
}
614638
}, 0);
615639
};
@@ -1100,6 +1124,60 @@ export default class PixiStage {
11001124
console.error('Failed to load figureCash:', error);
11011125
}
11021126
}
1127+
1128+
private createReactiveList<T extends object>(array: T[]): T[] {
1129+
return new Proxy(array, {
1130+
// eslint-disable-next-line max-params
1131+
set: (target, property, value, receiver) => {
1132+
const result = Reflect.set(target, property, value, receiver);
1133+
if (property !== 'length') {
1134+
this.updateTickerStatus();
1135+
} else {
1136+
this.updateTickerStatus();
1137+
}
1138+
return result;
1139+
},
1140+
deleteProperty: (target, property) => {
1141+
const result = Reflect.deleteProperty(target, property);
1142+
this.updateTickerStatus();
1143+
return result;
1144+
},
1145+
});
1146+
}
1147+
1148+
private updateTickerStatus() {
1149+
if (this.isTickerUpdatePending) return;
1150+
this.isTickerUpdatePending = true;
1151+
1152+
Promise.resolve().then(() => {
1153+
this.isTickerUpdatePending = false;
1154+
const app = this.currentApp;
1155+
if (!app) return;
1156+
1157+
const hasActiveAnimations = this.stageAnimations.length > 0;
1158+
const hasLive2D = this.figureObjects.some((fig) => fig.sourceType === 'live2d');
1159+
const hasSpine = this.figureObjects.some((fig) => fig.sourceType === 'spine');
1160+
const hasDynamicBg = this.backgroundObjects.some((bg) => bg.sourceType === 'video' || bg.sourceType === 'gif');
1161+
const hasGifFigure = this.figureObjects.some((fig) => fig.sourceType === 'gif');
1162+
1163+
const shouldRun = hasActiveAnimations || hasLive2D || hasSpine || hasDynamicBg || hasGifFigure;
1164+
1165+
if (shouldRun) {
1166+
if (!app.ticker.started) {
1167+
app.ticker.start();
1168+
logger.debug('Ticker: STARTED');
1169+
}
1170+
} else {
1171+
if (app.ticker.started) {
1172+
app.ticker.stop();
1173+
this.currentApp?.render();
1174+
logger.debug('Ticker: STOPPED');
1175+
} else {
1176+
this.requestRender();
1177+
}
1178+
}
1179+
});
1180+
}
11031181
}
11041182

11051183
function updateCurrentBacklogEffects(newEffects: IEffect[]) {

packages/webgal/src/Core/controller/storage/jumpFromBacklog.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ export const restorePerform = () => {
2424
performToRestore.forEach((e) => {
2525
runScript(e.script);
2626
});
27+
// 重新渲染
28+
WebGAL.gameplay.pixiStage?.requestRender();
2729
};
2830

2931
/**

0 commit comments

Comments
 (0)