diff --git a/player/player.gd b/player/player.gd index 66f9316..879fe8a 100644 --- a/player/player.gd +++ b/player/player.gd @@ -15,6 +15,13 @@ extends CharacterBody3D ## 跳跃输入缓冲帧数(输入事件在渲染帧到达,物理帧读取,避免漏跳) const JUMP_BUFFER_FRAMES: int = 6 +@export_group("属性") +## 血量 +@export var health: int = 100: + set(value): + health = clampi(value, 0, 100) + _refresh_health_label() + @export_group("移动") ## 常规移动速度(米/秒) @export var walk_speed: float = 5.0 @@ -47,9 +54,16 @@ var _pitch: float = 0.0 var _jump_buffer: int = 0 ## 本节点是否由本机玩家操控。由世界节点在生成时设置 authority 决定,见 world/main.gd。 var _is_local: bool = true +# 血条 +var _health_label: Label = null func _ready() -> void: + print("[观察] 我是 %d,这个节点归我管吗?%s,我的名字是 %s" + % [multiplayer.get_unique_id(), is_multiplayer_authority(), name]) + # 生成血条 + _make_health_label() + _is_local = is_multiplayer_authority() if not _is_local: # 远端玩家只是一具「回放身体」: @@ -82,6 +96,10 @@ func _unhandled_input(event: InputEvent) -> void: set_mouse_captured(Input.mouse_mode != Input.MOUSE_MODE_CAPTURED) elif event is InputEventMouseButton and event.pressed and Input.mouse_mode != Input.MOUSE_MODE_CAPTURED: set_mouse_captured(true) + elif event is InputEventKey and event.pressed and not event.echo and event.keycode == KEY_H: + # 只有权威端能改被同步的属性,别人改的会被覆盖回去 + if is_multiplayer_authority(): + health -= 10 func set_mouse_captured(captured: bool) -> void: @@ -129,3 +147,18 @@ func _physics_process(delta: float) -> void: velocity.z = horizontal.y move_and_slide() + +func _make_health_label() -> void: + var layer := CanvasLayer.new() + _health_label = Label.new() + _health_label.position = Vector2(16, 56) + layer.add_child(_health_label) + add_child(layer) + _refresh_health_label() + + +func _refresh_health_label() -> void: + # 远端玩家没有血条,_health_label 是 null,这里直接跳过 + if _health_label == null: + return + _health_label.text = "HP %d / 100" % health diff --git a/player/player.tscn b/player/player.tscn index 9c2c0a1..4eac4dc 100644 --- a/player/player.tscn +++ b/player/player.tscn @@ -1,7 +1,7 @@ [gd_scene format=3 uid="uid://bekuuw153mv03"] [ext_resource type="Script" uid="uid://f5ptp3is4agf" path="res://player/player.gd" id="1_oul6g"] -[ext_resource type="SceneReplicationConfig" path="res://player/player_sync.tres" id="2_rkbax"] +[ext_resource type="SceneReplicationConfig" uid="uid://c4ubbxjfrrs47" path="res://player/player_sync.tres" id="2_rkbax"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_rkbax"] radius = 0.4 @@ -18,6 +18,16 @@ roughness = 0.6 [node name="Player" type="CharacterBody3D" unique_id=869687860] script = ExtResource("1_oul6g") +health = null +walk_speed = null +sprint_speed = null +acceleration = null +air_acceleration = null +jump_velocity = null +turn_speed = null +mouse_sensitivity = null +pitch_min_deg = null +pitch_max_deg = null [node name="Collision" type="CollisionShape3D" parent="." unique_id=215132582] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.9, 0) diff --git a/player/player_sync.tres b/player/player_sync.tres index c217763..ca29b8d 100644 --- a/player/player_sync.tres +++ b/player/player_sync.tres @@ -1,4 +1,4 @@ -[gd_resource type="SceneReplicationConfig" format=3] +[gd_resource type="SceneReplicationConfig" format=3 uid="uid://c4ubbxjfrrs47"] [resource] properties/0/path = NodePath(".:position") @@ -7,3 +7,6 @@ properties/0/replication_mode = 1 properties/1/path = NodePath("Body:rotation") properties/1/spawn = true properties/1/replication_mode = 1 +properties/2/path = NodePath(".:health") +properties/2/spawn = true +properties/2/replication_mode = 1