拾起物品同步

This commit is contained in:
2026-10-03 18:48:04 +08:00
parent 0dcfb88bfe
commit 3d23804fa5
10 changed files with 359 additions and 86 deletions
+50
View File
@@ -123,6 +123,56 @@
**未做**:联机同步(第 2 步)。现在物品位置只有持有者本地在写,远端玩家看不到箱子被抱走 —— 需要给物品加
`MultiplayerSynchronizer` + 跟随持有者的 authority 切换 + 抢占仲裁。
## 补上:第一人称看得见胳膊 + 抱起物品联机同步
用户要求「玩家需要看到自己胳膊,联机也需要同步」,并给了 `CLAUDE.md`:
**「游戏内测试交给用户来,不要自己做」** —— 已记进 MEMORY.md,之后不再自己跑 `project_run` 截图验证。
**第一人称留胳膊**:`player.gd` 的 `_hide_body_keep_arms()` 用栈遍历 Body 下所有 MeshInstance3D,
按 `arm_` 前缀筛出胳膊留着、其余藏掉;一个都没筛到(换模型改名)就退化成整个 `body.visible = false`。
**联机同步**(关键设计:只同步一个整数):
- 新增 `world/items/carryable_sync.tres`(同步 `.:position` / `.:rotation` / `.:carrier_peer`),
`carryable_box.tscn` 里加 `Sync`(MultiplayerSynchronizer)节点。
- `Carryable.carrier_peer` 带 setter:非 0 就 `freeze = true` + `collision_layer = 0`;
为 0 时 `freeze = not multiplayer.is_server()`(只有服务器模拟,其余端跟着同步走)。
- **抱着时位置不走同步**:`_physics_process` 里 `_find_carrier_socket()`(玩家节点名 = peer id,组 `net_player`)
把物品摆到持有者抱持点上。每端都这么算 → 天然一致,也就没有「写位置 / 同步写回来」打架的问题。
- **权威永远在服务器**:`request_pickup(peer_id)` / `request_release(velocity)` 两个 RPC,
客户端 `rpc_id(1, ...)`、单机(is_server)直接调;服务器只改 `carrier_peer`,放下时顺手写 `linear_velocity`。
- 玩家侧:`_pick_up()` 乐观认领 + `pickup_confirm_time`(0.6s)超时松手;`_release_throw()` 把初速度发给服务器。
**顺手发现(重要,未改,等用户确认)**:`player.tscn` 的根节点 `Player` 现在带
`transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0)` —— 整只玩家被缩到 20%
(胶囊 0.36m、相机 0.32m、模型 0.23m),而且这个缩放会漏给「挂在编辑中场景根下」的节点:
`tests/test_zipline.gd` 就是这么挂滑索的,于是 `test_tangent_points_from_a_to_b` 红了
(实测 tangent(0)·along = 0.888 < 0.9;zipline.gd 的 `sample()` 用全局锚点 lerp 却加**未缩放的 sag**,
缩放一进来形状就偏了)。这行是我读 scene 之后才出现的,来源是提交 `6f3c89a 抱起物品`(用户提交的工作区)。
`test_run` **40/41**(唯一红的就是上面那条滑索测试)。
## 用户确认:玩家缩放 0.2 是有意的 → 滑索改成缩放无关
用户明确「就是想将玩家缩小到 0.2 倍」,所以那行不改。但滑索那条测试还得救,而且它暴露的是**真 bug**:
- `zipline.gd` 的 `sample()` 用 `anchor_a.global_position.lerp(anchor_b.global_position, t)` 再减
`UP * sag * 4t(1-t)` —— 前半截跟着父节点缩放、后半截不跟,父节点一有缩放曲线形状就偏。
`tangent()` / `ride_point()` 同样的混用。
- 改成**先在本地空间算曲线**(`_curve_local()`,原来的 `_local_sample` 从「把世界点转回本地」变成直接算本地),
`sample()`/`ride_point()` 用 `to_global()` 转世界,`tangent()` 用 `global_transform.basis * d` 转方向。
缆绳网格本来就在本地空间生成,现在少了一次多余的 `to_local`。
- 测试夹具原来挂在**编辑中场景根**下,于是玩家根的 0.2 缩放漏进滑索。改成挂在
`Engine.get_main_loop().root` 下的中性父节点(`_make_holder()`),夹具不再受编辑中场景影响。
- 新增 `test_shape_survives_parent_scale`:故意套一个 0.2 缩放的父节点,验 tangent 不歪、
中点下垂 = sag × 0.2。这条把刚踩的坑钉住了。
`test_run` **42/42**。
**留给用户决定的尺度问题**(我只报告,没改):玩家缩到 0.2 之后,世界单位的参数都还是老尺度 ——
`walk_speed 5 / sprint 8.5 / jump 5`(= 14 身高/秒)、`pickup_radius 3.0`(8 身高)、
滑索 `attach_radius 4.0` / `hang_offset 1.15`(人会吊在缆下方 3 个身高)、物品 `throw_speed 5~14`、
示例箱子 0.6m(比 0.36m 的玩家还高)。要不要按 0.2 一起缩,等用户拍板。
## 给「抱起物品系统」出了方案(未动代码)
用户要新功能:玩家抱起物品,先要方案。我在对话里给了设计,没有写文件。