-
-
Notifications
You must be signed in to change notification settings - Fork 288
fix: missing sync animation #734
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: missing sync animation #734
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary of Changes
Hello @HardyNLee, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request resolves a critical animation bug in Webgal Terre, particularly affecting the syncWithOrigine
functionality and experimental fast preview mode, where animations would disappear or conflict. The changes focus on robust animation lifecycle management, ensuring proper cleanup of timeouts, comprehensive stage animation resets, and intelligent application of entry animations for stage elements to maintain visual consistency and prevent unintended overrides.
Highlights
- Improved Animation Management: Perform-related timeouts are now correctly tracked and cleared by adding them to
performController.timeoutList
. This prevents animation conflicts that previously occurred due to uncleared timeouts. - Comprehensive Stage Reset: A new
removeAllAnimations()
method has been introduced inPixiController
and integrated into theresetStage
function. This ensures all active animations are explicitly cleared when the stage is reset, resolving issues with lingering old animations. - Smarter Background Effect Handling: The logic for removing background effects (
bg-main
) has been refined. Effects are now only removed if the background content (bgName
) has actually changed, preventing unintended clearing of effects during previews where the background remains the same. - Conditional Entry Animations: Entry animations for both figures and backgrounds are now applied conditionally. They will only trigger if the stage element (figure or background) does not already have an active effect in the
stage.effects
state. This is crucial for correct behavior with experimental fast preview, preventing new entry animations from overriding existing effects from the backlog state.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command>
or @gemini-code-assist <command>
. Below is a summary of the supported commands.
Feature | Command | Description |
---|---|---|
Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/
folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request effectively addresses animation synchronization issues. I've provided suggestions to improve code clarity, efficiency, and maintainability by refactoring duplicated code and adhering to React best practices.
public removeAllAnimations() { | ||
while (this.stageAnimations.length > 0) { | ||
this.removeAnimationByIndex(0); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation of removeAllAnimations
uses a while
loop, which can be inefficient if the number of animations is large. A more performant approach would be to iterate through the array once to perform the cleanup actions and then clear the array. This would have a time complexity of O(n).
public removeAllAnimations() {
this.stageAnimations.forEach((animation) => {
this.currentApp?.ticker.remove(animation.animationObject.tickerFunc);
animation.animationObject.setEndState();
this.unlockStageObject(animation.targetKey ?? 'default');
});
this.stageAnimations.length = 0;
}
let isRemoveEffects = true; | ||
if (webgalStore.getState().stage.bgName === sentence.content) { | ||
isRemoveEffects = false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const transformState = webgalStore.getState().stage.effects; | ||
const targetEffect = transformState.find((effect) => effect.target === thisBgKey); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To avoid potential race conditions, use the stageState
prop for consistency within React's render cycle, rather than calling webgalStore.getState()
directly.
const transformState = webgalStore.getState().stage.effects; | |
const targetEffect = transformState.find((effect) => effect.target === thisBgKey); | |
const targetEffect = stageState.effects.find((effect) => effect.target === thisBgKey); |
const transformState = webgalStore.getState().stage.effects; | ||
const targetEffect = transformState.find((effect) => effect.target === thisFigKey); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To avoid potential race conditions, use the stageState
prop to get the effects list, ensuring consistency with React's data flow.
const transformState = webgalStore.getState().stage.effects; | |
const targetEffect = transformState.find((effect) => effect.target === thisFigKey); | |
const targetEffect = stageState.effects.find((effect) => effect.target === thisFigKey); |
const transformState = webgalStore.getState().stage.effects; | ||
const targetEffect = transformState.find((effect) => effect.target === thisFigKey); | ||
|
||
if (!targetEffect) { | ||
const { duration, animation } = getEnterExitAnimation(thisFigKey, 'enter'); | ||
WebGAL.gameplay.pixiStage!.registerPresetAnimation( | ||
animation, | ||
softInAniKey, | ||
thisFigKey, | ||
stageState.effects, | ||
); | ||
setTimeout(() => WebGAL.gameplay.pixiStage!.removeAnimationWithSetEffects(softInAniKey), duration); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This block of code for conditionally playing an entrance animation is repeated multiple times in this file and also in useSetBg.ts
. To improve maintainability, extract this logic into a shared helper function.
function playEnterAnimationIfNeeded(
targetKey: string,
animationKey: string,
effects: IEffect[],
) {
const targetEffect = effects.find((effect) => effect.target === targetKey);
if (!targetEffect) {
const { duration, animation } = getEnterExitAnimation(targetKey, 'enter');
WebGAL.gameplay.pixiStage!.registerPresetAnimation(
animation,
animationKey,
targetKey,
effects,
);
setTimeout(
() => WebGAL.gameplay.pixiStage!.removeAnimationWithSetEffects(animationKey),
duration,
);
}
}
// Usage:
playEnterAnimationIfNeeded(thisFigKey, softInAniKey, stageState.effects);
if (script.args.find((e) => e.key === 'continue' && e.value === true)) perform.goNextWhenOver = true; | ||
|
||
this.performList.push(perform); | ||
this.timeoutList.push(perform.stopTimeout); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
注意到 48 行在 perform 中记录了 stopTimeout。这里的记录是必须的吗?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个是有作用的, 有些 stopFunction 关联的是 removeAnimation, 它是根据 target 名称移除动画的, 这使得新的同目标的动画, 会被旧的没清理的 timeout 的 stopFunction 给清掉, 实际测试不加这行的话, 连续快速同步同目标的动画, 会被旧的 timeout 给打断
编辑: 不是同 target, 而是同 key, 而自从 #711 后, setTransform, setTempAnimation, setAnimation 的 key 不在用随机数, 而是相同的了, 合并 #717 后 changeBg 和 changeFigure 也是相同的了
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我的意思是,这里是否不用单独开这个 timeoutList 记录,需要用的时候通过遍历演出表 performList.map(p=>p.stopTimeout) 就可以拿到所有的 timeout 了
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
看了下代码,这个 timeoutList 确实是很早就存在的,但是一直没有使用,可能是因为 performList 中已经有足够信息了。额外维护一个 list 会增加复杂度。因为遍历 performList 理论上应该可以获得所有 timeout 。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
已移除 perform controller
中的 timeout list
此外,建议装一个 eslint 插件,以使得提交的代码进一步符合 WebGAL 项目的规范。 |
const dispatch = webgalStore.dispatch; | ||
if (name !== '') dispatch(unlockCgInUserData({ name, url, series })); | ||
|
||
let isRemoveEffects = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isRemoveEffects 只在这里使用了,那么这里的代码应该有进一步简化的空间
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
已修改
嗯, 注册预设动画确实没问题, 在最新的提交中, 已将改动范围缩减至 getEnterExitAnimation 中
这个还是不行, 测试结果是, 仍然要判断是否存在 effect, 否则依然会触发实验性快速预览的 bug, 不过我目前也有点盲人摸象了, 不确定真正的原因是什么 |
介绍
完全修复
syncWithOrigine
的 "动画未结束的情况下进行同步,引起的动画消失的问题" , 包括实验性快速预览 ,这使得 Webgal Terre 预览时不再丢失动画这个 Bug 实际上是由多个问题叠加导致的
主要更改
performController.timeoutList
resetStage
时, 清除所有动画 (stage.removeAllAnimations()
)bgName !== sentence.content
时移除 bg-main 的 effectinitState
变换到backlogState
, 如果 backlogState 里有figName
bgName
, 会触发它们的出场动画, 但是很多情况下, 这些立绘和背景并不是在这一句出场, effect list 是有它们的 effect 的, 于是出场动画的 effect 覆盖了原本应该使用的在 backlog 里的 effect, 导致效果未正确继承已知问题