Initial project sync
This commit is contained in:
@@ -0,0 +1,696 @@
|
||||
# Migration Decisions
|
||||
|
||||
## 2026-07-06 第八轮:视差语义定案(远景天幕,夕阳恒在画面内)
|
||||
|
||||
策划澄清视差意图:背景是**远景天幕**,夕阳要时刻在画面内——即背景应
|
||||
大比例**跟随相机**(远景几乎不动的错觉),而非此前理解的"背景比世界慢
|
||||
一点"。此前 0.92/0.8 的参数把背景几乎钉在世界上,方向整个反了,这才是
|
||||
连续几轮"看不出视差"的真因。
|
||||
|
||||
1. **参数**:`PARALLAX_SCROLL_SCALE := 0.2`(背景仅以 0.2 倍速随世界滚动,
|
||||
80% 跟随相机);`PARALLAX_ANCHOR_X := 1734.5`(让夕阳——原画 x≈760、
|
||||
世界 x≈1656——在出生点镜头可见中心 1340.8 恰好居中)。
|
||||
2. **验算+截图验证**:相机可见中心全程 [1340.8, 2753.2],夕阳屏幕位置从
|
||||
正中缓移到左 282px,始终在画面内(含光晕);两端背景覆盖充足
|
||||
(极左窗⊂[581.5,2882.5]、极右窗⊂[1711.5,4012.5])。窗口化实测四点
|
||||
截图确认:出生点夕阳居中、中段/封门处缓移仍在画面中央区域,未来
|
||||
相位(红色天幕)同样成立;世界物件大幅滚动 vs 天幕缓动的对比即
|
||||
视差观感本体。
|
||||
3. **已知取舍加剧说明**:天幕语义下步道砖(烙在原画里)随镜头大幅跟随
|
||||
(奔跑时脚下滑动 176px/s)——单张烙死图的固有代价;美术把"近景步道"
|
||||
拆成独立 1:1 层后即可消除,其余层保持现参数。
|
||||
4. 可视化验证配方(复用):manage_scene=false + 手动挂 main.tscn +
|
||||
start_game(),Title 态直接 _set_state 不行(树暂停 + 标题屏不透明底色)。
|
||||
|
||||
## 2026-07-06 第七轮修复(玩家与敌人重叠:冲刺穿人收尾排斥)
|
||||
|
||||
策划确认:冲刺穿人机制保留,其余时间玩家不得与小怪/Boss 重叠。
|
||||
|
||||
1. **调查结论**:身体碰撞矩阵完整且实测有效(玩家 layer32/mask65,敌人
|
||||
layer64/mask33,平移互撞精确挡在半宽和 19px)。重叠的真实来源是
|
||||
dash_through 的收尾策略:落点嵌在敌人体内时,恢复碰撞的逻辑"干等分离"
|
||||
(07-04 定案,防止嵌入恢复被反推回入口侧)——嵌着就无限期保持幽灵态,
|
||||
玩家可长期站在敌人身体里;期间敌人 AI 还会照常向玩家中心走位,把重叠
|
||||
"续命"。叠加事实:Godot 的 move_and_slide 对已重叠的双方永不主动分离
|
||||
(safe_margin 0.001),所以一旦嵌入只能靠显式排斥。
|
||||
2. **修复**:MotionExecutor 记录冲刺方向;`_try_restore_collision` 嵌入时
|
||||
不再干等,每物理帧沿冲刺方向 `move_and_collide` 推 4px(240px/s,快于
|
||||
小怪追击 120px/s),顶到边界墙推不动则反向从入口侧退出;推清后恢复
|
||||
碰撞。幽灵掩码只剩 world 位,排斥不可能进入地形。"从远侧穿出"的
|
||||
07-04 手感语义保留;cancel 的非物理帧即时恢复路径不变(有测试钉)。
|
||||
3. **不动的部分**:敌人互相不碰撞(minion/boss mask 无 bit64,成群穿插是
|
||||
现状设计);小怪尸体在死亡动画期间仍挡路(存量怪癖);Boss 战前
|
||||
combat_enabled=false 非实体是有意豁免(test_level1_melee_contact 钉)。
|
||||
4. 契约测试 test_dash_overlap_separation:嵌入落点 45 帧内推出+恢复碰撞+
|
||||
从远侧穿出+间距 ≥ 半宽和;干净落点行为与旧版一致。
|
||||
|
||||
## 2026-07-06 第六轮修复(Boss→玩家击退 / 视差加强重启)
|
||||
|
||||
**语义澄清**:策划三轮反馈的"Boss 击退"实指 **Boss 攻击玩家时对玩家的击退**
|
||||
(第三~五轮修的"玩家击退 Boss"方向保留不回退)。
|
||||
|
||||
1. **Boss→玩家击退不可见的三个根因**:①Boss 近战沿用默认基准 120,普通
|
||||
连段倍率仅 0.4/0.5 → 滑行 2~3px(重击也只 20~37px);②敌方弹丸基准击退
|
||||
恒为 (0,0)(actors_container 只给敌弹注 speed),Boss 未来相位只用远程 →
|
||||
整相位击退数学上为零(.tres 里的 0.3/0.5 倍率是死数值);③相机 1:1 跟随
|
||||
玩家——玩家被击退时自己在屏幕上不动,只有背景平移,小位移完全无感。
|
||||
2. **修复**:boss.tscn DamageEmitter 覆写 `base_knockback = (360, 304.056)`
|
||||
(初速 ×3 = 距离 ×9):连段 20/32px、重击 190/341px;敌方弹丸生成时注入
|
||||
`base_knockback = (360, 0)`(不击飞):Boss 射击 11~32px、女巫 8~15px,
|
||||
强弱势归零规则照常生效。Boss 恒强势(is_strong_in_current_time_phase
|
||||
恒 true),玩家 Hitstun 0.4s 内不能起手/移动,滑行不受自身动作干扰。
|
||||
调参 knob:boss.tscn 的 base_knockback 一处 + actors_container.gd 注入值。
|
||||
3. **视差加强重启**:0.92 时代偏移峰值仅 ±56px、实战镜头段 ±20px,肉眼难辨
|
||||
(策划"看不出视差"两轮反馈的真因;上一轮误判为"脚下打滑"而回退)。现
|
||||
`PARALLAX_SCROLL_SCALE := 0.8`,峰值 ±141px、实战段 ±60px。已知取舍:
|
||||
步道砖烙在原画里会随镜头轻微滑动(0.8 下奔跑时约 44px/s),策划若不接受
|
||||
只能等美术拆层(无伤视差的唯一解,接线半小时)。
|
||||
|
||||
## 2026-07-06 第五轮修复(击退被反向突进吃掉 / 视差回退)
|
||||
|
||||
1. **Boss 实战零击退的真凶:自己的下一拍动作**。裸场景击退管线全通过,但
|
||||
真实 stage 里 Boss 被击退 3 帧后就照常起手攻击(attack 态还冻结摩擦衰减),
|
||||
随后动作自带的突进位移接管 velocity 以 -375px/s 冲回玩家——实测净位移
|
||||
**-24px**(比不击退还近)。修复:**趔趄门禁**——击退残速期
|
||||
`can_start_enemy_action` 返回 false(EnemyActionDriver 的 BT/谱面双路径
|
||||
都走此钩子),滑行完整播完 AI 才恢复;小怪加同款钩子。Boss 受击链强制
|
||||
撤退豁免:`_trigger_hit_chain_escape` 先 `clear_knockback_stray()`(新增
|
||||
motor 公开方法)再起手 boss_retreat_dash,否则 4 连击逃脱被门禁拦死。
|
||||
真实 stage 探针验证:位移 -24px → **+132px**(≈理论 129.6)。
|
||||
2. **单层微视差回退**。可行走步道砖烙在关卡原画里,整图 0.92 倍速 =
|
||||
角色脚下地砖打滑(策划反馈"视差有问题"即此)。逐像素核查后确认横向
|
||||
分层缝也不可行:油灯底座 y495-520、栅栏柱脚 y485-495、锚徽 y495-555、
|
||||
步道面 y495-550 相互咬合,任何水平缝都会把显眼物件剪成两截随视差错位;
|
||||
左右边界石墙纵贯全高更无法归层。结论:**单张烙死的图做不了无伤视差**,
|
||||
已回退到背景钉死,契约改为"背景不得随相机移动"。真视差待美术按
|
||||
"天空/远景海船/中景码头道具/近景步道"拆层出带透明通道的 PNG(宽度均
|
||||
≥2301+视差余量),接线约半小时(每层 Sprite2D + 相机可见中心 × 系数,
|
||||
勿用 Parallax2D——历史上因 CanvasModulate/wipe 兼容性移除过)。
|
||||
|
||||
## 2026-07-05 第四轮修复(Boss 击退加码 ×9 / 小怪击退修复 / 单层微视差)
|
||||
|
||||
1. **Boss 击退距离 ×3 → ×9**:首轮 ×3(滑行 43px 级)试玩仍嫌短,策划要求再
|
||||
×3。`boss.knockback_distance_taken_mult()` 3.0→9.0(初速 ×3)。斩波 Lv1
|
||||
击退 Boss ≈130px、下砸 ≈634px;嫌多嫌少改这一个返回值即可。
|
||||
2. **小怪击退修复(结构 bug,与 Boss 同源)**:minion.tscn 挂着 MovementMotor
|
||||
但 minion.gd 零引用——击退初速写入后下一帧就被 AI 接管/清零,且 motor 的
|
||||
摩擦衰减和假高度积分从不执行。修复:新增 movement_motor 成员;
|
||||
handle_air_time 无条件委托 motor(boss 同款);handle_movement 在相位切换
|
||||
hold **之后**加击退残速早退(换相位定身优先)。顺带修掉隐藏 bug:垂直击退
|
||||
曾令小怪 ground_state 永久卡 Airborne,从此 allowed_ground_states 拒绝一切
|
||||
出招——现在假高度正常积分、落地复位 Grounded。小怪不加距离倍率(基准
|
||||
15~70px 滑行),策划试玩后如需加码再走 knockback_distance_taken_mult 钩子。
|
||||
3. **关卡背景单层微视差**:ground_background.gd 新增 _process——ArtLayer.x =
|
||||
基准 + (相机可见中心 − 2047) × 0.08,即背景水平速度为相机的 0.92 倍
|
||||
(PARALLAX_SCROLL_SCALE)。锚点 2047 = GroundAnchor = battle_center =
|
||||
贴图中心;极限位移 ±56.5px,已验算两端不露边(顺带修掉了原有的极右
|
||||
16.5px 潜在露边)。用 get_screen_center_position()(含 limit 夹取)而非
|
||||
camera.global_position,玩家贴墙时背景不跟滑;无相机(headless/菜单)
|
||||
保持原位。手写每帧位移而非 Parallax2D:历史上 Parallax2D 因
|
||||
CanvasModulate/wipe 兼容性已被移除过(见下方历史条目)。真·多层视差
|
||||
(天空/远景/近景分速度)等美术拆层素材到位后再升级。
|
||||
4. **修复存量 flake**:test_rhythm_feedback_and_move_list 的特殊拍断言依赖
|
||||
"启动后 0.46s 内跑到检查点"(RhythmManager 墙钟自启动,_upcoming_beat_index
|
||||
走实时钟),启动稍慢即越过第 1 拍。按测试纪律钉停时钟(stop_manager),
|
||||
走确定性 _last_beat_index 兜底。6 连跑验证。
|
||||
5. 契约测试 test_round4_fixes 钉住小怪水平滑行/残速自清/垂直击退落地恢复、
|
||||
视差公式与无相机兜底;Boss ×9 更新在 test_round3_fixes。
|
||||
|
||||
## 2026-07-05 第三轮修复(标题背景重组 / 判定字样 1s 消失 / Boss 击退 ×3)
|
||||
|
||||
1. **标题画面重组**:背景弃用烙有 Logo 的整图(start_background_past/future),
|
||||
改用无 Logo 的干净关卡原画 `assets/art/ground/past/past.png` 与
|
||||
`future/future.png`(与关卡内背景同资产),Logo 由独立悬浮 TextureRect
|
||||
(`TITLE_LOGO_RECT` = 390,140,616×300,MOUSE_FILTER_IGNORE)叠加。背景轮换
|
||||
周期改为策划口径"2 秒为单位渐入切换":`TITLE_BG_HOLD_SECONDS` 2.8→2.0、
|
||||
`TITLE_BG_FADE_SECONDS` 1.6→0.8。渐变期间 Logo/菜单固定,顶部重叠感消除。
|
||||
难度选择页同步换干净未来原画 + 悬浮 Logo。双背景节点名与 `_title_bg_tween`
|
||||
变量契约保持不变(test_title_music_and_background 无需改动)。
|
||||
2. **判定字样 1 秒自动消失**:rhythm_track 新增 `JUDGEMENT_VISIBLE_SECONDS=1.0`
|
||||
倒计时;每次 `_show_judgement_art`(普通判定/锚点 held/TIME SHIFT 三条路径)
|
||||
重置计时("顶替"语义),到点把 JudgementArt/JudgementLabel 一并隐藏。倒计时
|
||||
期间不动 modulate/text/scale,与脉冲动画及判定色互不干扰。
|
||||
3. **Boss 击退距离 ×3**:调查发现 Boss(水平)击退位移实际恒为 0——boss.gd
|
||||
`handle_movement()` 每物理帧无条件 `velocity.x = 0.0`,击退初速活不过一帧
|
||||
(headless 实测 61 帧位移 0.00px)。修复:MovementMotor 暴露
|
||||
`has_knockback_stray()`,Boss 在击退残速期跳过清零、交给 480px/s² 摩擦自然
|
||||
衰减(与玩家同路径,不用被 test_boss_integration 禁止的本地计时器 hack)。
|
||||
距离 ×3 通过受击方鸭子钩子 `knockback_distance_taken_mult()=3.0` 实现,
|
||||
CombatManager 按 距离∝初速² 换算为初速 ×√3;只放大水平滑行,击飞不变。
|
||||
实测 120 初速滑行 14.4px→43.3px。小怪存在同类清零问题(minion.gd AI 每帧
|
||||
接管 velocity.x),策划未提,本轮未动。
|
||||
4. 契约测试 test_round3_fixes 钉住以上全部行为(背景资产路径、2s/0.8s 常量、
|
||||
悬浮 Logo 几何与鼠标穿透、判定 1s 消失+顶替重置、Boss 击退倍率与残速存活)。
|
||||
|
||||
## 2026-07-05 第二轮需求落地(剑雨放大 / 敌弹降速 / 菜单组件化 / 结算重做 / 受击朝向修复)
|
||||
|
||||
依据策划当日九条答复的最终口径:
|
||||
|
||||
1. **剑雨放大一倍(伤害不变)**:6 个 jian_yu .tres 的 `range` 140→280(三级判定
|
||||
仍相同);落剑视觉 strike_count `1+level`→`2*(1+level)`(4/6/8 把)、spread
|
||||
`90+40*level`→`120+40*level`(Lv3 最远落点 40+240=280 恰与新判定对齐,顺带修复
|
||||
旧版"视觉铺 250px 但判定只有 140px"的空气剑);BLADE_RAIN_TILE_SPECS 四条目
|
||||
scale 0.5→1.0(raindrop 跟随)。damage_mult/base_cost 一字未动。
|
||||
test_blade_rain_alignment 的 Lv3 数量断言 4→8。
|
||||
2. **敌弹降速 80%(斩波不变)**:actors_container.gd 新增
|
||||
`ENEMY_PROJECTILE_SPEED := 416.0`(520×0.8),非玩家阵营弹丸生成时覆写 speed;
|
||||
玩家弹保持 player_projectile.gd 默认 520。销毁按累计飞行距离,降速不缩射程。
|
||||
3. **受击朝向修复(策划定案:保持受击前朝向)**:双根因双修——
|
||||
① combat_manager._apply_knockback 按受击者与 result["from"](emitter 位置)的
|
||||
x 差把水平击退方向化为"背离攻击者"(dx=0 或缺 from 保留旧 +X);result dict
|
||||
里的 knockback 数值保持 resolver 原值,纯数值契约测试不受影响。
|
||||
② movement_motor 新增 `_knockback_stray_active` 标记:apply_knockback 置位、
|
||||
残速衰减到 0 或自主移动接管时清除;set_heading 在标记存活或 life_state !=
|
||||
Alive 时不改写 heading。玩家/敌人同语义(受击不转身)。
|
||||
4. **菜单组件化(废弃整图+透明热区)**:新素材套件入库 assets/ui/menu2/
|
||||
(面板 panel_tall + 按钮底两态 button_base_normal/hover + 文字贴图 13 张 +
|
||||
Logo title_logo),中文字体 assets/fonts/fzzdhjw.ttf。game_flow_manager 全部
|
||||
界面改为"面板 + StyleBoxTexture 双态按钮 + 文字贴图/字体"拼装:标题(Logo+
|
||||
三键+当前难度页脚)、难度选择(简单/普通/困难+开始/回标题+页脚,选中=高亮橙
|
||||
框)、暂停/确认框/胜负 splash(NinePatch 面板;确认框用 确认/取消 贴图)、
|
||||
结算(整面板+游戏结算标题字)。按钮保持 Button 类型 + 旧点击矩形兼容坐标测试;
|
||||
过去/未来场景背景轮换保留。素材里的"结束游戏"按策划答复弃用。
|
||||
5. **结算重做**:统计标签中文化(最大连击/完美/良好/勉强/失误/锚点成功/相位
|
||||
切换,fzzdhjw 字体渲染);RANK 只留等级("RANK S",去掉 "(83/100)" 分数),
|
||||
失败仍不显示 RANK。胜负停留时间 ×3:VICTORY_SCREEN_DELAY 1.2→3.6s、
|
||||
DEFEAT_SCREEN_DELAY 1.6→4.8s;保留两段式(胜负 splash → 查看结算 → 结算)。
|
||||
6. **胜负合成音效(策划定案:合成音,不引音频文件)**:SfxManager 新增
|
||||
&"victory"(C5-E5-G5-C6 上行琶音 1.2s)与 &"defeat"(G4-Eb4-C4-G3 分立下行
|
||||
1.3s,与 &"death" 滑音区分);订阅 EventBus.flow_state_changed,进入
|
||||
Victory/Defeat 态时播放(voice 继承 PROCESS_MODE_ALWAYS,暂停树可发声);
|
||||
玩家死亡瞬间的 &"death" 保留叠加。
|
||||
7. 新契约测试 test_round2_changes(剑雨数值、敌/我弹速、击退方向、朝向门禁、
|
||||
延迟常量、结算中文与 RANK 格式、难度页脚联动)。
|
||||
8. 顺带修复的存量测试问题:①四个对难度敏感的测试(startup_fix / time_phase_adapter /
|
||||
ui_animation_regression / v2_core_contracts)此前隐性依赖 menu 测试残留在
|
||||
settings.cfg 的 easy 难度,现已显式钉 easy;②三处过时断言改到现口径——相位强势
|
||||
倍率实为 ×1.4(资源 07-04 校准)、谱面预告标记已有意停用(钉住"不生成")、combo
|
||||
HUD 脉冲断言改抓命名槽位 Slot1;③test_stage4_movement_physics 的固定秒数等待
|
||||
会被 ANCHOR_ACTIVE 起手拉伸打败(偶发 flake),改为物理帧轮询。
|
||||
|
||||
## 2026-07-05 new1/new2/new3 需求落地(判定门控 / 左侧出生 / 怪物与 Boss 行为)
|
||||
|
||||
依据 docs/new1-3.md 与策划当日答疑的最终口径(new1 原文的"零代价无效输入"
|
||||
已被策划改为"MISS+锁定"混合方案):
|
||||
|
||||
1. **判定门控(new1 定案)**:RhythmManager 新增 `gate_judged_input` /
|
||||
`is_input_locked`(`input_lockout_seconds` 0.5、`consumed_repeat_grace` 1)。
|
||||
规则:每个节奏点只能被一次有效输入消耗;同拍第二次按键按双击容错忽略;
|
||||
第三次(或超出 BAD 窗的空按)判 MISS——保留原惩罚(无动作、清连击、四拍
|
||||
槽写 ∅)并触发 0.5s 输入锁定,锁定期间按键完全无效(不判定、不留痕、不
|
||||
刷新锁定)。纯判定接口 judge/get_rating_for_time 保持无副作用;门控只作
|
||||
用于**实时判定**的输入(_ensure_judged 打 `live` 标记),测试/AI 的预置
|
||||
判定原样绕过。接入点:ActionController.submit_intent 主路径 +
|
||||
两个蓄力施放路径。锁定横跨时间锚点拍 = 锚点必破(相位切换),设计确认。
|
||||
test_player_combo_input 顺带修复:每次按键前把时钟钉到新拍心,替代旧的
|
||||
墙钟判定(~20% flake 消除)。新测试 test_input_gate。
|
||||
2. **出生点左移(new2)**:stage.tscn 玩家 (2047,560)→(1180,560),相机初始
|
||||
(1180,395);开场需向右推进约 1000px 才遇预置近战怪(2200 不变,策划确认
|
||||
该段路用于熟悉操作)。LevelDirector 的战斗中心/增援锚点不变。标题固定+
|
||||
背景轮播本就已实现,未改动。基线测试(x1_visual_baseline /
|
||||
rhythm_ui_layout / boss_integration / level1_melee_contact /
|
||||
minion_phase_system)中依赖旧出生点的断言改为按门线/停步距离取位。
|
||||
3. **伤害体系(new3 定案)**:保留"基础攻击 × 相位倍率"。近战小怪基础攻击
|
||||
翻倍 25→50(LevelDirector 按 MinionBehavior.role 配置 emitter.damage,
|
||||
远程保持 25);Boss 近战招式倍率翻倍(combo 0.8/0.9→1.6/1.8;重击保守
|
||||
放大 combo_3 1.4→2.2、lunging_stab 2.0→3.0,未按字面 ×2 以免单跳 120),
|
||||
Boss 远程倍率下调 shoot 0.6→0.4(30×0.4=12 恰合 new3 推荐)、2way
|
||||
0.7→0.45。
|
||||
4. **距离参数(new3)**:近战怪警戒 420→360、停步 110→120、出手距离
|
||||
150→120、攻击判定 range 58~74→130(前方 reach≈140);远程怪危险距离
|
||||
150→220、后撤 190→220、后撤完毕按拍停顿 1 拍;**射程上限压到视距内**
|
||||
(攻击距离 430→450 ≤ 相机半宽 460——绝不屏幕外开火,new3 的 720 被策划
|
||||
否决)。Boss melee_distance 135→180、ranged 260→360、dash 360→460。
|
||||
5. **远程怪受击脱离(策划定案,取代 new3 §5.5 的单次受击)**:连续受击 4 次
|
||||
(2s 链窗)触发闪烁无敌 0.4s + 跳跃形式脱离(escape_speed_scale 3.2;
|
||||
minion.gd 的 approach_direction 钳制放宽到 ±4);无敌走
|
||||
FrameCollisionDriver.damage_receiver_enabled(驱动器每帧重申矩阵,直接改
|
||||
Area2D 会被覆盖);3s 冷却防连续触发;贴墙时沿用穿过玩家身位的反向跳。
|
||||
6. **Boss 霸体(策划定案,取代 new3 §6.5 韧性系统——明确不做韧性)**:
|
||||
CombatResolver 新增受击方 `shrugs_off_hit(action)` 钩子;Boss 对
|
||||
base_cost≤0 的攻击恒霸体(伤害照常、打断与击退取消),耗能技能可压制。
|
||||
所有耗能技能补上击退:dash_slash 1.5、combo_finisher 2.0、ground_smash
|
||||
2.2(保留原 y1.8 击飞)、zhan_bo 1.0/1.3/1.6、jian_yu 0.8/y0.6;玩家弹丸
|
||||
在 ActorsContainer 注入 base_knockback(120,304)(原为零)。保留"被连打
|
||||
4 次后撤逃脱"作为防贴脸兜底。resolve_knockback 顺带修复为跟随伤害判定
|
||||
通道(good 0.85),对齐 test_combat_manager_resolvers 既有契约。
|
||||
7. **Boss 相位行为(new3 §6.4/6.7)**:远程相位被近身(≤240px)优先
|
||||
boss_retreat_dash 拉开(后撤无伤害、8 拍冷却);相位切换后停顿 1 拍再
|
||||
决策(以总线最后拍号为基准,兼容测试合成拍号)。stage.tscn 的 Boss
|
||||
stationary=true 保持——那是战前木桩状态,BossRoomGate 反锁时已会释放。
|
||||
新测试 test_new3_enemy_rules(霸体规则/按职责基础攻击/受击脱离)。
|
||||
|
||||
## 2026-07-04 playtest pass 2 (dash pierce / anchor presentation / radial phase wipe)
|
||||
|
||||
1. **Dash-through actually pierces now.** Two compounding defects: (a) action
|
||||
displacement speed was computed over the full action length while the
|
||||
motion only runs from Active start to action end, so every action
|
||||
under-travelled by the startup fraction — the 260px dash realized ~195px
|
||||
and frequently ENDED inside the boss; (b) the collision mask snapped back
|
||||
the moment the action finished, so ending overlapped meant depenetration
|
||||
shoved the player back out the entry side ("did not pierce").
|
||||
Fixes: `_action_motion_speed` divides by (action_beats - startup_beats);
|
||||
MotionExecutor ghosts BOTH directions during dash_through (strips
|
||||
player_body|enemy_body bits from mask AND layer so neither side's
|
||||
move_and_slide recovery can shove anyone), and restores collision
|
||||
deferred — each physics frame it shape-queries the ghosted body layers
|
||||
and only snaps back once clear of overlap. Outside physics frames
|
||||
(headless tests) restore is immediate, keeping the existing
|
||||
test_stage4_movement_physics contract green.
|
||||
2. **Time anchor presentation follows the upgrade semantics.** The mirrored
|
||||
red pair converging every anchor beat read as "recolored beat balls",
|
||||
and at high streak tiers (interval 1) it doubled screen elements. Now:
|
||||
the beat movers THEMSELVES turn anchor-red when the beat they converge on
|
||||
is an anchor (screen element count never exceeds the rhythm grid).
|
||||
Follow-up: the extra "herald" ball that parked above the center emblem was
|
||||
judged redundant in playtest (the recolored movers + the HUD "ANCHOR Nb"
|
||||
countdown carry the information) and was removed entirely — time anchors
|
||||
add zero elements to the track. Held/broken feedback unchanged.
|
||||
3. **Phase switch is a player-centered radial wipe.** Scene tint now lives
|
||||
solely on the CanvasModulate (stronger: past warm 1.0/0.94/0.82, future
|
||||
cool 0.55/0.72/1.0; the color-mapped ground reads as the other map). On
|
||||
time_phase_changed the world gets the NEW tint instantly and a fullscreen
|
||||
blend_mul shader multiplies everything OUTSIDE an expanding circle
|
||||
(centered on the player, radius 0 → screen diagonal in 0.5s) by
|
||||
old_tint/new_tint — the old scene visibly dissolves outward from the
|
||||
player, with a bright rim at the wavefront. Works symmetrically in both
|
||||
switch directions; the wipe center follows the player each frame.
|
||||
|
||||
## 2026-07-04 action feel pass (mirroring / air slam / dash derive / charge gauge / dummy boss)
|
||||
|
||||
Fixes driven by playtest feedback against the player_tagged author sheets:
|
||||
|
||||
1. **Blade wave cast mirroring.** zhan_bo has no displacement and no left/right
|
||||
tag, so the body never turned while the projectile aimed at the nearest
|
||||
boss. `_play_action_animation` now faces projectile actions
|
||||
(`hit_type == projectile` or `projectile` tag) toward
|
||||
`projectile_direction()`; the whole Visual (body + FX overlay) mirrors
|
||||
with heading as usual.
|
||||
2. **Air combo is a ground slam.** The author's 12-Aerial Combo sheets are
|
||||
byte-identical to 13-Plunging Strike (PREP / SWING START / FALLING [LOOP] /
|
||||
LAND + FX2/3/4): the move is a forward slam, not an in-air slash. atk_air
|
||||
gained the falling loop segment + FX3 hold; both atk_air and plunge_start
|
||||
now arm `_pending_air_slam_land` at active start — the falling pose holds
|
||||
until touchdown, then a shared `air_slam_land` animation (land.png 6f +
|
||||
FX4) plays. FX overlay offsets follow the author's bottom-right anchor
|
||||
rule `offset = (64 - cell_w, -cell_h)` → FX4 (135x166) = (-71, -166).
|
||||
air_attack_l/r data: move_mult_y 0.2 → -1.6, active 0.5 / recovery 0.5.
|
||||
3. **[A][sp] derive beats the A-charge.** With hold_threshold at 0.25 beats
|
||||
(0.125s @120bpm), beat-cadenced [A] then [SP] with A still held had already
|
||||
entered Charging, so SP was shelved and the A release cast blade rain.
|
||||
New rule in ActionController.submit_intent: a pressed SP while an
|
||||
on_release charge hold (A/D) is armed or charging breaks the charge and
|
||||
falls through to normal resolution — the four-slot window still holds [A],
|
||||
so [A][SP] resolves the dash (dash_through pierces the boss and hits while
|
||||
passing). S-charge (on_secondary_key) is untouched.
|
||||
4. **Blade rain composite.** Falling blades now fall for exactly
|
||||
BLADE_RAIN_DROP_FALL_TIME (0.24s @1900px/s) and vanish at ground contact
|
||||
as the landing tile starts (its first frames carry the streak + impact);
|
||||
tiles are bottom-anchored to the ground line via per-sheet cell_height,
|
||||
uniform 0.5 scale, spread grows with charge level (2/3/4 strikes).
|
||||
5. **Charge gauge = cast level.** ChargeComponent's private 1.1s ramp had
|
||||
nothing to do with the beat-quantized cast level in ActionController.
|
||||
ActionController now exposes `charge_state()` (MAX_CHARGE_LEVEL 3,
|
||||
progress_units 0..max-1) as the single source; the gauge renders
|
||||
level-space (ready == top level), pulses the overlay on level-up, and the
|
||||
HUD shows "CHARGE LV n / 3" with per-level fill colors. Legacy 1.1s ramp
|
||||
remains only as a standalone fallback.
|
||||
6. **Dummy boss for testing.** Boss export `stationary` (attacks but never
|
||||
displaces: no BT dash/retreat — replaced with ranged pressure — no action
|
||||
motion, no hit-chain escape). Enabled on the Stage instance only;
|
||||
boss.tscn keeps mobile defaults so behavior-tree contract tests still
|
||||
exercise retreat/escape (the point-blank test explicitly un-sets it).
|
||||
|
||||
## 2026-07-04 time anchor / dual time phase feature pass
|
||||
|
||||
Implemented the full AnchorV1.0 chapter 10-12/17/20 feature set following the
|
||||
incremental plan in `Fighting_Rthythm_game/docs/时间锚点与双相位架构修改方案.md`
|
||||
(all names below use its reserved terms: `time_anchor` / `time_phase` /
|
||||
`attack_buff` / `streak`):
|
||||
|
||||
- **New autoloads** (registered after CombatManager): `TimePhaseManager`
|
||||
(sole writer of `current_time_phase`, broadcasts `time_phase_changed`) and
|
||||
`TimeAnchorSystem` (schedules chart-explicit + periodic anchors, resolves
|
||||
held/broken from `judgement_made` facts only, routes `force_time_phase`).
|
||||
Periodic candidates are computed lazily (origin + current streak tier) and
|
||||
lock when they enter the 2-beat lead window; explicit chart anchors win
|
||||
same-beat collisions and restart the periodic count.
|
||||
- **EventBus** gained `time_phase_changed` / `time_anchor_scheduled` /
|
||||
`time_anchor_resolved` / `streak_changed` / `attack_buff_changed`.
|
||||
`judgement_made(quality, offset_ms, beat_index)` was already extended
|
||||
during migration (7.1-A), so everything here is pure increment.
|
||||
- **EffectContainer** two increments only: stack-aware aggregation for add
|
||||
modifiers (`value x stacks`; all pre-existing resources are max_stacks 1,
|
||||
audited by test_effect_container) and `set_effect_stacks` (plus a small
|
||||
`effect_stacks` reader). Resolvers/CombatManager/RhythmManager untouched.
|
||||
- **Player** gained `StreakCounter` (+1 on skill_executed, zero on miss /
|
||||
chart_reset) and `AttackBuffComponent` (stack storage IS the
|
||||
`effect_time_anchor_attack_buff.tres` Effect instance: +10% damage_mult per
|
||||
stack, cap 20, halved floor on every actual phase switch, zeroed on
|
||||
chart_reset). Damage rides the existing buffs multiplier slot in
|
||||
`resolve_damage` — the design formula 1 + 0.10 x stacks emerges from the
|
||||
stack-aware aggregation.
|
||||
- **Boss** gained `TimePhaseAdapter` with the PastStrong profile
|
||||
(`resources/time_phase/profile_past_strong_enemy.tres` — past: dmg x1.2 /
|
||||
taken x0.8, future: x0.7 / x1.3 via `effect_tp_*` resources; the
|
||||
FutureStrong mirror profile exists for future enemies). Damage-taken
|
||||
multipliers ride DefenseModifier entries; both phases share all collision.
|
||||
- **Chart layer**: `ChartEvent.time_phase_mask` (+`matches_time_phase`),
|
||||
`ChartTrack.time_phase_mask` (authoring default pushed onto `both` events
|
||||
at load), `BeatChart.initial_time_phase`, ChartRunner trigger-time final
|
||||
ruling (skipped events are marked triggered and never re-dispatched) and
|
||||
initial-phase application on ready/reset. stage9_boss_duel gained a
|
||||
time_anchor track (beats 8 / 40).
|
||||
- **Dual music layers**: `AudioLayerController` (scenes/audio/) runs two
|
||||
always-synced players seeded from `RhythmManager.song_position`, crossfades
|
||||
volumes on phase switch (0.35s), drift-corrects the *presentation* players
|
||||
only (loop-wrap aware), and mutes the clock stream. Placeholder assets:
|
||||
both layers use ev_past1.mp3; the future layer goes through a runtime low-pass
|
||||
bus so the switch is audible until a real Future loop lands.
|
||||
- **Presentation placeholders per request**: the second map is ground.png
|
||||
color-mapped (Stage tints the ground sprite + a CanvasModulate, warm past /
|
||||
cool future, 0.35s tween + white flash under the UI layer); the time anchor
|
||||
ball is yellow_ball.png color-mapped crimson in RhythmTrack (mirrored pair
|
||||
converging on the center, grows near the hit point, held → green lock
|
||||
flash "ANCHOR HELD", broken → magenta "TIME SHIFT!").
|
||||
- **HUD**: TimePhaseHud (phase name + next-anchor countdown, buff stacks
|
||||
/20 with percent, streak) and DebugPanel lines for time phase state and
|
||||
armed/last-resolved anchors.
|
||||
- **Tooling/tests**: `tools/time_anchor_chart_tool.gd` (validate / generate /
|
||||
simulate) and seven new SceneTree tests (`test_time_phase_manager`,
|
||||
`test_time_anchor_resolution`, `test_time_anchor_scheduling`,
|
||||
`test_streak_counter`, `test_attack_buff`, `test_time_phase_adapter`,
|
||||
`test_chart_time_phase_mask`). No Godot binary is available on this
|
||||
machine, so the suite is authored but not yet executed locally.
|
||||
|
||||
Open tuning items deferred (doc chapter 12): anchor-specific window, streak
|
||||
clear on hurt, on_break punishment effects, conditional anchors (v1.5).
|
||||
|
||||
## 2026-07-03 body collision audit
|
||||
|
||||
Phase 0 keeps the base physics layer names from the migration manual:
|
||||
`world`, `player_hurtbox`, `enemy_hurtbox`, `player_hitbox`, and `enemy_hitbox`.
|
||||
|
||||
The source project still uses root body collision to let the player and boss block each other:
|
||||
the player body is on layer 2 with mask 5, while the boss body is on layer 4 with mask 3.
|
||||
To preserve that feel without mixing body blocking into hurtbox or hitbox layers, the target
|
||||
project reserves layer 6 as `player_body` and layer 7 as `enemy_body`.
|
||||
|
||||
## 2026-07-03 phase 4 character asset migration
|
||||
|
||||
Phase 4 copies character art only from the curated `tmp/new` source folders:
|
||||
`player_tagged` is migrated to `res://assets/art/characters/player/`, and `boss_tagged`
|
||||
is migrated to `res://assets/art/characters/boss/`. File names are normalized to ASCII
|
||||
snake_case before animation paths are authored.
|
||||
|
||||
The player package README is preserved as `credits_blair_ceradsky.txt`; the package is
|
||||
CC-BY 4.0 and must credit Blair Ceradsky / @MookaTheCaveman. The boss folder still has
|
||||
no license file in the source material, so boss art is a development asset until the
|
||||
license is identified and added.
|
||||
|
||||
The old jump-height test is superseded by a no-free-movement/no-jump-input regression:
|
||||
player movement in this migration comes from ActionData-driven rhythm actions only.
|
||||
|
||||
## 2026-07-03 post-migration bug-fix pass
|
||||
|
||||
A full audit against `AnchorV1.0.md`, the migration plan/manual, and the character/boss
|
||||
design doc fixed the following migration defects (tests updated in the same pass):
|
||||
|
||||
1. Energy scale: player max energy was 10 while skills cost 15-50, so no skill could
|
||||
ever be paid for. Player/EnergyComponent max is now 100 and the energy bar fills
|
||||
proportionally.
|
||||
2. Melee reach: all player melee ActionData had `range = 0`, leaving a 48px centered
|
||||
hitbox that body-blocking made unreachable. Every melee action now carries a range.
|
||||
3. Projectile teams: the shared projectile scene was hard-wired to enemy-hitbox layer /
|
||||
player-hurtbox mask, so the player's blade wave hit the player and never the boss.
|
||||
`projectile_requested` now carries a context Dictionary (team, action, judgement,
|
||||
range); ActorsContainer assigns collision layers per team and injects the ActionData
|
||||
and judgement so damage multipliers resolve. Player gained muzzle spawn methods;
|
||||
the boss muzzle height was lowered to 55 so bullets actually cross the player hurtbox.
|
||||
4. Super armor: HealthComponent entered Hitstun on every damaging hit regardless of
|
||||
`interrupts`; it now respects the defense resolution (death still always applies).
|
||||
5. Boss behavior tree: retreat no longer has top priority at melee range (combo first,
|
||||
2-way shot punish when melee is on cooldown, retreat only after both), the ranged
|
||||
cycle no longer bypasses the 2-way cooldown, and beyond dash range the boss closes
|
||||
in instead of shooting forever. Hit-chain escape now needs 4 hits, has a 4s cooldown
|
||||
and only fires while grounded. Chart events take priority: an upcoming chart event
|
||||
postpones BT decisions and a triggering chart event overrides a BT action.
|
||||
6. Boss presentation: MotionExecutor is cancelled on action end (no more sliding across
|
||||
the arena), animation speed_scale is aligned to the action's beat length, and the
|
||||
boss no longer turns to track the player mid-action.
|
||||
7. Charge levels: level was measured from the initial key press (always level 3);
|
||||
it is now measured from time spent in the Charging phase, quantized by
|
||||
`charge_level_beats` (1 beat per level). Holding A/D during a chain-cancelled combo
|
||||
step now arms the charge gate too.
|
||||
8. Combo HUD: enemy ComboWindows no longer broadcast to the EventBus, so the player's
|
||||
four-slot HUD is not wiped whenever the boss is interrupted.
|
||||
9. Direction semantics: displacement direction now follows the left/right action tags
|
||||
(mirror pairs) and falls back to the current heading for forward actions (W launcher
|
||||
no longer forces the player to face right); plunging strike now actually drives the
|
||||
fake-height fall (negative move_mult_y maps to height_speed while airborne).
|
||||
10. Player presentation: hit-stun and death now play (manual sheet animations from
|
||||
14_hit_stun / 15_death), the plunge has its falling loop, and the charge FX overlay
|
||||
uses the real charging_up_overlay sheet instead of leftover textures.
|
||||
11. Rhythm track UI reads BPM from RhythmManager (was hard-coded 80 vs the actual 120).
|
||||
12. Block: parry reduction is graded by the block judgement (perfect 100% / good 80% /
|
||||
bad 60%) and only applies to attacks from the front, per AnchorV1.0 section 9.4;
|
||||
blocked hits no longer interrupt. block_start active window widened to 0.5 beats
|
||||
(total 0.8 beats = 0.4s at 120 BPM, matching the design sheet).
|
||||
|
||||
## 2026-07-03 playtest follow-up fixes (bullets / collision / latency / air lock)
|
||||
|
||||
Root causes found during the first playtest and their fixes:
|
||||
|
||||
1. **Stuck in the air after W then S.** MotionExecutor converted `move_mult_y` into a
|
||||
screen-space body velocity; when landing flipped the presentation state to LAND the
|
||||
attack-state cleanup never ran, so the plunge left `velocity.y = -220` on the
|
||||
CharacterBody and the body ascended forever (vertical motion belongs to the fake
|
||||
height system, the body must stay on the ground plane). MotionExecutor is now
|
||||
horizontal-only, MovementMotor zeroes `velocity.y` on landing and decays stray
|
||||
horizontal knockback velocity (KNOCKBACK_FRICTION 480) whenever no attack owns it.
|
||||
2. **Bullets looked wrong.** effect_sheet.png is a 6x2 grid of 32px cells (verified by
|
||||
alpha scan); the projectile sliced it as 5x2 (38.4px, non-integer) so every frame was
|
||||
cut through the middle. The projectile now uses 6x2, loops the four flight frames at
|
||||
16 fps, expires by travel range (default 460px, zhan_bo levels 380/460/540) instead
|
||||
of a 0.3s animation timer, and flies at 520px/s instead of 1100 so it is readable.
|
||||
3. **Collision boxes did not match the drawn bodies.** The new art draws both characters
|
||||
with their feet ~40px above the node root (player idle rows 24-88 of 128; boss rows
|
||||
16-47 with a -67 sprite offset). All body/hurtbox/hitbox shapes still sat at the old
|
||||
feet-at-root heights, i.e. ~35px below the visible bodies. Player shapes moved to
|
||||
y=-72, boss shapes to y=-70, projectile lanes to -70 on both sides. Player waves now
|
||||
also clear enemy bullets (mask includes enemy_hitbox; enemy_projectiles are freed on
|
||||
contact) implementing the design's projectile duel.
|
||||
4. **Blade wave fired away from the boss.** The player heading defaults to left and only
|
||||
directional attacks turn it; zhan_bo now aims at the nearest live member of the
|
||||
"bosses" group with heading as fallback.
|
||||
5. **Latency feel.** anchor_grid halved (0.5 -> 0.25 beats) so on-beat presses reach
|
||||
Active with no artificial stretch; the four-slot clear display no longer swallows the
|
||||
next input (it flushes and consumes immediately); agile input flushing enabled in
|
||||
project.godot; player action displacement now follows the S6 rule (move_mult 1.0 =
|
||||
100px over the action) instead of a flat 220px/s lunge.
|
||||
|
||||
test_boss_integration projectile assertions were rewritten for the new contract
|
||||
(6x2 grid, flight loop, range expiry, torso-lane spawn heights, moved hurtboxes).
|
||||
|
||||
## 2026-07-03 player animation / FX audit vs player_tagged source pack
|
||||
|
||||
Audited all 17 tagged action folders against the runtime setup. Root problem: only the
|
||||
three AnimationPlayer clips (atk_ground_1/2, rising_slash) had FX tracks; every action
|
||||
running through the manual sheet-animation path had no FX channel at all, and looping
|
||||
cast animations were being stomped by idle because attack_time_left used the natural
|
||||
clip length (0.1s for the 2-frame blade rain loop).
|
||||
|
||||
- Manual animation system now supports per-segment fps and a parallel FX timeline
|
||||
driving Visual/FxOverlay. All overlay offsets were computed by aligning the author's
|
||||
embedded frame-0 idle reference against the idle sheet (method reproduces the two
|
||||
hand-calibrated offsets exactly): 01/02/03/05 slash (-147,-191), 04 dash (-98,-128),
|
||||
07 rising (-111,-156), 08 prep ring (-64,-305), 11 cast (-115,-172),
|
||||
12/13 FX2/FX3 (-107,-198).
|
||||
- FX wired: atk_ground_3 + combo_finisher slash overlays, dash_slash speed-line overlay
|
||||
(frame 1 is the author's intentional blank), atk_air FX2, plunge FX2 + FX3 falling
|
||||
hold, blade_wave cast overlay, blade_rain launch ring (prep overlay frames 17-19).
|
||||
- Charge visuals split per entry: A/D charge plays the MAGIC CAST prep body animation
|
||||
(hold last frame) with the sword-ring overlay forming (frames 1-16, hold); S charge
|
||||
keeps idle stance with CHARGING UP overlay at the author's 50fps.
|
||||
- Mode C: ContactFxSpawner script added (was a script-less placeholder node) — spawns
|
||||
the per-attack ENEMY CONTACT bursts on the target for melee and the projectile
|
||||
contact burst for blade waves. Mode D: ground_smash chains three SHOCKWAVE tiles
|
||||
along the ground; jian_yu spawns raindrops plus 2-4 RAIN LANDING TILE pillars scaled
|
||||
by charge level. One-shot world FX use scenes/combat/one_shot_fx.gd.
|
||||
- Blade wave projectiles now use the author's PROJECTILE sheet (5 frames, 33fps loop);
|
||||
enemy bullets keep the effect_sheet placeholder.
|
||||
- Smoothness: attack presentation window extended to the action's beat length (idle no
|
||||
longer cuts off casts), same-name animations restart on chain (player and boss), and
|
||||
starting any new action clears stale FX overlay state. Idle now plays all 8 frames
|
||||
(test updated to [0..7]).
|
||||
|
||||
## 2026-07-04 full UI reskin (ui_and_ground asset pack) + harbor stage backdrop
|
||||
|
||||
The placeholder rhythm-track art (rod/blue_ball stitching, center.png emblem,
|
||||
yellow_ball movers) was replaced wholesale by the authored pack in ui_and_ground/,
|
||||
and the stage gained a three-layer harbor backdrop. Map A (past phase) uses the
|
||||
purple/gold set, map B (future phase) the red "d" set; the world itself still
|
||||
renders map B via the existing CanvasModulate color mapping + radial wipe.
|
||||
|
||||
- RhythmTrack re-skins entirely from `TRACK_SKINS[time_phase]`
|
||||
(rhythm_track.gd): background b/bd (single stretched piece — no more rod
|
||||
stitching, the line sits centered in the frame), long axis line/lined, center
|
||||
emblem anchor01/anchor01d, movers star/stard, special (time anchor) beats swap
|
||||
the mover texture to sanchor/sanchord — still zero extra track elements.
|
||||
- Hit feedback per the art spec: a judged normal beat flips the emblem to the
|
||||
own-phase anchor02 variant and fires the own-phase c01 flash; a held special
|
||||
beat flips the emblem to the CROSS-phase anchor02 variant with the own-phase
|
||||
c02 flash (A: anchor02d + c02, B: anchor02 + c02d). The emblem reverts to
|
||||
idle after 0.45s. A latch keeps the follow-up judgement readout from
|
||||
overwriting anchor feedback (held resolutions arrive nested inside the same
|
||||
judgement_made dispatch; deadline breaks pass an empty judgement dict and
|
||||
don't latch).
|
||||
- Beat ticks now pulse the flash at 0.35 peak alpha so full brightness reads as
|
||||
"you hit something"; test_ui_animation_regression asserts visibility > 0.2.
|
||||
- Stage backdrop: long.png (sunset sea, Parallax2D scroll 0.12, scaled 1.4378 to
|
||||
exactly fill the 982px-tall view) and mid.png (lighthouse/ship/crane cluster,
|
||||
scroll 0.4, scaled 0.92, bases tucked 17px below the sea horizon at y≈383)
|
||||
render behind the ground scene; both are plain-canvas Parallax2D so the
|
||||
CanvasModulate phase tint and the radial wipe cover them too.
|
||||
- ground.png (stone dock with chain railing + end pillars) replaces the old
|
||||
strip at uniform scale 1.7979: the walk surface in the art (texture y 570)
|
||||
lands exactly on the gameplay ground plane y=366 and the art spans precisely
|
||||
boundary-to-boundary (-21.5..4115.5, pillars at the walls). A dark
|
||||
StreetUnderfill polygon backfills below the art so the bottom of the frame
|
||||
never shows void, and Camera2D got limit_left/right (-22/4116) so the view
|
||||
can no longer slide past the artwork at the arena edges.
|
||||
|
||||
## 2026-07-04 (later) disaster recovery + WYSIWYG authored view + panel HUD + per-frame collision matrices
|
||||
|
||||
Context: at ~05:11 an incomplete Mac zip (Baidu sync had not finished uploading
|
||||
scenes/assets — the *.baiduyun.uploading.cfg markers) was extracted over the
|
||||
tree and the merge wiped scenes/, scripts/, tools/, most of resources/ and
|
||||
assets/. The repo had zero commits, so nothing was recoverable from git. The
|
||||
tree was rebuilt from four sources: (1) the three session transcripts (every
|
||||
file ever read/written, replayed Write+Edit chains, most files verified
|
||||
byte-exact against the surviving .git/index SHA-1s), (2) the old project
|
||||
(assets, addon, byte-identical UI scenes, the tagged author packs under
|
||||
assets/art/characters/tmp/new/), (3) ui_and_ground/ + playbossui/ art packs,
|
||||
(4) the three newer test files carried by the zip (test_rhythm_ui_layout,
|
||||
test_boss_integration, test_stage4_player_scene), which numerically encode the
|
||||
newer authored-view state and were treated as the binding spec. A survivor
|
||||
backup was kept at ../Rthythm_archor_game_survivor_backup_0542. THIS commit
|
||||
history now exists precisely so this can never happen again.
|
||||
|
||||
WYSIWYG (editor == game), per the newer tests:
|
||||
- Stage exports use_authored_camera_view (default true): the editor-authored
|
||||
Camera2D pose IS the runtime view — position (2229.63, 97.38), zoom 0.82,
|
||||
no player follow, no zoom overwrite. false restores the legacy follow rig.
|
||||
- MainUI moved out of CanvasLayer into the world canvas: Main/UI is a Control
|
||||
positioned at the camera world-rect origin (1527.191, -297.742) at scale
|
||||
1/0.82, sized 1152x648 — the editor shows UI over world exactly as rendered.
|
||||
- Backgrounds are plain Node2D containers (names LongParallax/MidParallax kept
|
||||
for test paths): long.png sunset at (791.6, -335) x1.25, mid.png regions as
|
||||
moored ship (1230, -250) and lighthouse (2650, -303); CanvasModulate is
|
||||
authored in stage.tscn so the phase tint previews in the editor.
|
||||
- Ground sprite crops to region Rect2(0, 90, 2301, 593), offset (-1150.5,
|
||||
-480) — walk line stays texture y570 = world y366. Actor grounding is
|
||||
authored: Visual position (0, 32) with player.gd visual_ground_offset 32.
|
||||
- Player Visual scale ±2, boss Visual scale ±4 (flip preserves magnitude);
|
||||
all scaled sprites use TEXTURE_FILTER_LINEAR.
|
||||
|
||||
Panel HUD (playbossui pack): StatusBars at (20.74, 35.64) wraps playerui.png
|
||||
(x1.5) with HealthBar/EnergyBar/ChargeBar overlaying the baked wells
|
||||
(player_red_ui/player_blue_ui fills); BossStatus right edge 1123.2 wraps
|
||||
boss_ui.png with BossHealthBar (boss_red_ui fill) + DREAD HARBINGER name;
|
||||
ComboWindow centered at y 278.64; TimePhaseHud and DebugPanel ship hidden.
|
||||
|
||||
Per-frame collision/damage matrices (frame_collision_driver.gd, on player and
|
||||
boss): every physics tick the driver re-derives all three matrices from the
|
||||
frame actually displayed —
|
||||
- body: base layer/mask re-asserted, composed with MotionExecutor ghost bits;
|
||||
- damage-receive: DamageReceiver rect follows the opaque pixel bounds of the
|
||||
current frame (per-sheet bounds cached from texture alpha), margins via
|
||||
hurt_margin, mirrored automatically through the Visual transform;
|
||||
- damage-send: DamageEmitter only monitors during ACTIVE-phase frames whose
|
||||
native-forward extent reaches HIT_REACH_GATE (0.72) of the sheet's max —
|
||||
the hit window is the weapon-extended frames, not the whole active phase;
|
||||
the shape is rebuilt per frame from pose reach vs action range.
|
||||
DamageEmitter gained per-swing dedup (_already_hit_ids) since per-frame
|
||||
windows can re-trigger area_entered within one swing. New headless test:
|
||||
tests/test_frame_collision_driver.gd (synthetic 4-frame sheet: pose-following
|
||||
hurtbox, reach-gated hitbox, mirror flip, matrix re-assertion, swing dedup).
|
||||
|
||||
Verification pass (9 static-analysis agents over all 39 tests + cross-refs)
|
||||
confirmed the rebuild and surfaced fixes that were applied:
|
||||
- grounding: player CharacterSprite/FxOverlay moved to node position (0, 40)
|
||||
(visible feet at world 398, camera-frame ratio 0.88; FX stays glued since
|
||||
both sprites shift together and all test-pinned offsets are untouched);
|
||||
boss.gd gained the set_sprite_height_position override so the authored
|
||||
Visual (0, 32) survives physics ticks — boss visible feet land at 398 too.
|
||||
- driver: forward reach is now facing-derived (boss art is native RIGHT-
|
||||
facing, player native LEFT — the mirror sign of basis_x times heading picks
|
||||
the correct native side); a late-ACTIVE fallback window guarantees a plain
|
||||
range hit if no frame of a swing passes the reach gate (art timing can no
|
||||
longer whiff a beat-anchored swing); frame bounds use per-frame
|
||||
get_region().get_used_rect() (C++-side, no first-swing hitch).
|
||||
- test isolation: chart_runner and TimeAnchorSystem resolve bus/manager/clock
|
||||
via reverse root-child scan, and only the real TimeAnchorSystem autoload
|
||||
self-drives from the global clock (test instances are inert).
|
||||
- player.gd no longer contains get_parent() (architecture test contract).
|
||||
Known pre-existing flake (left as-is, documented): test_player_combo_input
|
||||
judges through the RhythmManager wall clock headless, so ~20% of beat phase
|
||||
lands in the miss window and the run can abort; other suites pin judgements.
|
||||
The `libraries/ =` AnimationPlayer serialization was flagged and verified
|
||||
VALID (per-library subpath form, matches the editor-saved old project), and
|
||||
hash-verified load_steps miscounts in old .tres files were intentionally kept
|
||||
(historical bytes, self-healing on editor save).
|
||||
|
||||
## 2026-07-04 final Level 1 and menu UI migration baseline
|
||||
|
||||
The playable baseline was restored to the `rthythm_archor_game_player`
|
||||
reference for camera, HUD canvas, actor/background scale, and authored stage
|
||||
proportions. Level migration is scoped to Level 1 flow, spawn logic, gate state,
|
||||
and combat sequencing; it must not resize the player, minions, Boss,
|
||||
background, HUD, or camera.
|
||||
|
||||
- `GameFlowManager` now follows the `Rthythm_archor_game` menu implementation
|
||||
byte-for-byte and uses the authored menu textures under `assets/ui/menu`.
|
||||
Difficulty options apply immediately on click, the difficulty page exposes
|
||||
the reference start/back commands, and no current-value label is drawn over
|
||||
the command area.
|
||||
- Stage runtime returns to the player reference view: `UILayer/UI` remains a
|
||||
CanvasLayer-hosted HUD, the camera starts at `(2047, 395)` with zoom
|
||||
`(1.25, 1.25)`, and camera follow is retained.
|
||||
- Root ground anchors for player, the initial minion, and Boss stay at
|
||||
`y = 560`; the visible sprite feet line is verified at `y = 520` for all
|
||||
three actors. Boss uses `visual_ground_offset = -40` and the first active
|
||||
minion uses `visual_ground_offset = -32` so the runtime walk/dash frame lines
|
||||
up with the same visible baseline without changing actor scale.
|
||||
|
||||
## 2026-07-05 charge release facing, blade rain ground line, projectile hit circles
|
||||
|
||||
Three combat-feel fixes reported from play: the S-charge release auto-aimed at
|
||||
the nearest enemy (waves went right whenever a target stood to the right), the
|
||||
blade rain landing FX rendered 40px below where the player visibly stands, and
|
||||
enemy bullets carried a hit circle far larger than the drawn bolt.
|
||||
|
||||
- Player `projectile_direction` now returns the current facing only (left
|
||||
heading releases left); the nearest-enemy auto-aim helper was removed along
|
||||
with the projectile-turn branch in `_play_action_animation` (a release no
|
||||
longer flips the player toward a target behind them). Regression:
|
||||
`tests/test_zhan_bo_release_facing.gd`.
|
||||
- World-FX ground anchoring: actor origins sit on `y = 560` but the visible
|
||||
feet line is `y = 520` (40px transparent margin under the authored player
|
||||
frames; minions/boss match via `visual_ground_offset`). Blade rain raindrops
|
||||
and landing tiles now anchor to `Player.VISIBLE_GROUND_LINE_OFFSET = -40` so
|
||||
the lowest visible pixel of every landing tile shares the player's visible
|
||||
ground line instead of sinking into the pier. `tests/test_blade_rain_alignment.gd`
|
||||
asserts against the constant.
|
||||
- Projectile collision must stay inside the visible art: `VISUAL_PROFILES`
|
||||
gained `collision_radius` (bullet 9.0 — the effect_sheet bolt is ~32x18px at
|
||||
scale 2; wave keeps 32.0, inside its ~66px smallest frame) and
|
||||
`_apply_visual_profile` duplicates the scene's shared `CircleShape2D` before
|
||||
resizing so bullet/wave instances never overwrite each other. Layer audit
|
||||
found emitter/receiver/projectile team masks already correct (player
|
||||
projectile also keeps enemy_hitbox in its mask on purpose — wave clears
|
||||
enemy bullets). Melee hitboxes untouched: jian_yu keeps its 140px range,
|
||||
which stays narrower than the FX spread at every level.
|
||||
- Known stale test: `test_stage4_player_scene.gd` expects the old 2x-scaled
|
||||
player Visual with a `(0, 32)` editor feet preview; it fails against the
|
||||
current 1x `player.tscn` regardless of these changes (verified by reverting).
|
||||
Reference in New Issue
Block a user