拾起物品同步
This commit is contained in:
+51
-15
@@ -39,8 +39,8 @@ const JUMP_BUFFER_FRAMES: int = 6
|
||||
@export_group("视角")
|
||||
## 眼睛高度(米)。相机就架在这个高度上 —— 按碰撞胶囊定,跟模型高矮无关。
|
||||
@export var eye_height: float = 1.6
|
||||
## 第一人称下藏掉自己的模型。不藏的话相机要么在模型里、要么贴着头顶,画面糊一片。
|
||||
## 想做成「看得见自己身体」的第一人称,就把这个关掉、并把 eye_height 降到模型头部高度。
|
||||
## 第一人称下藏掉自己的身体。**两条胳膊会留下来** —— 抱东西时得看得见自己的手。
|
||||
## 想连胳膊也看不见就把这个关掉(那样相机要么在模型里、要么贴着头顶,画面会糊一片)。
|
||||
## 只影响本机这一份 —— 远端玩家的模型照常显示。
|
||||
@export var hide_own_body: bool = true
|
||||
## 鼠标灵敏度(弧度/像素)
|
||||
@@ -73,6 +73,8 @@ const JUMP_BUFFER_FRAMES: int = 6
|
||||
@export var throw_charge_time: float = 0.8
|
||||
## 扔出去时额外叠上玩家自身的速度(跑着扔会飞更远)
|
||||
@export var throw_inherits_velocity: bool = true
|
||||
## 等服务器确认抱起的宽限时间(秒)。联机下被别人先抢走时,超时就自动松手
|
||||
@export var pickup_confirm_time: float = 0.6
|
||||
|
||||
@onready var body: Node3D = $Body
|
||||
## 眼睛分两层转:CameraRig 绕竖直轴转(yaw),Camera 原地抬头低头(pitch)。
|
||||
@@ -83,9 +85,9 @@ const JUMP_BUFFER_FRAMES: int = 6
|
||||
@onready var _health_label: Label3D = $HealthLabel
|
||||
## 滑索操作提示,同样在 player.tscn 里配好,默认隐藏
|
||||
@onready var _hint: Label3D = $InteractHint
|
||||
## 抱持点:抱起来的物品每物理帧摆到它上面
|
||||
@onready var _carry_socket: Node3D = $CameraRig/CarrySocket
|
||||
## 抱东西时的胳膊表现层(挂 carry_arms.gd):只收「抱没抱、走多快」
|
||||
## 抱东西时的胳膊表现层(挂 carry_arms.gd):只收「抱没抱、走多快」。
|
||||
## 抱持点(CameraRig/CarrySocket)不在这里引用 —— 物品自己按名字找持有者的抱持点,
|
||||
## 这样每端算出来的位置都一样,联机不用同步物品位置。
|
||||
@onready var _carry_arms: CarryArms = $Body/CarryArms
|
||||
|
||||
## 动画状态机(挂在 Body/AnimationPlayer 上)。只把「运动结果」交给它,也只知道它会自己播动画。
|
||||
@@ -110,12 +112,14 @@ var _zip_speed: float = 0.0
|
||||
## 挂上瞬间「人相对缆」的偏移,随后衰减到 0 —— 吸附是滑过去的,不是瞬移
|
||||
var _zip_grab_offset: Vector3 = Vector3.ZERO
|
||||
|
||||
## 手上抱着的物品。非 null 时每物理帧把它摆到抱持点上。
|
||||
## 只在权威端写;远端玩家的物品位置由物品自己的 Sync 复制过来。
|
||||
## 手上抱着的物品。位置由物品自己跟住抱持点(见 Carryable),玩家不插手 ——
|
||||
## 这样每端算出来的位置都一样,联机不用同步物品位置。
|
||||
var _carried: Carryable = null
|
||||
## 长按 Q 的蓄力进度 0~1
|
||||
var _throw_charge: float = 0.0
|
||||
var _throw_charging: bool = false
|
||||
## 等服务器确认抱起的剩余时间。服务器没给(被别人先抢了)就自己松手
|
||||
var _pickup_wait: float = 0.0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -134,7 +138,7 @@ func _ready() -> void:
|
||||
return
|
||||
camera_rig.position.y = eye_height
|
||||
if hide_own_body:
|
||||
body.visible = false
|
||||
_hide_body_keep_arms()
|
||||
_yaw = camera_rig.rotation.y
|
||||
_pitch = clampf(camera.rotation.x, deg_to_rad(pitch_min_deg), deg_to_rad(pitch_max_deg))
|
||||
_apply_look()
|
||||
@@ -143,6 +147,25 @@ func _ready() -> void:
|
||||
_refresh_health_label()
|
||||
|
||||
|
||||
## 第一人称:藏掉身体,但**把两条胳膊留下** —— 抱东西时得看得见自己的手。
|
||||
## 模型各部位是独立 mesh,按名字挑出来即可;名字对不上(换模型了)就退化成整个藏掉。
|
||||
func _hide_body_keep_arms() -> void:
|
||||
var stack: Array[Node] = [body]
|
||||
var kept := 0
|
||||
while not stack.is_empty():
|
||||
var node: Node = stack.pop_back()
|
||||
for child in node.get_children():
|
||||
stack.append(child)
|
||||
var mesh := child as MeshInstance3D
|
||||
if mesh == null:
|
||||
continue
|
||||
var is_arm := str(mesh.name).begins_with("arm_")
|
||||
mesh.visible = is_arm
|
||||
kept += 1 if is_arm else 0
|
||||
if kept == 0:
|
||||
body.visible = false
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
|
||||
_yaw -= event.relative.x * mouse_sensitivity
|
||||
@@ -218,11 +241,15 @@ func _physics_process(delta: float) -> void:
|
||||
else:
|
||||
_hint.visible = false
|
||||
|
||||
# 抱着东西:每帧把它摆到抱持点上,并推进 Q 的蓄力。
|
||||
# 物品的位置由持有者写 —— 远端玩家的那份由物品自己的 Sync 复制过去。
|
||||
# 抱着东西:推进 Q 的蓄力。物品位置不归玩家管 —— 它自己跟住抱持点(见 Carryable),
|
||||
# 每端都这么算,所以联机不用同步物品位置。
|
||||
if _carried != null:
|
||||
_carried.apply_hold_transform(_carry_socket)
|
||||
if _throw_charging:
|
||||
if _carried.carrier_peer != multiplayer.get_unique_id():
|
||||
# 服务器还没确认,或者被别人先抢走了:给一小段时间,超时就松手
|
||||
_pickup_wait -= delta
|
||||
if _pickup_wait <= 0.0:
|
||||
_carried = null
|
||||
elif _throw_charging:
|
||||
_throw_charge = minf(1.0, _throw_charge + delta / maxf(throw_charge_time, 0.01))
|
||||
# 胳膊表现层只收「抱没抱、走多快」,摆成什么样是它自己的事
|
||||
_carry_arms.set_carrying(
|
||||
@@ -310,15 +337,20 @@ func _find_carryable() -> Carryable:
|
||||
|
||||
|
||||
## 抱起最近的可抱物品。手上已经有东西、或者正挂在缆上都不抱。
|
||||
## 实际「谁抱到了」由服务器仲裁(先到先得),这里只是发起请求并乐观地先认领,
|
||||
## 服务器不给就在 _physics_process 里超时松手。
|
||||
func _pick_up() -> void:
|
||||
if _carried != null or _zipline != null:
|
||||
return
|
||||
var item := _find_carryable()
|
||||
if item == null:
|
||||
return
|
||||
item.begin_carry(self)
|
||||
item.apply_hold_transform(_carry_socket)
|
||||
_carried = item
|
||||
_pickup_wait = pickup_confirm_time
|
||||
if multiplayer.is_server():
|
||||
item.request_pickup(multiplayer.get_unique_id())
|
||||
else:
|
||||
item.request_pickup.rpc_id(1, multiplayer.get_unique_id())
|
||||
|
||||
|
||||
## 松手扔出:方向就是视线方向,速度按蓄力插值(轻点也能扔出去,只是近)。
|
||||
@@ -334,7 +366,11 @@ func _release_throw() -> void:
|
||||
if throw_inherits_velocity:
|
||||
launch += velocity
|
||||
_throw_charge = 0.0
|
||||
item.end_carry(launch)
|
||||
# 出手速度交给服务器:它收回模拟权,让物品带着这个速度接着飞
|
||||
if multiplayer.is_server():
|
||||
item.request_release(launch)
|
||||
else:
|
||||
item.request_release.rpc_id(1, launch)
|
||||
|
||||
|
||||
# ---------------- 滑索 ----------------
|
||||
|
||||
Reference in New Issue
Block a user