refactor to state machine

This commit is contained in:
2025-02-02 01:08:44 +09:00
parent c8c5c08b4d
commit be682b2813
18 changed files with 379 additions and 121 deletions
+3 -6
View File
@@ -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,
]
+7
View File
@@ -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)
+1 -1
View File
@@ -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")
@@ -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")
+29 -34
View File
@@ -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)
-33
View File
@@ -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)
+22
View File
@@ -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
+16 -1
View File
@@ -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
+28
View File
@@ -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
@@ -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:
+51
View File
@@ -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)
+28
View File
@@ -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