Skip to content

Commit 7829620

Browse files
Merge pull request #775 from OpenWebGAL/fix-assign-to-destroyed-container
fix: assign transform to a destroyed container problem
2 parents fd35764 + 674a669 commit 7829620

9 files changed

Lines changed: 92 additions & 30 deletions

File tree

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

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export interface IAnimationObject {
1717
setEndState: Function;
1818
tickerFunc: PIXI.TickerCallback<number>;
1919
getEndStateEffect?: Function;
20+
forceStopWithoutSetEndState?: Function;
2021
}
2122

2223
interface IStageAnimationObject {
@@ -34,7 +35,7 @@ export interface IStageObject {
3435
uuid: string;
3536
// 一般与作用目标有关
3637
key: string;
37-
pixiContainer: WebGALPixiContainer;
38+
pixiContainer: WebGALPixiContainer | null;
3839
// 相关的源 url
3940
sourceUrl: string;
4041
sourceExt: string;
@@ -235,7 +236,7 @@ export default class PixiStage {
235236
const targetPixiContainer = this.getStageObjByKey(target);
236237
if (targetPixiContainer) {
237238
const container = targetPixiContainer.pixiContainer;
238-
PixiStage.assignTransform(container, effect.transform);
239+
if (container) PixiStage.assignTransform(container, effect.transform);
239240
}
240241
return;
241242
}
@@ -267,6 +268,19 @@ export default class PixiStage {
267268
}
268269
}
269270

271+
public removeAnimationWithoutSetEndState(key: string) {
272+
const index = this.stageAnimations.findIndex((e) => e.key === key);
273+
if (index >= 0) {
274+
const thisTickerFunc = this.stageAnimations[index];
275+
this.currentApp?.ticker.remove(thisTickerFunc.animationObject.tickerFunc);
276+
if (thisTickerFunc.animationObject.forceStopWithoutSetEndState) {
277+
thisTickerFunc.animationObject.forceStopWithoutSetEndState();
278+
}
279+
this.unlockStageObject(thisTickerFunc.targetKey ?? 'default');
280+
this.stageAnimations.splice(index, 1);
281+
}
282+
}
283+
270284
public removeAllAnimations() {
271285
while (this.stageAnimations.length > 0) {
272286
this.removeAnimationByIndex(0);
@@ -776,6 +790,7 @@ export default class PixiStage {
776790
const figureRecordTarget = this.live2dFigureRecorder.find((e) => e.target === key);
777791
if (target && figureRecordTarget?.motion !== motion) {
778792
const container = target.pixiContainer;
793+
if (!container) return;
779794
const children = container.children;
780795
for (const model of children) {
781796
let category_name = motion;
@@ -799,6 +814,7 @@ export default class PixiStage {
799814
if (target?.sourceType !== 'spine') return;
800815

801816
const container = target.pixiContainer;
817+
if (!container) return;
802818
// Spine figure 结构: Container -> Sprite -> Spine
803819
const sprite = container.children[0] as PIXI.Container;
804820
if (sprite?.children?.[0]) {
@@ -825,6 +841,7 @@ export default class PixiStage {
825841
const figureRecordTarget = this.live2dFigureRecorder.find((e) => e.target === key);
826842
if (target && figureRecordTarget?.expression !== expression) {
827843
const container = target.pixiContainer;
844+
if (!container) return;
828845
const children = container.children;
829846
for (const model of children) {
830847
// @ts-ignore
@@ -840,6 +857,7 @@ export default class PixiStage {
840857
const figureRecordTarget = this.live2dFigureRecorder.find((e) => e.target === key);
841858
if (target && !isEqual(figureRecordTarget?.blink, blinkParam)) {
842859
const container = target.pixiContainer;
860+
if (!container) return;
843861
const children = container.children;
844862
let newBlinkParam: BlinkParam = { ...baseBlinkParam, ...blinkParam };
845863
// 继承现有 BlinkParam
@@ -860,6 +878,7 @@ export default class PixiStage {
860878
const figureRecordTarget = this.live2dFigureRecorder.find((e) => e.target === key);
861879
if (target && !isEqual(figureRecordTarget?.focus, focusParam)) {
862880
const container = target.pixiContainer;
881+
if (!container) return;
863882
const children = container.children;
864883
let newFocusParam: FocusParam = { ...baseFocusParam, ...focusParam };
865884
// 继承现有 FocusParam
@@ -883,6 +902,7 @@ export default class PixiStage {
883902
const target = this.figureObjects.find((e) => e.key === key);
884903
if (target && target.sourceType === 'live2d') {
885904
const container = target.pixiContainer;
905+
if (!container) return;
886906
const children = container.children;
887907
for (const model of children) {
888908
// @ts-ignore
@@ -925,20 +945,28 @@ export default class PixiStage {
925945
const indexBg = this.backgroundObjects.findIndex((e) => e.key === key);
926946
if (indexFig >= 0) {
927947
const bgSprite = this.figureObjects[indexFig];
928-
for (const element of bgSprite.pixiContainer.children) {
929-
element.destroy();
948+
if (bgSprite.pixiContainer)
949+
for (const element of bgSprite.pixiContainer.children) {
950+
element.destroy();
951+
}
952+
if (bgSprite.pixiContainer) {
953+
bgSprite.pixiContainer.destroy();
954+
this.figureContainer.removeChild(bgSprite.pixiContainer);
930955
}
931-
bgSprite.pixiContainer.destroy();
932-
this.figureContainer.removeChild(bgSprite.pixiContainer);
956+
bgSprite.pixiContainer = null;
933957
this.figureObjects.splice(indexFig, 1);
934958
}
935959
if (indexBg >= 0) {
936960
const bgSprite = this.backgroundObjects[indexBg];
937-
for (const element of bgSprite.pixiContainer.children) {
938-
element.destroy();
961+
if (bgSprite.pixiContainer)
962+
for (const element of bgSprite.pixiContainer.children) {
963+
element.destroy();
964+
}
965+
if (bgSprite.pixiContainer) {
966+
bgSprite.pixiContainer.destroy();
967+
this.backgroundContainer.removeChild(bgSprite.pixiContainer);
939968
}
940-
bgSprite.pixiContainer.destroy();
941-
this.backgroundContainer.removeChild(bgSprite.pixiContainer);
969+
bgSprite.pixiContainer = null;
942970
this.backgroundObjects.splice(indexBg, 1);
943971
}
944972
// /**

packages/webgal/src/Core/controller/stage/pixi/animations/testblur.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export function generateTestblurAnimationObj(targetKey: string, duration: number
1010
* 在此书写为动画设置初态的操作
1111
*/
1212
function setStartState() {
13-
if (target) {
13+
if (target?.pixiContainer) {
1414
target.pixiContainer.alpha = 0;
1515
// @ts-ignore
1616
target.pixiContainer.blur = 0;
@@ -22,7 +22,7 @@ export function generateTestblurAnimationObj(targetKey: string, duration: number
2222
* 在此书写为动画设置终态的操作
2323
*/
2424
function setEndState() {
25-
if (target) {
25+
if (target?.pixiContainer) {
2626
target.pixiContainer.alpha = 1;
2727
// @ts-ignore
2828
target.pixiContainer.blur = 5;
@@ -40,9 +40,10 @@ export function generateTestblurAnimationObj(targetKey: string, duration: number
4040
const currentAddOplityDelta = (duration / baseDuration) * delta;
4141
const increasement = 1 / currentAddOplityDelta;
4242
const decreasement = 5 / currentAddOplityDelta;
43-
if (container.alpha < 1) {
44-
container.alpha += increasement;
45-
}
43+
if (container)
44+
if (container.alpha < 1) {
45+
container.alpha += increasement;
46+
}
4647
// @ts-ignore
4748
if (container.blur < 5) {
4849
// @ts-ignore

packages/webgal/src/Core/controller/stage/pixi/animations/timeline.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ export function generateTimelineObj(
9292
* 在此书写为动画设置终态的操作
9393
*/
9494
function setEndState() {
95+
if (!container) {
96+
return;
97+
}
9598
if (animateInstance) animateInstance.stop();
9699
animateInstance = null;
97100
if (target?.pixiContainer) {
@@ -126,11 +129,17 @@ export function generateTimelineObj(
126129
return timeline[timeline.length - 1];
127130
}
128131

132+
function forceStopWithoutSetEndState() {
133+
if (animateInstance) animateInstance.stop();
134+
animateInstance = null;
135+
}
136+
129137
return {
130138
setStartState,
131139
setEndState,
132140
tickerFunc,
133141
getEndStateEffect,
142+
forceStopWithoutSetEndState,
134143
};
135144
}
136145

packages/webgal/src/Core/controller/stage/pixi/animations/universalSoftIn.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export function generateUniversalSoftInAnimationObj(targetKey: string, duration:
1212
*/
1313
function setStartState() {
1414
elapsedTime = 0; // Reset timer when animation starts
15-
if (target) {
15+
if (target?.pixiContainer) {
1616
// 修正:不再强制设为 0,而是记录当前的透明度
1717
startAlpha = target.pixiContainer.alpha;
1818
}
@@ -22,7 +22,7 @@ export function generateUniversalSoftInAnimationObj(targetKey: string, duration:
2222
* 在此书写为动画设置终态的操作
2323
*/
2424
function setEndState() {
25-
if (target) {
25+
if (target?.pixiContainer) {
2626
// 终态是完全不透明,这保持不变
2727
target.pixiContainer.alpha = 1;
2828
}
@@ -49,7 +49,7 @@ export function generateUniversalSoftInAnimationObj(targetKey: string, duration:
4949
// 公式:最终值 = 初始值 + (目标值 - 初始值) * 进度
5050
// 在这里,目标值是 1,所以公式为:
5151
// alpha = startAlpha + (1 - startAlpha) * easedProgress
52-
sprite.alpha = startAlpha + (1 - startAlpha) * easedProgress;
52+
if (sprite) sprite.alpha = startAlpha + (1 - startAlpha) * easedProgress;
5353
}
5454
}
5555

packages/webgal/src/Core/controller/stage/pixi/animations/universalSoftOff.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export function generateUniversalSoftOffAnimationObj(targetKey: string, duration
1212
*/
1313
function setStartState() {
1414
elapsedTime = 0; // 重置计时器
15-
if (target) {
15+
if (target?.pixiContainer) {
1616
// 修正:不再强制设为1,而是记录当前的透明度
1717
startAlpha = target.pixiContainer.alpha;
1818
}
@@ -22,7 +22,7 @@ export function generateUniversalSoftOffAnimationObj(targetKey: string, duration
2222
* 在此书写为动画设置终态的操作
2323
*/
2424
function setEndState() {
25-
if (target) {
25+
if (target?.pixiContainer) {
2626
// 终态是完全透明,这保持不变
2727
target.pixiContainer.alpha = 0;
2828
}
@@ -50,7 +50,7 @@ export function generateUniversalSoftOffAnimationObj(targetKey: string, duration
5050
// 在这里,目标值是 0,所以公式简化为:
5151
// alpha = startAlpha + (0 - startAlpha) * easedProgress
5252
// alpha = startAlpha * (1 - easedProgress)
53-
targetContainer.alpha = startAlpha * (1 - easedProgress);
53+
if (targetContainer) targetContainer.alpha = startAlpha * (1 - easedProgress);
5454
}
5555
}
5656

packages/webgal/src/Core/gameScripts/changeBg/index.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,15 @@ export const changeBg = (sentence: ISentence): IPerform => {
3232
dispatch(unlockCgInUserData({ name: unlockName, url, series }));
3333
}
3434

35+
/**
36+
* 判断背景 URL 是否发生了变化
37+
*/
38+
const isUrlChanged = webgalStore.getState().stage.bgName !== sentence.content;
39+
3540
/**
3641
* 删掉相关 Effects,因为已经移除了
3742
*/
38-
if (webgalStore.getState().stage.bgName !== sentence.content) {
43+
if (isUrlChanged) {
3944
dispatch(stageActions.removeEffectByTargetId(`bg-main`));
4045
}
4146

@@ -85,6 +90,17 @@ export const changeBg = (sentence: ISentence): IPerform => {
8590
duration = getAnimateDuration(exitAnimation);
8691
}
8792

93+
/**
94+
* 背景状态后处理
95+
*/
96+
function postBgStateSet() {
97+
if (isUrlChanged) {
98+
// 当 URL 发生变化时,清理旧的 hold 动画
99+
WebGAL.gameplay.performController.unmountPerform(`animation-bg-main`, true);
100+
}
101+
}
102+
103+
postBgStateSet();
88104
dispatch(setStage({ key: 'bgName', value: sentence.content }));
89105

90106
return {

packages/webgal/src/Core/gameScripts/changeFigure.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,12 @@ export function changeFigure(sentence: ISentence): IPerform {
196196
}
197197
};
198198

199-
function setFigureData() {
199+
function postFigureStateSet() {
200200
if (isUrlChanged) {
201201
// 当 url 发生变化时,即发生新立绘替换
202202
// 应当赋予一些参数以默认值,防止从旧立绘的状态获取数据
203+
// 并且关闭一些 hold 动画
204+
WebGAL.gameplay.performController.unmountPerform(`animation-${key}`, true);
203205
bounds = bounds ?? [0, 0, 0, 0];
204206
blink = blink ?? cloneDeep(baseBlinkParam);
205207
focus = focus ?? cloneDeep(baseFocusParam);
@@ -236,7 +238,7 @@ export function changeFigure(sentence: ISentence): IPerform {
236238
*/
237239
const freeFigureItem: IFreeFigure = { key, name: content, basePosition: pos };
238240
setAnimationNames(key, sentence);
239-
setFigureData();
241+
postFigureStateSet();
240242
dispatch(stageActions.setFreeFigureByKey(freeFigureItem));
241243
} else {
242244
/**
@@ -255,7 +257,7 @@ export function changeFigure(sentence: ISentence): IPerform {
255257

256258
key = positionMap[pos];
257259
setAnimationNames(key, sentence);
258-
setFigureData();
260+
postFigureStateSet();
259261
dispatch(setStage({ key: dispatchMap[pos], value: content }));
260262
}
261263

packages/webgal/src/Core/gameScripts/setTransform.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,11 @@ export const setTransform = (sentence: ISentence): IPerform => {
4646
const animationDuration = getAnimateDuration(animationName);
4747

4848
const key = `${target}-${animationName}-${animationDuration}`;
49-
let stopFunction = () => {};
49+
let keepAnimationStopped = false;
5050
setTimeout(() => {
51+
if (keep && keepAnimationStopped) {
52+
return;
53+
}
5154
WebGAL.gameplay.pixiStage?.stopPresetAnimationOnTarget(target);
5255
const animationObj: IAnimationObject | null = getAnimationObject(
5356
animationName,
@@ -60,10 +63,13 @@ export const setTransform = (sentence: ISentence): IPerform => {
6063
WebGAL.gameplay.pixiStage?.registerAnimation(animationObj, key, target);
6164
}
6265
}, 0);
63-
stopFunction = () => {
66+
const stopFunction = () => {
67+
if (keep) {
68+
WebGAL.gameplay.pixiStage?.removeAnimationWithoutSetEndState(key);
69+
keepAnimationStopped = true;
70+
return;
71+
}
6472
setTimeout(() => {
65-
const endDialogKey = webgalStore.getState().stage.currentDialogKey;
66-
const isHasNext = startDialogKey !== endDialogKey;
6773
WebGAL.gameplay.pixiStage?.removeAnimationWithSetEffects(key);
6874
}, 0);
6975
};

packages/webgal/src/Stage/MainStage/useSetFigure.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export function useSetFigure(stageState: IStageState) {
6363
useEffect(() => {
6464
Object.entries(figureMetaData).forEach(([key, value]) => {
6565
const figureObject = WebGAL.gameplay.pixiStage?.getStageObjByKey(key);
66-
if (figureObject && !figureObject.isExiting && value?.zIndex !== undefined) {
66+
if (figureObject && !figureObject.isExiting && value?.zIndex !== undefined && figureObject.pixiContainer) {
6767
figureObject.pixiContainer.zIndex = value.zIndex;
6868
}
6969
});

0 commit comments

Comments
 (0)