diff --git a/characters/player/player.gd b/characters/player/player.gd index 4ec2273..e199233 100644 --- a/characters/player/player.gd +++ b/characters/player/player.gd @@ -1,6 +1,8 @@ extends RigidBody3D class_name Player +enum PlayerState { PLAYER_ALIVE, PLAYER_DEAD } + # constants const max_energy : float = 100.0 const energy_charge_rate : float = 10 # energy per second @@ -21,10 +23,11 @@ var gravity : Vector3 = g * ProjectSettings.get_setting("physics/3d/default_gra player_id = id $PlayerInput.set_multiplayer_authority(id) -@onready var input = $PlayerInput +@export var player_state = PlayerState.PLAYER_ALIVE + +@onready var input : PlayerInput = $PlayerInput @onready var camera = $SpringArm3D/Camera3D -# floor detection @onready var hud = $HUD @onready var shape_cast = $ShapeCast3D @onready var weapon = $SpringArm3D/Inventory/SpaceGun @@ -34,20 +37,36 @@ var gravity : Vector3 = g * ProjectSettings.get_setting("physics/3d/default_gra signal died(player) signal energy_changed(energy) +var _jumping = false + func _ready(): energy_changed.connect(hud._on_energy_changed) + $HealthComponent.health_changed.connect(hud._on_health_changed) + $HealthComponent.health_zeroed.connect(_die) if player_id == multiplayer.get_unique_id(): camera.current = true else: $HUD.hide() + input.fired_primary.connect(_fire_primary) + input.jumped.connect(_jump) -func is_on_floor() -> bool: +func _fire_primary(): + if player_state == PlayerState.PLAYER_DEAD: + return + $"SpringArm3D/Inventory/SpaceGun".fire_primary() + +func _jump(): + if player_state == PlayerState.PLAYER_DEAD: + return + _jumping = true + +func _is_on_floor() -> bool: return shape_cast.is_colliding() -func is_skiing() -> bool: +func _is_skiing() -> bool: return input.skiing -func handle_jetpack(delta, direction): +func _handle_jetpack(delta, direction): if input.jetting: if energy > 0: var up_vector = Vector3.UP * jetpack_vertical_force * jetpack_force_factor @@ -61,9 +80,14 @@ func handle_jetpack(delta, direction): energy_changed.emit(energy) func _process(delta): + if player_state == PlayerState.PLAYER_DEAD: + return %SpringArm3D.global_transform.basis = Basis.from_euler(Vector3(input.camera_rotation.y, input.camera_rotation.x, 0.0)) func _physics_process(delta): + if player_state == PlayerState.PLAYER_DEAD: + return + # retrieve user's direction vector var _input_dir = input.direction # compute direction in local space @@ -71,16 +95,16 @@ func _physics_process(delta): # adjust direction based on spring arm rotation _direction = _direction.rotated(Vector3.UP, $SpringArm3D.rotation.y) - handle_jetpack(delta, _direction) + _handle_jetpack(delta, _direction) # handle ski - if is_skiing(): + if _is_skiing(): physics_material_override.friction = 0 else: physics_material_override.friction = 1 - if is_on_floor(): - if not _direction.is_zero_approx() and not is_skiing(): + if _is_on_floor(): + if not _direction.is_zero_approx() and not _is_skiing(): # retrieve collision normal var normal = shape_cast.get_collision_normal(0) # calculate the angle between the ground normal and the up vector @@ -92,15 +116,13 @@ func _physics_process(delta): linear_velocity = lerp(linear_velocity, _direction * ground_speed, .1) - if input.jumping: + if _jumping: linear_velocity.y = sqrt(2 * abs((mass * gravity * delta).y) * 1) - else: - pass - input.jumping = false + _jumping = false -func die(): - $PlayerInput.disable() +func _die(): + player_state = PlayerState.PLAYER_DEAD var tween = create_tween() tween.tween_property(input, "camera_rotation:y", -PI/2, 0.25) tween.tween_property($SpringArm3D, "position:y", -0.75, 0.25) @@ -113,4 +135,4 @@ func respawn(location): linear_velocity = Vector3() $HealthComponent.heal_full() position = location - $PlayerInput.enable() + player_state = PlayerState.PLAYER_ALIVE diff --git a/characters/player/player.tscn b/characters/player/player.tscn index 8a70b27..f34de7c 100644 --- a/characters/player/player.tscn +++ b/characters/player/player.tscn @@ -1,17 +1,21 @@ -[gd_scene load_steps=11 format=3 uid="uid://cbhx1xme0sb7k"] +[gd_scene load_steps=12 format=3 uid="uid://cbhx1xme0sb7k"] [ext_resource type="Script" path="res://characters/player/player.gd" id="1_ymjub"] [ext_resource type="PackedScene" uid="uid://bcv81ku26xo" path="res://interfaces/hud/hud.tscn" id="2_5qvi2"] [ext_resource type="PackedScene" uid="uid://c8co0qa2omjmh" path="res://weapons/space_gun/space_gun.tscn" id="2_ka38u"] [ext_resource type="Shape3D" uid="uid://dkwljsgaflf31" path="res://characters/player/collision_shape.res" id="2_y6kgj"] [ext_resource type="PackedScene" uid="uid://bof3mg7wgxrmn" path="res://components/health_component.tscn" id="5_dlsxj"] +[ext_resource type="Script" path="res://characters/player/player_input.gd" id="6_xwlxv"] [sub_resource type="PhysicsMaterial" id="PhysicsMaterial_clur0"] resource_local_to_scene = true bounce = 1.0 absorbent = true +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_1hdqa"] + [sub_resource type="CapsuleMesh" id="CapsuleMesh_vmqfq"] +material = SubResource("StandardMaterial3D_1hdqa") radius = 0.3 [sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_rqdp6"] @@ -24,6 +28,15 @@ properties/1/replication_mode = 1 properties/2/path = NodePath(".:player_id") properties/2/spawn = true properties/2/replication_mode = 2 +properties/3/path = NodePath("HealthComponent:health") +properties/3/spawn = true +properties/3/replication_mode = 2 +properties/4/path = NodePath(".:player_state") +properties/4/spawn = true +properties/4/replication_mode = 2 +properties/5/path = NodePath("SpringArm3D:position") +properties/5/spawn = true +properties/5/replication_mode = 2 [sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_5j4ew"] properties/0/path = NodePath(".:direction") @@ -39,70 +52,6 @@ properties/3/path = NodePath(".:skiing") properties/3/spawn = false properties/3/replication_mode = 2 -[sub_resource type="GDScript" id="GDScript_uy24w"] -script/source = "extends MultiplayerSynchronizer -class_name PlayerInput - -@export var jumping = false -@export var jetting = false -@export var skiing = false -@export var direction = Vector2.ZERO -@export var camera_rotation : Vector2 -@export var MOUSE_SENSITIVITY : float = 0.5 - -var _mouse_position: Vector2 - -func _ready(): - enable() - Input.mouse_mode = Input.MOUSE_MODE_CAPTURED - -func _unhandled_input(event: InputEvent) -> void: - var mouse_mode = Input.get_mouse_mode() - - # isolate mouse events - if event is InputEventMouseMotion: - if mouse_mode == Input.MOUSE_MODE_CAPTURED: - # retrieve mouse position relative to last frame - _mouse_position = event.relative * MOUSE_SENSITIVITY - -func _process(delta): - direction = Input.get_vector(\"left\", \"right\", \"forward\", \"backward\") - if Input.is_action_just_pressed(\"jump_and_jet\"): - jump.rpc() - if Input.is_action_just_pressed(\"fire_primary\"): - fire_primary.rpc() - jetting = Input.is_action_pressed(\"jump_and_jet\") - skiing = Input.is_action_pressed(\"ski\") - _update_camera(delta) - -@rpc(\"call_local\") -func jump(): - jumping = true - -@rpc(\"call_local\") -func fire_primary(): - $\"../SpringArm3D/Inventory/SpaceGun\".fire_primary() - -func _update_camera(delta): - # clamp vertical rotation (head motion) - camera_rotation.y -= _mouse_position.y * delta - camera_rotation.y = clamp(camera_rotation.y, deg_to_rad(-90.0),deg_to_rad(90.0)) - # wrap horizontal rotation (to prevent accumulation) - camera_rotation.x -= _mouse_position.x * delta - camera_rotation.x = wrapf(camera_rotation.x, deg_to_rad(0.0),deg_to_rad(360.0)) - # reset mouse motion until next input event - _mouse_position = Vector2.ZERO - -func disable(): - set_process(false) - set_process_unhandled_input(false) - -func enable(): - var has_authority = get_multiplayer_authority() == multiplayer.get_unique_id() - set_process(has_authority) - set_process_unhandled_input(has_authority) -" - [node name="Player" type="RigidBody3D"] axis_lock_angular_x = true axis_lock_angular_y = true @@ -148,7 +97,4 @@ replication_config = SubResource("SceneReplicationConfig_rqdp6") [node name="PlayerInput" type="MultiplayerSynchronizer" parent="."] root_path = NodePath(".") replication_config = SubResource("SceneReplicationConfig_5j4ew") -script = SubResource("GDScript_uy24w") - -[connection signal="health_changed" from="HealthComponent" to="HUD" method="_on_health_changed"] -[connection signal="health_zeroed" from="HealthComponent" to="." method="die"] +script = ExtResource("6_xwlxv") diff --git a/characters/player/player_input.gd b/characters/player/player_input.gd new file mode 100644 index 0000000..b45b883 --- /dev/null +++ b/characters/player/player_input.gd @@ -0,0 +1,56 @@ +extends MultiplayerSynchronizer +class_name PlayerInput + +@export var jetting = false +@export var skiing = false +@export var direction = Vector2.ZERO +@export var camera_rotation : Vector2 +@export var MOUSE_SENSITIVITY : float = 0.5 + +signal jumped +signal fired_primary + +var _mouse_position: Vector2 + +func _ready(): + var has_authority = is_multiplayer_authority() + set_process(has_authority) + set_process_unhandled_input(has_authority) + Input.mouse_mode = Input.MOUSE_MODE_CAPTURED + +func _unhandled_input(event: InputEvent) -> void: + var mouse_mode = Input.get_mouse_mode() + + # isolate mouse events + if event is InputEventMouseMotion: + if mouse_mode == Input.MOUSE_MODE_CAPTURED: + # retrieve mouse position relative to last frame + _mouse_position = event.relative * MOUSE_SENSITIVITY + +func _process(delta): + direction = Input.get_vector("left", "right", "forward", "backward") + if Input.is_action_just_pressed("jump_and_jet"): + _jump.rpc() + if Input.is_action_just_pressed("fire_primary"): + _fire_primary.rpc() + jetting = Input.is_action_pressed("jump_and_jet") + skiing = Input.is_action_pressed("ski") + _update_camera(delta) + +@rpc("call_local") +func _jump(): + jumped.emit() + +@rpc("call_local") +func _fire_primary(): + fired_primary.emit() + +func _update_camera(delta): + # clamp vertical rotation (head motion) + camera_rotation.y -= _mouse_position.y * delta + camera_rotation.y = clamp(camera_rotation.y, deg_to_rad(-90.0),deg_to_rad(90.0)) + # wrap horizontal rotation (to prevent accumulation) + camera_rotation.x -= _mouse_position.x * delta + camera_rotation.x = wrapf(camera_rotation.x, deg_to_rad(0.0),deg_to_rad(360.0)) + # reset mouse motion until next input event + _mouse_position = Vector2.ZERO diff --git a/components/health_component.gd b/components/health_component.gd index 915e20c..f29b2d8 100644 --- a/components/health_component.gd +++ b/components/health_component.gd @@ -2,13 +2,13 @@ extends Area3D class_name HealthComponent @export var max_health : int = 100 -@export var health : int: +@export var health : int = 100: set(value): health = value health_changed.emit(value) signal health_zeroed -signal health_changed +signal health_changed(value : int) func _ready(): health = max_health diff --git a/interfaces/hud/hud.tscn b/interfaces/hud/hud.tscn index df716b8..4e15af1 100644 --- a/interfaces/hud/hud.tscn +++ b/interfaces/hud/hud.tscn @@ -4,17 +4,21 @@ script/source = "extends CanvasLayer class_name HUD -@onready var health_bar = $HealthBar -@onready var energy_bar = $EnergyBar +@onready var _health_bar = $HealthBar +@onready var _energy_bar = $EnergyBar -func _update_energy_label(energy): - energy_bar.value = energy +func _ready(): + _update_health_label(100) + _update_energy_label(100) + +func _update_energy_label(energy) -> void: + _energy_bar.value = energy func _on_energy_changed(new_energy) -> void: _update_energy_label(new_energy) -func _update_health_label(health): - health_bar.value = health +func _update_health_label(health) -> void: + _health_bar.value = health func _on_health_changed(new_health) -> void: _update_health_label(new_health)