diff --git a/project.godot b/project.godot index 7e059d5..83e4aea 100644 --- a/project.godot +++ b/project.godot @@ -23,6 +23,7 @@ run/size/viewport_width=1280 [autoload] MultiplayerManager="*res://scripts/multiplayer/multiplayer_manager.gd" +Main="*res://scripts/main.gd" [display] @@ -66,6 +67,11 @@ mouse_release={ "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } +walk={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194325,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} [rendering] diff --git a/scenes/house.tscn b/scenes/house.tscn index 3a108d4..f37ab7d 100644 --- a/scenes/house.tscn +++ b/scenes/house.tscn @@ -87,7 +87,6 @@ mesh = SubResource("BoxMesh_thq07") [node name="Ceiling" type="StaticBody3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 10, 0) -visible = false [node name="CollisionShape3D" type="CollisionShape3D" parent="Ceiling"] shape = SubResource("BoxShape3D_xn166") @@ -151,7 +150,7 @@ omni_attenuation = 1.5 [node name="SecondFloorLight" type="OmniLight3D" parent="Lights"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 9, 0) -visible = false -light_energy = 0.3 +light_energy = 6.0 shadow_enabled = true omni_range = 40.0 +omni_attenuation = 1.5 diff --git a/scenes/in_game.tscn b/scenes/in_game.tscn index 07735e3..803928d 100644 --- a/scenes/in_game.tscn +++ b/scenes/in_game.tscn @@ -24,24 +24,25 @@ environment = SubResource("Environment_2c67a") [node name="MultiplayerSpawner" type="MultiplayerSpawner" parent="."] _spawnable_scenes = PackedStringArray("res://scenes/runner.tscn") -spawn_path = NodePath("../RunnersNode") +spawn_path = NodePath("../Runners") -[node name="GroundStaticBody3D" type="StaticBody3D" parent="."] +[node name="Ground" type="StaticBody3D" parent="."] -[node name="GroundCollisionShape3D" type="CollisionShape3D" parent="GroundStaticBody3D"] +[node name="GroundCollider" type="CollisionShape3D" parent="Ground"] shape = SubResource("WorldBoundaryShape3D_1l61b") -[node name="GroundMeshInstance3D" type="MeshInstance3D" parent="GroundStaticBody3D"] +[node name="GroundMesh" type="MeshInstance3D" parent="Ground"] mesh = ExtResource("1_7j0qh") surface_material_override/0 = ExtResource("2_f8uto") [node name="House" parent="." instance=ExtResource("4_38bom")] -[node name="RunnersNode" type="Node3D" parent="."] +[node name="Runners" type="Node3D" parent="."] +unique_name_in_owner = true -[node name="CanvasLayer" type="CanvasLayer" parent="."] +[node name="StatsOverlay" type="CanvasLayer" parent="."] -[node name="Control" type="Control" parent="CanvasLayer"] +[node name="StatsContainer" type="Control" parent="StatsOverlay"] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -49,7 +50,7 @@ anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -[node name="RichTextLabel" type="RichTextLabel" parent="CanvasLayer/Control"] +[node name="StatsLabel" type="RichTextLabel" parent="StatsOverlay/StatsContainer"] unique_name_in_owner = true layout_mode = 0 offset_right = 200.0 diff --git a/scenes/main_menu.tscn b/scenes/main_menu.tscn index 4c34037..eaa983f 100644 --- a/scenes/main_menu.tscn +++ b/scenes/main_menu.tscn @@ -11,7 +11,7 @@ grow_horizontal = 2 grow_vertical = 2 script = ExtResource("1_ivhyr") -[node name="MainMenuPanel" type="Panel" parent="."] +[node name="Panel" type="Panel" parent="."] layout_mode = 1 anchors_preset = 15 anchor_right = 1.0 @@ -19,7 +19,7 @@ anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -[node name="ColorRect" type="ColorRect" parent="MainMenuPanel"] +[node name="Background" type="ColorRect" parent="Panel"] layout_mode = 1 anchors_preset = 15 anchor_right = 1.0 @@ -28,7 +28,7 @@ grow_horizontal = 2 grow_vertical = 2 color = Color(0.156863, 0.156863, 0.305882, 1) -[node name="MainMenuCenterContainer" type="CenterContainer" parent="MainMenuPanel"] +[node name="Center" type="CenterContainer" parent="Panel"] layout_mode = 1 anchors_preset = 15 anchor_right = 1.0 @@ -36,10 +36,10 @@ anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -[node name="MainMenuVBoxContainer" type="VBoxContainer" parent="MainMenuPanel/MainMenuCenterContainer"] +[node name="VerticalMenu" type="VBoxContainer" parent="Panel/Center"] layout_mode = 2 -[node name="IpAddressRichTextLabel" type="RichTextLabel" parent="MainMenuPanel/MainMenuCenterContainer/MainMenuVBoxContainer"] +[node name="IpLabel" type="RichTextLabel" parent="Panel/Center/VerticalMenu"] custom_minimum_size = Vector2(0, 25) layout_mode = 2 size_flags_vertical = 4 @@ -47,21 +47,21 @@ bbcode_enabled = true text = "[center]Server Address[/center]" scroll_active = false -[node name="IpAddressTextEdit" type="TextEdit" parent="MainMenuPanel/MainMenuCenterContainer/MainMenuVBoxContainer"] +[node name="IpTextBox" type="TextEdit" parent="Panel/Center/VerticalMenu"] unique_name_in_owner = true custom_minimum_size = Vector2(0, 40) layout_mode = 2 size_flags_vertical = 4 placeholder_text = "localhost (default)" -[node name="JoinButtonSpacer" type="Control" parent="MainMenuPanel/MainMenuCenterContainer/MainMenuVBoxContainer"] +[node name="JoinButtonSpacer" type="Control" parent="Panel/Center/VerticalMenu"] custom_minimum_size = Vector2(0, 15) layout_mode = 2 -[node name="JoinButton" type="Button" parent="MainMenuPanel/MainMenuCenterContainer/MainMenuVBoxContainer"] +[node name="JoinButton" type="Button" parent="Panel/Center/VerticalMenu"] custom_minimum_size = Vector2(200, 40) layout_mode = 2 text = "Join" text_overrun_behavior = 3 -[connection signal="pressed" from="MainMenuPanel/MainMenuCenterContainer/MainMenuVBoxContainer/JoinButton" to="." method="_on_join_button_pressed"] +[connection signal="pressed" from="Panel/Center/VerticalMenu/JoinButton" to="." method="_on_join_button_pressed"] diff --git a/scenes/runDA10.tmp b/scenes/runDA10.tmp new file mode 100644 index 0000000..eb3e9a6 --- /dev/null +++ b/scenes/runDA10.tmp @@ -0,0 +1,113 @@ +[gd_scene load_steps=16 format=3 uid="uid://8esyynmieyog"] + +[ext_resource type="Script" path="res://scripts/runner.gd" id="1_d63rt"] +[ext_resource type="Script" path="res://scripts/runner_input.gd" id="2_xmliy"] +[ext_resource type="Material" uid="uid://ccrb46njti2ke" path="res://materials/runner.tres" id="3_6c0ro"] +[ext_resource type="Script" path="res://scripts/state_machine.gd" id="4_40cmc"] +[ext_resource type="Script" path="res://scripts/states/idle.gd" id="5_hq6tn"] +[ext_resource type="Script" path="res://scripts/states/move.gd" id="6_1teax"] +[ext_resource type="Script" path="res://scripts/states/fall.gd" id="7_jfat4"] + +[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_ukf45"] +properties/0/path = NodePath(".:player_id") +properties/0/spawn = true +properties/0/replication_mode = 2 +properties/1/path = NodePath(".:server_position") +properties/1/spawn = true +properties/1/replication_mode = 2 +properties/2/path = NodePath(".:server_rotation") +properties/2/spawn = true +properties/2/replication_mode = 2 + +[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_1agtp"] +properties/0/path = NodePath("RunnerInput:move_direction") +properties/0/spawn = true +properties/0/replication_mode = 2 + +[sub_resource type="SphereShape3D" id="SphereShape3D_wsx1k"] + +[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_j6tb3"] +radius = 0.3 +height = 1.8 + +[sub_resource type="CapsuleMesh" id="CapsuleMesh_di3a0"] +radius = 0.3 +height = 1.8 + +[sub_resource type="PrismMesh" id="PrismMesh_fcj1v"] + +[sub_resource type="SphereMesh" id="SphereMesh_tudvv"] + +[sub_resource type="SphereMesh" id="SphereMesh_1gltg"] + +[node name="Runner" type="CharacterBody3D" node_paths=PackedStringArray("state_machine")] +script = ExtResource("1_d63rt") +state_machine = NodePath("StateMachine") + +[node name="RunnerSync" type="MultiplayerSynchronizer" parent="."] +replication_config = SubResource("SceneReplicationConfig_ukf45") + +[node name="RunnerInput" type="MultiplayerSynchronizer" parent="."] +unique_name_in_owner = true +replication_config = SubResource("SceneReplicationConfig_1agtp") +script = ExtResource("2_xmliy") + +[node name="Camera" type="Camera3D" parent="."] +unique_name_in_owner = true + +[node name="CameraPivot" type="Node3D" parent="."] +unique_name_in_owner = true +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0) + +[node name="CameraSpringArm" type="SpringArm3D" parent="CameraPivot"] +shape = SubResource("SphereShape3D_wsx1k") +spring_length = 3.5 + +[node name="CameraTarget" type="Node3D" parent="CameraPivot/CameraSpringArm"] +unique_name_in_owner = true +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0) + +[node name="Collider" type="CollisionShape3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) +shape = SubResource("CapsuleShape3D_j6tb3") + +[node name="Skin" type="Node3D" parent="."] +unique_name_in_owner = true + +[node name="MainBody" type="MeshInstance3D" parent="Skin"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) +mesh = SubResource("CapsuleMesh_di3a0") +skeleton = NodePath("../..") +surface_material_override/0 = ExtResource("3_6c0ro") + +[node name="Beak" type="MeshInstance3D" parent="Skin/MainBody"] +transform = Transform3D(0.35, 0, 0, 0, -1.09278e-08, 0.1, 0, -0.25, -4.37114e-09, 0, 0.65, -0.3) +visible = false +mesh = SubResource("PrismMesh_fcj1v") +surface_material_override/0 = ExtResource("3_6c0ro") + +[node name="RightEye" type="MeshInstance3D" parent="Skin/MainBody"] +transform = Transform3D(0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0.1, 0.6, -0.25) +mesh = SubResource("SphereMesh_tudvv") + +[node name="LeftEye" type="MeshInstance3D" parent="Skin/MainBody"] +transform = Transform3D(0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, -0.1, 0.6, -0.25) +mesh = SubResource("SphereMesh_1gltg") + +[node name="StateMachine" type="Node" parent="." node_paths=PackedStringArray("current_state")] +script = ExtResource("4_40cmc") +current_state = NodePath("Idle") + +[node name="Idle" type="Node" parent="StateMachine" node_paths=PackedStringArray("move_state")] +script = ExtResource("5_hq6tn") +move_state = NodePath("../Move") + +[node name="Move" type="Node" parent="StateMachine" node_paths=PackedStringArray("idle_state", "fall_state")] +script = ExtResource("6_1teax") +idle_state = NodePath("../Idle") +fall_state = NodePath("../Fall") + +[node name="Fall" type="Node" parent="StateMachine" node_paths=PackedStringArray("move_state", "idle_state")] +script = ExtResource("7_jfat4") +move_state = NodePath("../Move") +idle_state = NodePath("../Idle") diff --git a/scenes/runner.tscn b/scenes/runner.tscn index 4e29284..b3229a8 100644 --- a/scenes/runner.tscn +++ b/scenes/runner.tscn @@ -1,10 +1,13 @@ -[gd_scene load_steps=12 format=3 uid="uid://8esyynmieyog"] +[gd_scene load_steps=17 format=3 uid="uid://8esyynmieyog"] [ext_resource type="Script" path="res://scripts/runner.gd" id="1_d63rt"] -[ext_resource type="Script" path="res://scripts/runner_input.gd" id="2_xmliy"] +[ext_resource type="Script" path="res://scripts/multiplayer/input.gd" id="2_xmliy"] [ext_resource type="Material" uid="uid://ccrb46njti2ke" path="res://materials/runner.tres" id="3_6c0ro"] -[ext_resource type="Script" path="res://scripts/state_machine.gd" id="4_40cmc"] +[ext_resource type="Script" path="res://scripts/states/state_machine.gd" id="4_40cmc"] [ext_resource type="Script" path="res://scripts/states/idle.gd" id="5_hq6tn"] +[ext_resource type="Script" path="res://scripts/states/run.gd" id="6_1teax"] +[ext_resource type="Script" path="res://scripts/states/fall.gd" id="7_jfat4"] +[ext_resource type="Script" path="res://scripts/states/walk.gd" id="8_phh70"] [sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_ukf45"] properties/0/path = NodePath(".:player_id") @@ -18,9 +21,12 @@ properties/2/spawn = true properties/2/replication_mode = 2 [sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_1agtp"] -properties/0/path = NodePath("RunnerInput:move_direction") +properties/0/path = NodePath("Input:direction") properties/0/spawn = true properties/0/replication_mode = 2 +properties/1/path = NodePath("Input:walking") +properties/1/spawn = true +properties/1/replication_mode = 2 [sub_resource type="SphereShape3D" id="SphereShape3D_wsx1k"] @@ -34,52 +40,78 @@ height = 1.8 [sub_resource type="PrismMesh" id="PrismMesh_fcj1v"] -[node name="Runner" type="CharacterBody3D"] -script = ExtResource("1_d63rt") +[sub_resource type="SphereMesh" id="SphereMesh_tudvv"] -[node name="RunnerSync" type="MultiplayerSynchronizer" parent="."] +[sub_resource type="SphereMesh" id="SphereMesh_1gltg"] + +[node name="Runner" type="CharacterBody3D" node_paths=PackedStringArray("state_machine")] +script = ExtResource("1_d63rt") +state_machine = NodePath("StateMachine") + +[node name="Sync" type="MultiplayerSynchronizer" parent="."] replication_config = SubResource("SceneReplicationConfig_ukf45") -[node name="RunnerInput" type="MultiplayerSynchronizer" parent="."] +[node name="Input" type="MultiplayerSynchronizer" parent="."] unique_name_in_owner = true replication_config = SubResource("SceneReplicationConfig_1agtp") script = ExtResource("2_xmliy") -[node name="RunnerCamera" type="Camera3D" parent="."] +[node name="Camera" type="Camera3D" parent="."] unique_name_in_owner = true [node name="CameraPivot" type="Node3D" parent="."] unique_name_in_owner = true transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0) -[node name="RunnerCameraSpringArm3D" type="SpringArm3D" parent="CameraPivot"] +[node name="CameraSpringArm" type="SpringArm3D" parent="CameraPivot"] shape = SubResource("SphereShape3D_wsx1k") spring_length = 3.5 -[node name="RunnerCameraTarget" type="Node3D" parent="CameraPivot/RunnerCameraSpringArm3D"] +[node name="CameraTarget" type="Node3D" parent="CameraPivot/CameraSpringArm"] unique_name_in_owner = true transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0) -[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +[node name="Collider" type="CollisionShape3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) shape = SubResource("CapsuleShape3D_j6tb3") -[node name="RunnerSkin" type="Node3D" parent="."] +[node name="Skin" type="Node3D" parent="."] unique_name_in_owner = true -[node name="MeshInstance3D" type="MeshInstance3D" parent="RunnerSkin"] +[node name="MainBody" type="MeshInstance3D" parent="Skin"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) mesh = SubResource("CapsuleMesh_di3a0") skeleton = NodePath("../..") surface_material_override/0 = ExtResource("3_6c0ro") -[node name="MeshInstance3D" type="MeshInstance3D" parent="RunnerSkin/MeshInstance3D"] -transform = Transform3D(0.35, 0, 0, 0, -1.09278e-08, 0.1, 0, -0.25, -4.37114e-09, 0, 0.65, -0.3) +[node name="Beak" type="MeshInstance3D" parent="Skin/MainBody"] +transform = Transform3D(0.35, 0, 0, 0, -0.105655, 0.0906308, 0, -0.226577, -0.0422618, 0, 0.45, -0.3) mesh = SubResource("PrismMesh_fcj1v") -surface_material_override/0 = ExtResource("3_6c0ro") -[node name="StateMachine" type="Node" parent="."] +[node name="RightEye" type="MeshInstance3D" parent="Skin/MainBody"] +transform = Transform3D(0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0.1, 0.6, -0.25) +mesh = SubResource("SphereMesh_tudvv") + +[node name="LeftEye" type="MeshInstance3D" parent="Skin/MainBody"] +transform = Transform3D(0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, -0.1, 0.6, -0.25) +mesh = SubResource("SphereMesh_1gltg") + +[node name="StateMachine" type="Node" parent="." node_paths=PackedStringArray("current_state")] script = ExtResource("4_40cmc") +current_state = NodePath("Idle") [node name="Idle" type="Node" parent="StateMachine"] +unique_name_in_owner = true script = ExtResource("5_hq6tn") + +[node name="Run" type="Node" parent="StateMachine"] +unique_name_in_owner = true +script = ExtResource("6_1teax") + +[node name="Fall" type="Node" parent="StateMachine"] +unique_name_in_owner = true +script = ExtResource("7_jfat4") + +[node name="Walk" type="Node" parent="StateMachine"] +unique_name_in_owner = true +script = ExtResource("8_phh70") diff --git a/scripts/in_game.gd b/scripts/in_game.gd index 5dc9423..fd6026d 100644 --- a/scripts/in_game.gd +++ b/scripts/in_game.gd @@ -1,13 +1,10 @@ extends Node3D -const template := "FPS: %d\nPing: %d ms" +const statsTemplate := "FPS: %d\nPing: %d ms" var runner_scene := preload("res://scenes/runner.tscn") var _ping := 0.0 -var _runners_node: Node3D - -func _ready() -> void: - _runners_node = get_node("RunnersNode") +@onready var _runners_node: Node3D = %Runners func spawn_player(player_id) -> void: if multiplayer.is_server(): @@ -21,7 +18,7 @@ func _process(_delta: float) -> void: if DisplayServer.get_name() == "headless": return - %RichTextLabel.text = template % [ + %StatsLabel.text = statsTemplate % [ Engine.get_frames_per_second(), _ping, ] diff --git a/scripts/main.gd b/scripts/main.gd new file mode 100644 index 0000000..659e43a --- /dev/null +++ b/scripts/main.gd @@ -0,0 +1,7 @@ +extends Node + +var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity") +var gravity_vector: Vector3 = ProjectSettings.get_setting("physics/3d/default_gravity_vector") +var physics_tickrate = Engine.get_physics_ticks_per_second() +var terminal_velocity: float = 150.0 +var gravity_velocity: Vector3 = (gravity_vector * gravity) / (physics_tickrate as float) diff --git a/scripts/main_menu.gd b/scripts/main_menu.gd index f277c34..b937a9b 100644 --- a/scripts/main_menu.gd +++ b/scripts/main_menu.gd @@ -1,5 +1,5 @@ extends Control func _on_join_button_pressed() -> void: - MultiplayerManager.connect_to_ip(%IpAddressTextEdit.text) + MultiplayerManager.connect_to_ip(%IpTextBox.text) get_tree().change_scene_to_file("res://scenes/in_game.tscn") diff --git a/scripts/runner_input.gd b/scripts/multiplayer/input.gd similarity index 50% rename from scripts/runner_input.gd rename to scripts/multiplayer/input.gd index 07ef6fd..806bd0a 100644 --- a/scripts/runner_input.gd +++ b/scripts/multiplayer/input.gd @@ -1,10 +1,9 @@ extends MultiplayerSynchronizer -var move_direction: Vector2 +@export var direction: Vector2 = Vector2.ZERO +@export var walking: bool = false func _ready() -> void: - move_direction = Vector2.ZERO - if multiplayer.is_server() or get_multiplayer_authority() != multiplayer.get_unique_id(): set_process(false) set_physics_process(false) @@ -12,5 +11,6 @@ func _ready() -> void: func _physics_process(_delta: float) -> void: var directional_input := Input.get_vector("move_right", "move_left", "move_forward", "move_back") - var camera_adjusted: Vector3 = (directional_input.x * %RunnerCameraTarget.global_basis.z) + (directional_input.y * %RunnerCameraTarget.global_basis.x) - move_direction = Vector2(camera_adjusted.x, camera_adjusted.z).rotated(PI / 2.0) + var camera_adjusted: Vector3 = (directional_input.x * %CameraTarget.global_basis.z) + (directional_input.y * %CameraTarget.global_basis.x) + direction = Vector2(camera_adjusted.x, camera_adjusted.z).rotated(PI / 2.0).normalized() + walking = Input.is_action_pressed("walk") diff --git a/scripts/runner.gd b/scripts/runner.gd index 36c3ff1..0a06cc7 100644 --- a/scripts/runner.gd +++ b/scripts/runner.gd @@ -1,11 +1,11 @@ extends CharacterBody3D -const _gravity := -30.0 - @export var player_id := 69: set(id): player_id = id - %RunnerInput.set_multiplayer_authority(id) + %Input.set_multiplayer_authority(id) + +@export var state_machine: Node @export_group("Camera") @export_range(0.0, 1.0) var mouse_sensitivity := 0.2 @@ -13,8 +13,10 @@ const _gravity := -30.0 @export var smooth_camera := false @export_group("Movement") -@export var move_speed := 8.0 -@export var acceleration := 30.0 +@export var run_speed := 8.0 +@export var walk_speed := 4.0 +@export var acceleration := 45.0 +@export var air_deceleration := 5.0 @export var rotation_speed := 20.0 @export_group("Client Tweening") @@ -23,25 +25,26 @@ const _gravity := -30.0 @export var client_smoothing_rotation_speed := 10.0 @onready var _camera_pivot: Node3D = %CameraPivot -@onready var _camera_target: Node3D = %RunnerCameraTarget -@onready var _camera: Node3D = %RunnerCamera -@onready var _skin: Node3D = %RunnerSkin +@onready var _camera_target: Node3D = %CameraTarget +@onready var _camera: Node3D = %Camera +@onready var skin: Node3D = %Skin -var _camera_input_direction := Vector2.ZERO -var _last_direction := Vector3.FORWARD -var _on_ground := false +var camera_input_direction := Vector2.ZERO +var last_direction := Vector3.FORWARD +@export_group("Server variables") @export var server_position := Vector3.ZERO @export var server_rotation := Vector3.ZERO func _ready() -> void: + state_machine.set_subject(self) if multiplayer.is_server(): return if multiplayer.get_unique_id() == player_id: - %RunnerCamera.make_current() + %Camera.make_current() else: - %RunnerCamera.clear_current(false) + %Camera.clear_current(false) func _input(event: InputEvent) -> void: if multiplayer.get_unique_id() != player_id: @@ -54,17 +57,18 @@ func _input(event: InputEvent) -> void: if event is InputEventMouseMotion: if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED: - _camera_input_direction += event.screen_relative * mouse_sensitivity + camera_input_direction += event.screen_relative * mouse_sensitivity func _physics_process(delta: float) -> void: + state_machine.process_physics(delta) if multiplayer.get_unique_id() == player_id: _camera_pivot.rotation.x = clamp( - _camera_pivot.rotation.x - _camera_input_direction.y * delta, + _camera_pivot.rotation.x - camera_input_direction.y * delta, -PI / 3.0, PI / 6.0, ) - _camera_pivot.rotation.y -= _camera_input_direction.x * delta + _camera_pivot.rotation.y -= camera_input_direction.x * delta _camera.global_rotation = _camera_pivot.global_rotation if smooth_camera: @@ -72,26 +76,17 @@ func _physics_process(delta: float) -> void: else: _camera.global_position = _camera_target.global_position - _camera_input_direction = Vector2.ZERO + camera_input_direction = Vector2.ZERO - if multiplayer.is_server(): - var move_direction = Vector3(%RunnerInput.move_direction.x, 0, %RunnerInput.move_direction.y) - var y_velocity := velocity.y - velocity = velocity.move_toward(move_direction * move_speed, acceleration * delta) - velocity.y = y_velocity + (_gravity * delta) - move_and_slide() - - if move_direction.length() >= 0.1: - _last_direction = move_direction - var target_angle := Vector3.FORWARD.signed_angle_to(_last_direction, Vector3.UP) - _skin.global_rotation.y = lerp_angle(_skin.rotation.y, target_angle, rotation_speed * delta) - - server_position = position - server_rotation = _skin.global_rotation - else: + if not multiplayer.is_server(): if client_smoothing: position = lerp(position, server_position, client_smoothing_speed * delta) - _skin.global_rotation.y = lerp_angle(_skin.global_rotation.y, server_rotation.y, client_smoothing_rotation_speed * delta) + skin.global_rotation.y = lerp_angle(skin.global_rotation.y, server_rotation.y, client_smoothing_rotation_speed * delta) else: position = server_position - _skin.global_rotation.y = server_rotation.y + skin.global_rotation.y = server_rotation.y + + if multiplayer.is_server(): + server_position = position + server_rotation = skin.global_rotation + #print("Velocity: %s" % velocity) diff --git a/scripts/state_machine.gd b/scripts/state_machine.gd deleted file mode 100644 index e359755..0000000 --- a/scripts/state_machine.gd +++ /dev/null @@ -1,33 +0,0 @@ -extends Node - -@export var starting_state: State - -var current_state: State - -func init(subject: Node) -> void: - for state in get_children(): - state.subject = subject - - _change_state(starting_state) - -func _change_state(new_state: State) -> void: - if current_state: - current_state.exit() - - current_state = new_state - current_state.enter() - -func _physics_process(delta: float) -> void: - var new_state = current_state.process_physics(delta) - if new_state: - _change_state(new_state) - -func _unhandled_input(event: InputEvent) -> void: - var new_state = current_state.process_input(event) - if new_state: - _change_state(new_state) - -func _process(delta: float) -> void: - var new_state = current_state.process_frame(delta) - if new_state: - _change_state(new_state) diff --git a/scripts/states/fall.gd b/scripts/states/fall.gd new file mode 100644 index 0000000..ee5ef35 --- /dev/null +++ b/scripts/states/fall.gd @@ -0,0 +1,22 @@ +extends State + +func process_physics(delta: float) -> State: + if not multiplayer.is_server(): + return + + var target_velocity = Vector3(0, subject.velocity.y, 0) + subject.velocity = subject.velocity.move_toward(target_velocity, subject.air_deceleration * delta) + subject.velocity += Main.gravity_velocity + subject.move_and_slide() + + if subject.is_on_floor(): + var input_direction = %Input.direction + if input_direction.length() < 0.05: + return %Idle + + if %Input.walking: + return %Walk + + return %Run + + return diff --git a/scripts/states/idle.gd b/scripts/states/idle.gd index 99793dd..7bfe6b3 100644 --- a/scripts/states/idle.gd +++ b/scripts/states/idle.gd @@ -1,4 +1,19 @@ extends State func process_physics(delta: float) -> State: - return + if not multiplayer.is_server(): + return + + var target_velocity = Vector3(0, subject.velocity.y, 0) + subject.velocity = subject.velocity.move_toward(target_velocity, subject.acceleration * delta) + subject.velocity += Main.gravity_velocity + subject.move_and_slide() + + if not subject.is_on_floor(): + return %Fall + + var input_direction = %Input.direction + if input_direction.length() < 0.05: + return + + return %Run diff --git a/scripts/states/run.gd b/scripts/states/run.gd new file mode 100644 index 0000000..9d313e3 --- /dev/null +++ b/scripts/states/run.gd @@ -0,0 +1,28 @@ +extends State + +func process_physics(delta: float) -> State: + if not multiplayer.is_server(): + return + + var input_direction = %Input.direction + if input_direction.length() < 0.05: + return %Idle + + var move_direction = Vector3(input_direction.x, 0, input_direction.y) + var target_velocity = Vector3(move_direction.x * subject.run_speed, subject.velocity.y, move_direction.z * subject.run_speed) + subject.velocity = subject.velocity.move_toward(target_velocity, subject.acceleration * delta) + subject.velocity += Main.gravity_velocity + subject.move_and_slide() + + if move_direction.length() >= 0.1: + subject.last_direction = move_direction + var target_angle := Vector3.FORWARD.signed_angle_to(subject.last_direction, Vector3.UP) + subject.skin.global_rotation.y = lerp_angle(subject.skin.rotation.y, target_angle, subject.rotation_speed * delta) + + if %Input.walking: + return %Walk + + if not subject.is_on_floor(): + return %Fall + + return diff --git a/scripts/state.gd b/scripts/states/state.gd similarity index 69% rename from scripts/state.gd rename to scripts/states/state.gd index 97168f8..2bbb3c6 100644 --- a/scripts/state.gd +++ b/scripts/states/state.gd @@ -1,9 +1,6 @@ class_name State extends Node -@export var move_speed: float = 100.0 -@export var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity") - var subject func enter() -> void: diff --git a/scripts/states/state_machine.gd b/scripts/states/state_machine.gd new file mode 100644 index 0000000..05f81c5 --- /dev/null +++ b/scripts/states/state_machine.gd @@ -0,0 +1,51 @@ +extends Node + +@export var current_state: State +var subject: Node + +func set_subject(new_subject: Node) -> void: + subject = new_subject + for state in get_children(): + state.subject = subject + +func _change_state(new_state: State) -> void: + if current_state: + #print("Exiting: %s" % current_state.name) + current_state.exit() + + current_state = new_state + print("Entering: %s" % current_state.name) + current_state.enter() + +func process_physics(delta: float) -> void: + if not current_state: + return + + if not current_state.subject: + return + + var new_state = current_state.process_physics(delta) + if new_state: + _change_state(new_state) + +func process_input(event: InputEvent) -> void: + if not current_state: + return + + if not current_state.subject: + return + + var new_state = current_state.process_input(event) + if new_state: + _change_state(new_state) + +func process_frame(delta: float) -> void: + if not current_state: + return + + if not current_state.subject: + return + + var new_state = current_state.process_frame(delta) + if new_state: + _change_state(new_state) diff --git a/scripts/states/walk.gd b/scripts/states/walk.gd new file mode 100644 index 0000000..9f848a7 --- /dev/null +++ b/scripts/states/walk.gd @@ -0,0 +1,28 @@ +extends State + +func process_physics(delta: float) -> State: + if not multiplayer.is_server(): + return + + var input_direction = %Input.direction + if input_direction.length() < 0.05: + return %Idle + + var move_direction = Vector3(input_direction.x, 0, input_direction.y) + var target_velocity = Vector3(move_direction.x * subject.walk_speed, subject.velocity.y, move_direction.z * subject.walk_speed) + subject.velocity = subject.velocity.move_toward(target_velocity, subject.acceleration * delta) + subject.velocity += Main.gravity_velocity + subject.move_and_slide() + + if move_direction.length() >= 0.1: + subject.last_direction = move_direction + var target_angle := Vector3.FORWARD.signed_angle_to(subject.last_direction, Vector3.UP) + subject.skin.global_rotation.y = lerp_angle(subject.skin.rotation.y, target_angle, subject.rotation_speed * delta) + + if not %Input.walking: + return %Run + + if not subject.is_on_floor(): + return %Fall + + return