fix: #987 next 后接场景跳转失效问题#995
Conversation
There was a problem hiding this comment.
Code Review
This pull request refactors the gameplay progression logic by separating user-initiated stepping (nextSentence) from internal engine progression (continueSentence). This prevents internal events (like scene transitions or input submissions) from being incorrectly treated as user interactions. The review feedback suggests implementing a debounce mechanism for goNextWhenOver to prevent double-stepping issues when multiple parallel performs finish in the same tick, and adding defensive checks to ensure commitForward() is only called if forward() succeeds.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| import { IPerform } from '@/Core/Modules/perform/performInterface'; | ||
| import { ISentence } from '@/Core/controller/scene/sceneInterface'; | ||
| import { nextSentence } from '@/Core/controller/gamePlay/nextSentence'; | ||
| import { continueSentence } from '@/Core/controller/gamePlay/nextSentence'; | ||
| import { WEBGAL_NONE } from '@/Core/constants'; | ||
| import { getBooleanArgByKey } from '@/Core/util/getSentenceArg'; | ||
| import { stageStateManager } from '@/Core/Modules/stage/stageStateManager'; |
There was a problem hiding this comment.
为了解决多个并行演出(parallel performs)在同一帧/同一 Tick 结束或被卸载时,多次触发 goNextWhenOver 导致游戏意外跳过多个句子的潜在 Bug,建议对 goNextWhenOver 进行防抖(debounce)处理。
我们可以在文件顶部声明一个 goNextOverTimeoutMap,用于存储每个 PerformController 实例的定时器。
import { IPerform } from '@/Core/Modules/perform/performInterface';
import { ISentence } from '@/Core/controller/scene/sceneInterface';
import { continueSentence } from '@/Core/controller/gamePlay/nextSentence';
import { WEBGAL_NONE } from '@/Core/constants';
import { getBooleanArgByKey } from '@/Core/util/getSentenceArg';
import { stageStateManager } from '@/Core/Modules/stage/stageStateManager';
const goNextOverTimeoutMap = new WeakMap<any, ReturnType<typeof setTimeout>>();| private goNextWhenOver = () => { | ||
| let isBlockingNext = false; | ||
| this.performList?.forEach((e) => { |
There was a problem hiding this comment.
在这里,我们通过 goNextOverTimeoutMap 获取并清除已有的定时器,然后将执行逻辑包装在 setTimeout(..., 0) 中。这样在同一个 Tick 内多次调用 goNextWhenOver 时,只有最后一次会真正执行,从而完美避免了多重推进(double-stepping)的 Bug。
private goNextWhenOver = () => {
const existingTimeout = goNextOverTimeoutMap.get(this);
if (existingTimeout) clearTimeout(existingTimeout);
const timeout = setTimeout(() => {
goNextOverTimeoutMap.delete(this);
let isBlockingNext = false;
this.performList?.forEach((e) => {| // 有阻塞,提前结束 | ||
| setTimeout(this.goNextWhenOver, 100); | ||
| } else { | ||
| nextSentence(); | ||
| continueSentence(); | ||
| } | ||
| }; |
There was a problem hiding this comment.
配合顶部的防抖逻辑,在定时器回调中,如果检测到仍有阻塞的演出,则在 100ms 后重新调度;否则安全地调用 continueSentence()。最后将定时器存入 goNextOverTimeoutMap。
// 有阻塞,提前结束
const retryTimeout = setTimeout(this.goNextWhenOver, 100);
goNextOverTimeoutMap.set(this, retryTimeout);
} else {
continueSentence();
}
}, 0);
goNextOverTimeoutMap.set(this, timeout);
};| forward(); | ||
| commitForward(); |
Deploying webgal-dev with
|
| Latest commit: |
bce063a
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://98594f64.webgal-dev.pages.dev |
| Branch Preview URL: | https://fix-next-scene.webgal-dev.pages.dev |
Close #987
添加一个“内部继续推进”,防止因为之前的动画没结束,preforward 认为无法继续推进,阻挡 changeScene 等 script 跳到新场景后,自动执行的 nextSentence 不作用的问题。