- item_tooltip_view.gd: 新增 avoid_rect 属性,tooltip 与装备窗口重叠时自动推到左侧 - inventory_ui.gd: 悬停装备时传入窗口矩形作为避让区域 - 包含其他累积的功能开发和测试文件
11 KiB
11 KiB
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。
- 检查 syncing、moving skill、lock;设置 Src/Dst/rotation/
CInstanceBase::CheckAdvancing- Actor collision 使用真实 collision sphere;逐个
TestActorCollision并AdjustDynamicCollisionMovement,第二个碰撞或调整后仍相交时BlockMovement。 - 对移动段和下一位置检查
ATTRIBUTE_BLOCK。
- Actor collision 使用真实 collision sphere;逐个
Current call chain
PlayerController._on_clickground_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地面点击特效。
- 生成 40250
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,再二分地表;40250GetPickingPointWithRay先对象 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 的真实调用链复核:
- 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 停止”不能视为已实现。 - 参考
__OnClickSmart在没有拾取对象/地面时明确NEW_Stop();当前_on_click已在_ray_ground未命中时调用stop(),清除旧的_is_going、预约目标和按键状态,避免 click miss 后继续移动。player_move_test.gd已增加回归。 - 40250
NEW_CanMoveToDestPixelPosition/CheckAdvancing使用当前 Actor motion 的真实 collision sphere、对象碰撞AvoidObject/AdjustCollisionMovement,第二次碰撞或调整后仍相交时BlockMovement;当前只用固定ACTOR_BODY_RADIUS_M、静态 kind 判断、一次切线再 x/z 分轴推进,没有第二碰撞停止状态,也没有从 MSM 读取每个骨骼碰撞球。 - 当前
_ray_ground以每 1m、最多 800m 的高度采样后二分;参考GetPickingPointWithRay由 terrain/object picking 和相机 ray 边界决定,桥、台阶和对象 height 的优先级不是同一算法。现有测试只用假 world 高度和静态 obstacle,未覆盖真实 bridge/object/attribute 边界。 - 四组回归均通过:
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,再决定是否下沉共享碰撞几何,而不是继续调固定半径。