From 1bd447a56eb0b715f686b7951d8e17c1e4777e22 Mon Sep 17 00:00:00 2001 From: yvmou_ Date: Thu, 8 Oct 2026 16:40:43 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E5=8F=AF=E6=8A=B1=E8=B5=B7?= =?UTF-8?q?=E7=89=A9=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- world/items/carryable.gd | 118 -------------------------------- world/items/carryable.gd.uid | 1 - world/items/carryable_box.tscn | 28 -------- world/items/carryable_sync.tres | 12 ---- 4 files changed, 159 deletions(-) delete mode 100644 world/items/carryable.gd delete mode 100644 world/items/carryable.gd.uid delete mode 100644 world/items/carryable_box.tscn delete mode 100644 world/items/carryable_sync.tres diff --git a/world/items/carryable.gd b/world/items/carryable.gd deleted file mode 100644 index 64c45f8..0000000 --- a/world/items/carryable.gd +++ /dev/null @@ -1,118 +0,0 @@ -@tool -class_name Carryable -extends RigidBody3D -## 可抱起的物品。**只有带这个脚本(并进了 carryable 组)的东西才抱得起来** —— 这就是 -## 「仅特定物品可抱」的实现方式:门槛不在玩家那边,而在物品自己身上。 -## -## 和 Zipline 一样,手感参数放物品这一侧:不同物品可以有不同的抱持偏移、不同的投掷速度, -## 玩家只负责「找到它、把它摆到手上、扔出去」,不定义手感。 -## -## 用法:把这个脚本挂在物品根节点(RigidBody3D)上,再给它加一个 MultiplayerSynchronizer -## (配置见 res://world/items/carryable_sync.tres,同步 position / rotation / carrier_peer)。 -## 参考示例见 res://world/items/carryable_box.tscn。 -## -## 联机只同步一个整数:`carrier_peer`(谁抱着)。 -## **抱着的时候位置根本不走同步** —— 每一端都从「持有者的抱持点」把物品摆出来, -## 结果天然一致,也省掉了「持有者写位置、同步又把位置写回来」的互相打架。 -## 空着的时候才靠 position / rotation 同步,而且只有服务器在模拟。 -## -## 标了 @tool 是为了能在编辑器里跑测试(非 @tool 脚本在编辑器里是 placeholder,方法调不动); -## 运行时行为完全一样。 - -## 所有可抱物品都进这个组,玩家靠它找物品 -const GROUP: StringName = &"carryable" -## 玩家节点在世界里以 peer id 命名并进了这个组,靠它找持有者的抱持点 -const PLAYER_GROUP: StringName = &"net_player" -## 抱持点在玩家场景里的相对路径 -const SOCKET_PATH: String = "CameraRig/CarrySocket" - -@export_group("抱持") -## 被抱时相对抱持点的偏移(米)。物品大小不同,靠它对准手心 -@export var hold_offset: Vector3 = Vector3.ZERO -## 被抱时的朝向(度) -@export var hold_rotation_deg: Vector3 = Vector3.ZERO - -@export_group("投掷") -## 长按蓄满力后的出手速度(米/秒) -@export var throw_speed_max: float = 14.0 -## 轻点时最低出手速度(米/秒) -@export var throw_speed_min: float = 5.0 - -## 谁抱着它(peer id),0 = 没人抱。 -## 由服务器改,通过物品自己的 MultiplayerSynchronizer 复制到各端;各端只读。 -var carrier_peer: int = 0: - set(value): - if carrier_peer == value: - return - carrier_peer = value - _update_simulation() - -var _saved_collision_layer: int = 1 - - -func _ready() -> void: - add_to_group(GROUP) - _saved_collision_layer = collision_layer - _update_simulation() - - -func can_be_carried() -> bool: - return carrier_peer == 0 - - -## 抱着的时候跟着持有者的抱持点走;空着的时候什么都不做(交给物理 / 同步) -func _physics_process(_delta: float) -> void: - if carrier_peer == 0: - return - var socket := _find_carrier_socket() - if socket != null: - apply_hold_transform(socket) - - -## 把自己摆到抱持点上。偏移和朝向由物品自己决定,玩家不用管。 -func apply_hold_transform(socket: Node3D) -> void: - var socket_basis := socket.global_basis - global_position = socket.global_position + socket_basis * hold_offset - global_basis = socket_basis * Basis.from_euler(hold_rotation_deg * PI / 180.0) - - -## 按蓄力比例算出手速度(0 = 轻点,1 = 蓄满) -func throw_speed(charge: float) -> float: - return lerpf(throw_speed_min, throw_speed_max, clampf(charge, 0.0, 1.0)) - - -## 请求抱起。客户端用 rpc_id(1, ...) 发给服务器仲裁(先到先得),单机时服务器直接执行。 -## 服务器只改 `carrier_peer` 这一个值,其余交给同步 —— 各端看到的状态因此必然一致。 -@rpc("any_peer", "call_remote", "reliable") -func request_pickup(peer_id: int) -> void: - if not multiplayer.is_server() or carrier_peer != 0: - return - carrier_peer = peer_id - - -## 放下 / 扔出。持有者算好初速度发给服务器:服务器收回模拟权,让物品带着这个速度接着飞。 -@rpc("any_peer", "call_remote", "reliable") -func request_release(velocity: Vector3) -> void: - if not multiplayer.is_server() or carrier_peer == 0: - return - carrier_peer = 0 - linear_velocity = velocity - - -## 抱着时冻结物理、清掉碰撞层(不清会把抱着它的人顶飞); -## 空着时只有服务器模拟,其余端冻住跟着同步过来的位置走,免得各端各算一套。 -func _update_simulation() -> void: - if carrier_peer != 0: - freeze = true - collision_layer = 0 - return - collision_layer = _saved_collision_layer - freeze = not multiplayer.is_server() - - -## 找持有者的抱持点。找不到就什么都不做 —— 远端玩家还没生成时会出现这种情况。 -func _find_carrier_socket() -> Node3D: - for node in get_tree().get_nodes_in_group(PLAYER_GROUP): - if str(node.name) == str(carrier_peer): - return node.get_node_or_null(SOCKET_PATH) as Node3D - return null diff --git a/world/items/carryable.gd.uid b/world/items/carryable.gd.uid deleted file mode 100644 index fb6143f..0000000 --- a/world/items/carryable.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bdo6ee5tmvnc2 diff --git a/world/items/carryable_box.tscn b/world/items/carryable_box.tscn deleted file mode 100644 index aa5ff1f..0000000 --- a/world/items/carryable_box.tscn +++ /dev/null @@ -1,28 +0,0 @@ -[gd_scene load_steps=6 format=3] - -[ext_resource type="Script" path="res://world/items/carryable.gd" id="1_carryable"] -[ext_resource type="SceneReplicationConfig" path="res://world/items/carryable_sync.tres" id="2_sync"] - -[sub_resource type="BoxMesh" id="BoxMesh_body"] -size = Vector3(0.6, 0.6, 0.6) - -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_box"] -albedo_color = Color(0.92, 0.6, 0.25, 1) -roughness = 0.7 - -[sub_resource type="BoxShape3D" id="BoxShape3D_body"] -size = Vector3(0.6, 0.6, 0.6) - -[node name="CarryableBox" type="RigidBody3D"] -mass = 2.0 -script = ExtResource("1_carryable") - -[node name="Mesh" type="MeshInstance3D" parent="."] -mesh = SubResource("BoxMesh_body") -surface_material_override/0 = SubResource("StandardMaterial3D_box") - -[node name="Collision" type="CollisionShape3D" parent="."] -shape = SubResource("BoxShape3D_body") - -[node name="Sync" type="MultiplayerSynchronizer" parent="."] -replication_config = ExtResource("2_sync") diff --git a/world/items/carryable_sync.tres b/world/items/carryable_sync.tres deleted file mode 100644 index d4b26a0..0000000 --- a/world/items/carryable_sync.tres +++ /dev/null @@ -1,12 +0,0 @@ -[gd_resource type="SceneReplicationConfig" format=3] - -[resource] -properties/0/path = NodePath(".:position") -properties/0/spawn = true -properties/0/replication_mode = 1 -properties/1/path = NodePath(".:rotation") -properties/1/spawn = true -properties/1/replication_mode = 1 -properties/2/path = NodePath(".:carrier_peer") -properties/2/spawn = true -properties/2/replication_mode = 1