- item_tooltip_view.gd: 新增 avoid_rect 属性,tooltip 与装备窗口重叠时自动推到左侧 - inventory_ui.gd: 悬停装备时传入窗口矩形作为避让区域 - 包含其他累积的功能开发和测试文件
110 lines
11 KiB
Markdown
110 lines
11 KiB
Markdown
# movement.click_collision
|
||
|
||
## Scope
|
||
|
||
审计鼠标点地、点实体、掉落物优先级、预约移动、地形 ATTRIBUTE_BLOCK、Actor 碰撞、滑动/停止和输入门控。
|
||
|
||
## Reference call chain
|
||
|
||
- `CPythonPlayer::NEW_SetMouseState`
|
||
- 按绑定分派 MOVE、SMART、CAMERA、AUTO、ATTACK、SKILL。
|
||
- `__OnPressSmart` / `__OnClickSmart`
|
||
- 优先级为 item -> actor -> ground -> screen;按住和点击分别进入移动/攻击/交互分支。
|
||
- `__OnPressGround` / `__OnClickGround`
|
||
- 清预约和自动攻击,取消钓鱼,检查 `MOVABLE_GROUND_DISTANCE`,调用 `NEW_MoveToDestPixelPositionDirection`;被 gate 拒绝时使用 `__ReserveClickGround` 延迟重试。
|
||
- `CInstanceBase::NEW_Goto` / `NEW_Stop`
|
||
- 检查 syncing、moving skill、lock;设置 Src/Dst/rotation/`m_isGoing`,到达或停止时结束 walking。
|
||
- `CInstanceBase::CheckAdvancing`
|
||
- Actor collision 使用真实 collision sphere;逐个 `TestActorCollision` 并 `AdjustDynamicCollisionMovement`,第二个碰撞或调整后仍相交时 `BlockMovement`。
|
||
- 对移动段和下一位置检查 `ATTRIBUTE_BLOCK`。
|
||
|
||
## Current call chain
|
||
|
||
- `PlayerController._on_click`
|
||
- `ground_items.pick_at` 优先,其次对 pickables 做射线/AABB 点选,最后做地面射线求交。
|
||
- `PlayerController._goto` / `_process`
|
||
- 检查 active/frozen/locked/moving_skill 和近距离门;被 gate 拒绝时保存目标并在 0.1 秒后重试。
|
||
- 点地使用 Src/Dst;WASD/移动端输入取消点地目标。
|
||
- `PlayerController._get_blocking_actor` / `_actor_blocked`
|
||
- 使用固定 `ACTOR_BODY_RADIUS_M`、距离门和趋近条件;静态 Actor 阻挡,其他 Actor 尝试切线滑移。
|
||
- `PlayerController._blocked`
|
||
- 通过 `Metin2World.is_blocked` 查询地形/静态阻挡;阻挡时尝试 x/z 分轴推进。
|
||
- `GameScene._on_ground_clicked`
|
||
- 生成 40250 `EFFECT_PICK` / `click.mse` 地面点击特效。
|
||
|
||
## Field-level findings
|
||
|
||
- 40250 的 `NEW_SetMouseState` 区分 `MBS_PRESS` 和 `MBS_CLICK`:Smart 按住会持续执行 `__OnPressSmart`,可持续预约地面/Actor/物品;松开才执行 `__OnClickSmart`。当前 `PlayerController._unhandled_input` 只处理左键按下,未实现同一条鼠标 Smart press/hold 状态机,因此按住鼠标连续移动、按住点 Actor/物品和 screen-direction 分支不能证明与参考一致。
|
||
- 40250 的 Smart 优先级是 item -> actor -> ground -> screen,并且 actor/item 在按住与点击时走不同的预约/攻击/拾取逻辑。当前单击优先级已映射,但 actor 分支直接 `target_selected`,item 通过 signal 进入 NetPlay;没有统一记录 press/click/auto 三种组合的发送包序列。
|
||
- 40250 `NEW_CanMoveToDestPixelPosition` 只拒绝当前坐标相同;当前 `_goto` 以固定 1m 门提前成功返回,门值来自近似常量,不是从 `CPythonPlayer::SetMovableGroundDistance` 的运行时状态读取。
|
||
- 40250 Actor 碰撞使用当前运动模式选择 body/defending sphere,并在每个真实碰撞球对之间做距离门、趋近判定;当前 `_get_blocking_actor` 固定 0.55m 半径,且 `_actor_blocked` 只把部分 meta kind 当作静态阻挡,远端骨骼/坐骑/多个 collision sphere 的分支未复刻。
|
||
- 40250 的物体碰撞在 `__TestObjectCollision` 命中后走 `AvoidObject`/`AdjustCollisionMovement`,若仍阻挡则 `BlockMovement` 清除运动;当前对 terrain/Actor 采用一次 frame 的 direct、切线和 x/z 分轴推进,可能留下 `_is_going` 或继续发移动状态,需单独验证被阻挡终止时序。
|
||
- 当前 `_ray_ground` 以每 1m 射线采样、最多 80m,再二分地表;40250 `GetPickingPointWithRay` 先对象 picking,再 terrain/object height,且射线范围由相机 ray 配置,采样边界和桥/台阶优先级不同。
|
||
|
||
## Branch matrix
|
||
|
||
| 场景 | 40250 | 当前端 | 结论 |
|
||
|---|---|---|---|
|
||
| 点选优先级 | item -> actor -> ground;点击和按住路径不同 | item -> actor -> ground;左键 click 已接入 | MAPPED,按住/自动模式仍需完整 fixture |
|
||
| 近距离点地 | 小于 `MOVABLE_GROUND_DISTANCE` 直接不动 | 固定 1m `MOVABLE_GROUND_DISTANCE_M` | PARTIAL:默认值/运行时设置未完全证明 |
|
||
| lock/sync/moving skill | 拒绝平移;moving skill 可转向;失败点地预约 0.1s | 三门和预约重试已实现 | MAPPED + tests |
|
||
| 地形阻挡 | 对 movement segment 分段检查 ATTRIBUTE_BLOCK,下一位置命中则 BlockMovement | `is_blocked` + direct/分轴推进 | PARTIAL:采样步长和 BlockMovement 时序不同 |
|
||
| Actor 碰撞 | 使用每个 MSM 的真实 collision sphere;动态调整;第二次碰撞直接停 | 固定 body 半径近似,按 static/动态尝试滑移 | GAP:碰撞几何和多碰撞分支不 1:1 |
|
||
| 点地特效 | 成功 `NEW_Goto` 后显示 `EFFECT_PICK` | `ground_clicked` 连接 `click.mse` | MAPPED |
|
||
| 空白点击停止 | 无 item/actor/ground 时 `__OnClickSmart -> NEW_Stop` | `_ray_ground` 未命中时 `_on_click -> stop()` | MAPPED + regression |
|
||
| 输入中断 | 失焦/停止/攻击/技能清除预约或按键状态 | `_notification`、`stop`、NetPlay 入口已接入 | PARTIAL:窗口/网络中断组合待测 |
|
||
|
||
## Equivalence matrix
|
||
|
||
| 项目 | 状态 | 证据 |
|
||
|---|---|---|
|
||
| Preconditions | MAPPED | active、player、camera、world 和三道移动 gate 已定位 |
|
||
| Branch structure | PARTIAL | Smart/Auto/Camera/Attack/Skill 绑定和两种鼠标状态尚未全部覆盖 |
|
||
| Algorithms/formulas | PARTIAL | 转向/距离/到达算法已映射;collision sphere 与 segment sampling 是近似 |
|
||
| State transition order | PARTIAL | 预约、输入、碰撞、动画和网络状态的交错顺序需真实包/场景 fixture |
|
||
| Constants/units | PARTIAL | 1m 近距离门、固定 0.55m body 半径、8m distance gate 未完全由资源证明 |
|
||
| Timing/event sources | PARTIAL | 参考端 frame collision/update 与当前 Godot `_process` 同步点不同 |
|
||
| Resource/data sources | PARTIAL | 参考端 `.msm` sphere/bone collision,当前移动层没有直接消费全部骨骼碰撞数据 |
|
||
| Protocol side effects | MAPPED | ground/actor/item/skill 入口已接入 NetPlay;完整发送包序列仍需 fixture |
|
||
| Interruption/failure/cleanup | PARTIAL | 点地被阻挡、实体删除、失焦、死亡、换图中断和连续点击待测 |
|
||
|
||
## Regression evidence
|
||
|
||
- `project/player_move_test.gd`:Src/Dst、三道 gate、预约、Actor 阻挡/死亡/skip collision、坐骑转向、空白点击停止旧目标。
|
||
- `project/movement_parity_test.gd`:转向阻尼、到达精度和切线碰撞入口。
|
||
- `project/netplay_test.gd`:CLICK_ACTOR、CLICK_ITEM、CLICK_POSITION、USE_SKILL 预约分支。
|
||
- `project/test_click_target_effect_parity.gd`:点地、目标光圈和飞行物静态障碍测试。
|
||
- 本轮四项回归均退出码通过;其中 click/target/fly 测试仍报告 3 个 ObjectDB 泄漏和 1 个资源退出时仍在使用,说明效果节点的清理虽满足断言,但退出生命周期尚不干净。
|
||
|
||
## Deep audit round 2026-09-20
|
||
|
||
本轮按 40250 鼠标输入、移动门、碰撞和地面 picking 的真实调用链复核:
|
||
|
||
1. 40250 `NEW_SetMouseState` 读取鼠标绑定后,对 Smart 分支在 `MBS_PRESS` 和 `MBS_CLICK` 分别调用 `__OnPressSmart`/`__OnClickSmart`;按住期间每帧可持续执行 item/actor/ground/screen 分支,并维护 `m_isSmtMov`。当前 `PlayerController::_unhandled_input` 只处理 `InputEventMouseButton.pressed`,没有左键 release、hold tick 或 `MBS_PRESS` 状态,因此“按住点地持续走”“按住实体持续攻击/交互”“Smart release 停止”不能视为已实现。
|
||
2. 参考 `__OnClickSmart` 在没有拾取对象/地面时明确 `NEW_Stop()`;当前 `_on_click` 已在 `_ray_ground` 未命中时调用 `stop()`,清除旧的 `_is_going`、预约目标和按键状态,避免 click miss 后继续移动。`player_move_test.gd` 已增加回归。
|
||
3. 40250 `NEW_CanMoveToDestPixelPosition`/`CheckAdvancing` 使用当前 Actor motion 的真实 collision sphere、对象碰撞 `AvoidObject`/`AdjustCollisionMovement`,第二次碰撞或调整后仍相交时 `BlockMovement`;当前只用固定 `ACTOR_BODY_RADIUS_M`、静态 kind 判断、一次切线再 x/z 分轴推进,没有第二碰撞停止状态,也没有从 MSM 读取每个骨骼碰撞球。
|
||
4. 当前 `_ray_ground` 以每 1m、最多 800m 的高度采样后二分;参考 `GetPickingPointWithRay` 由 terrain/object picking 和相机 ray 边界决定,桥、台阶和对象 height 的优先级不是同一算法。现有测试只用假 world 高度和静态 obstacle,未覆盖真实 bridge/object/attribute 边界。
|
||
5. 四组回归均通过:`player_move_test.gd`、`movement_parity_test.gd`、`netplay_test.gd`、`test_click_target_effect_parity.gd`;最后一项退出时仍有 3 个 ObjectDB 泄漏和 1 个资源使用警告,说明效果断言通过不等价于退出/中断生命周期已清理。
|
||
|
||
### Active EterLib picking-core review
|
||
|
||
- `EterLib/GrpCollisionObject.cpp` 支持 bound box、cube、indexed mesh、mesh triangle、sphere 和 cylinder 的 ray intersection;`Ray.h` 固定 start/direction/range/end 的单位与边界,`lineintersect_utils.cpp` 还提供线段/平行线最近点和调整算法。
|
||
- 当前端点击/弹道分别使用 Godot ray/AABB/胶囊和简化地面采样;虽然 `test_click_target_effect_parity` 断言通过,但没有复用参考端同一 mesh-triangle/球柱体/线段最近点优先级,不能标记 picking 一致。
|
||
- 本轮完成 GrpCollisionObject/Ray/line intersection 静态核对,点击碰撞合同继续为 `PARTIAL`。
|
||
|
||
## Status
|
||
|
||
`PARTIAL`。当前实现的输入/预约主链已建立,但碰撞几何、逐 Actor 调整和多碰撞停止条件与 40250 仍有结构差异;本轮不做无证据的算法替换。
|
||
|
||
## Audit round 2026-09-21T04:35Z — collision geometry boundary
|
||
|
||
本轮重新沿 `CActorInstance::CheckAdvancing`、`TestActorCollision`、
|
||
`AvoidObject`/`BlockMovement`、`CMapOutdoor::GetPickingPointWithRay` 对照
|
||
`PlayerController::_process`、`_get_blocking_actor`、`_blocked` 和 `_ray_ground`:
|
||
|
||
- 40250 的阻挡判定来自 `.msm` 每个 Actor 的真实 collision sphere,并且在移动段/下一位置分别检查,动态调整后再次相交会进入 `BlockMovement`;当前端仍是固定 0.55m body 半径、单次切线和 x/z 分轴近似。
|
||
- 40250 的点地射线由 terrain/object picking 和相机 ray range 决定;当前端仍是最多 800m、每 1m 高度采样后二分,桥/台阶/object height 的优先级没有 1:1 数据来源。
|
||
- 现有 `player_move_test.gd`、`movement_parity_test.gd`、`netplay_test.gd`、`test_click_target_effect_parity.gd` 全部通过;最后一项仍有 3 个 ObjectDB 泄漏和 1 个资源退出警告,因此只证明当前 fixture 的行为,不证明真实碰撞资源和退出清理等价。
|
||
|
||
结论:本轮没有实施替换;合同继续 `PARTIAL`。下一轮应优先建立真实 `.msm` sphere/object picking fixture,再决定是否下沉共享碰撞几何,而不是继续调固定半径。
|