-
Notifications
You must be signed in to change notification settings - Fork 15
refactor(story-player): 抽出共享 DOTween ease 曲线库与 TweenRunner ease/loop 选项 - #407
refactor(story-player): 抽出共享 DOTween ease 曲线库与 TweenRunner ease/loop 选项 #407daflyinbed wants to merge 2 commits into
Conversation
review 跟进,两处收尾: - setImageTween 原本自己算 dotweenEaseCurve 再在 step 回调里 ease(raw), 绕过了 #407 新加的 TweenRunOptions。数值等价,但这样一来整个 stack 里 options 就没有任何生产调用方,也和 #407 约定的 { ease, loops } 调用形状 不一致。改为透传 options.ease;对应单测的 tween stub 也照 run 的方式 施加曲线,顺带把"曲线确实经 options 传下去"锁进断言。 - imageSprite 字段在 root/sprite 拆分后已无人读取(生产代码全部改用 imageRoot),原 PR 把它从 private 放开成 public 只是为了给单测取内层 sprite。直接删掉,单测改读 imageRoot.children[0]——noUnusedLocals 本来也不允许留一个只写不读的私有字段。
StarHeartHunt
commented
Sep 6, 2026
|
对着 2.7.71 (build 2771) 的 链路证据:
1. Elastic 三条曲线的 amplitude 用错(数值偏差可观)
comiss xmm9(1.0), xmm12(overshootOrAmplitude) ja loc_1841F1955 ; 仅当 1.0 > overshoot 时:amp = 1, s = period * 0.25 ; 否则 → Asin 分支:amp 保持原值,s = period / 2pi * asin(1 / amp) overshoot = 1.70158 ≥ 1,所以 原实现用的是 easings.net 那套 amplitude=1 形式(
端点有 early-out 所以现有的"端点锚定"用例测不出来,已补上中间点断言。全语料没有 Elastic ease,属潜伏问题,不影响线上。 顺带确认 Back 族是对的(1.70158、InOutBack ×ばつ1.525 与 native 一致),Bounce 族对照 2. 序数 0(
|
c630bf3 to
41063a1
Compare
...op 选项 - core/DotweenEase.ts: DOTween Ease 枚举全曲线移植(含 Flash 族与 EaseManager.Evaluate 的超枚举 default 分支),dotweenEaseCurve 按 GetEnum<Ease>(ignoreCase:false) 语义解析枚举名/整数串(含负数) - core/TweenRunner.run 增加 options(ease/loops),loops<0 映射 SetLoops 无限 Restart 循环,仅在 isAlive 失效时 settle - PixiStoryRenderer 私有 tween helper 透传 options - tests: tweenEase.spec / tweenRunner.spec
2.7.71 复核发现曲线库有三处与 native 不符,并补上 CgItemPanel 的合流。 1. Elastic 三条曲线的 amplitude 用错。`SetEase<T>(t, Ease)` @ 0x1848859d0 只写 easeType(flash 族额外做一次 int 截断),从不重置 overshoot/period; `DOTween..cctor` @ 0x1841bb710 的 defaultEaseOvershootOrAmplitude = 1.70158 由 `Tweener.Setup` @ 0x184896a60 拷进每个 tween。因此 `Evaluate` @ 0x1841f1170 的 elastic 分支不走 `overshootOrAmplitude < 1` 的钳位: amplitude 保持 1.70158,相移是 period/2pi*asin(1/amplitude) 而非 period/4。 原实现用的是 easings.net 的 amplitude=1 形式(2pi/3、2pi/4.5 常量), 偏差可观 —— OutElastic(0.1) 应为 1.84614 而非 1.25,InElastic(0.9) 应为 +0.34614 而非 -0.25(连符号都相反)。语料暂无 Elastic ease,属潜伏问题。 2. 序数 0(Ease.Unset)应落 OutQuad 而非 Linear。`Evaluate` 的入口守卫是 `(uint)(easeType - 1) > 0x24`,只有 1..37 有 case,Unset 与超表序数一样 走 default 分支(OutQuad 抛物线)。GetEnum 的解析回落是序数 1(Linear), 与序数 0 是两回事,原注释把两者混为一谈。 3. 曲线表是对象字面量,按名取值会命中 Object.prototype 的继承成员: ease="toString" 返回字符串(progress 变 NaN),ease="valueOf" / "hasOwnProperty" / "__proto__" 直接抛 TypeError,全都能绕过 ?? 兜底。 剧本文本是 wiki 可编辑内容,改为 Object.hasOwn 自有属性查找。 顺带按 native 补上 int32 溢出的序数回落(Int32.Parse 抛错 → GetEnum 捕获 → Linear)。 另外: - Flash 族的 (-1 / 0) 前提是错的,实际是 SetEase 截断后的 amplitude=1、 period=0;二者数值恰好等价(已逐点比对,ease="OutFlash" 渲染不变), 但 WeightedEase/多波循环按构造不可达,塌缩为 min(1, wave(time))。 - CgItemPanel 仍带着一份 3 条曲线、且 `ease.toLowerCase()` 大小写不敏感的 私有实现,与它自己注释里的 ignoreCase: false 相悖;并入 dotweenEaseCurve。 - TweenRunner 按 `SetLoops` @ 0x184885f00 钳位(0 → 1,< -1 → -1), 并删掉 loops === 1 时与取模分支恒等的死代码。 - 曲线表改用 satisfies,序数表里写错键名现在会编译失败。 - 出处地址统一到 2.7.71 (build 2771)。
41063a1 to
d7a8db5
Compare
review 跟进,两处收尾: - setImageTween 原本自己算 dotweenEaseCurve 再在 step 回调里 ease(raw), 绕过了 #407 新加的 TweenRunOptions。数值等价,但这样一来整个 stack 里 options 就没有任何生产调用方,也和 #407 约定的 { ease, loops } 调用形状 不一致。改为透传 options.ease;对应单测的 tween stub 也照 run 的方式 施加曲线,顺带把"曲线确实经 options 传下去"锁进断言。 - imageSprite 字段在 root/sprite 拆分后已无人读取(生产代码全部改用 imageRoot),原 PR 把它从 private 放开成 public 只是为了给单测取内层 sprite。直接删掉,单测改读 imageRoot.children[0]——noUnusedLocals 本来也不允许留一个只写不读的私有字段。
Uh oh!
There was an error while loading. Please reload this page.
背景
backgroundtween/imagetween/largebgtween/largeimgtween的 ease/loop 修复(#358/#348/#361/#362)此前各自携带一份 DOTween 曲线实现(#361/#362 的 TweenRunner 内联表逐字节相同,#348 又在 PixiStoryRenderer 内联一份)。本 PR 把这份共享基础设施抽成独立模块,四个命令 PR 改为基于本 PR。native 依据(2.7.61 / build 2761 GameAssembly.dll IDA 复核)
DG.Tweening.Core.Easing.EaseManager.Evaluate@ 0x184140b40(Robert Penner 方程;超枚举域数值走 default 分支 = OutQuad 抛物线,INTERNAL_Zero恒 1),Bounce/Flash辅助类 @ 0x18413fb50-0x1841438a0。DotNetExtensionMethods.GetEnum<Ease>(param, "ease", 默认立即数 1 = Ease.Linear, ignoreCase: false)选曲线:枚举名大小写敏感,整数字符串按 ordinal(ease="6"= OutQuad,负数与超表 ordinal 走 EaseManager default 分支 = OutQuad),解析失败回落 Linear。loop喂SetLoops(2*!loop - 1):true → -1即无限 Restart 循环(每轮回 From 重放,OnComplete 永不触发),false → 1单次。修复内容
1. 新增
core/DotweenEase.ts(曲线库,取自 #358 的完整移植)Ease枚举曲线(0-37),含 Flash 族直译(Flash.Ease@ 0x184143780 等:Flash 实现对overshootOrAmplitude/period不做哨兵替换,库级 SetEase 默认 (-1/0) 原样进公式,每段波退化为平面二次曲线——按公式带默认值直译)。注意:这取代了 fix(story-player): largebgtween/largeimgtween 实现 ease/loop 参数与 intinity lop 告警 #361 /fix(story-player): largeimgtween 实现 ease/loop 参数并修正 duration 默认值 #362 /fix(story-player): imagetween 缩放坐标空间对齐 native localScale 并实现 ease #348 里"Flash 不移植、回落 Linear"的简化,超集且更贴 native。dotweenEaseCurve(ease)按 GetEnum 语义解析(名字大小写敏感 / 整数串含负数按 ordinal / 超表 ordinal → OutQuad default 分支 / 其余回落 Linear)。2.
core/TweenRunner.run增加options?: TweenRunOptionsoptions.ease:逐周期曲线(默认 Linear);options.loops:SetLoopsRestart 语义,负数无限循环——每周期从 From 重放,仅在isAlive失效时 settle(调用方不得对其 await 阻塞)。3.
PixiStoryRenderer私有tweenhelper 透传options命令侧调用点统一
{ ease: dotweenEaseCurve(input.ease), loops: input.loop ? -1 : 1 }形状,由各命令 PR 提供。测试
tests/tweenEase.spec.ts:名字/ordinal(含负数与超表)/Flash/端点锚定;tests/tweenRunner.spec.ts:ease 步进、Restart 周期重放、无限循环仅在 isAlive 失效时 settle。后续