From ac49bcee0be3beca63ba9b3e55f644abce9a0e6a Mon Sep 17 00:00:00 2001 From: Thayol Date: Wed, 19 Feb 2025 22:23:06 +0900 Subject: [PATCH] add client prediction --- project.godot | 2 +- scenes/house.tscn | 2 -- scenes/runner.tscn | 2 ++ scripts/runner.gd | 37 +++++++++++++++++++++++---------- scripts/states/fall.gd | 2 +- scripts/states/idle.gd | 2 +- scripts/states/run.gd | 2 +- scripts/states/state_machine.gd | 2 +- scripts/states/walk.gd | 2 +- 9 files changed, 34 insertions(+), 19 deletions(-) diff --git a/project.godot b/project.godot index 83e4aea..1ac88d8 100644 --- a/project.godot +++ b/project.godot @@ -13,7 +13,7 @@ config_version=5 config/name="Instructions Clear" run/main_scene="res://scenes/empty.tscn" config/features=PackedStringArray("4.3", "Mobile") -run/max_fps=240 +run/max_fps=120 boot_splash/show_image=false config/icon="res://icon.svg" run/size/borderless=false diff --git a/scenes/house.tscn b/scenes/house.tscn index f37ab7d..9a8388d 100644 --- a/scenes/house.tscn +++ b/scenes/house.tscn @@ -143,14 +143,12 @@ mesh = SubResource("BoxMesh_lm401") [node name="FirstFloorLight" type="OmniLight3D" parent="Lights"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4, 0) -light_energy = 6.0 shadow_enabled = true omni_range = 40.0 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) -light_energy = 6.0 shadow_enabled = true omni_range = 40.0 omni_attenuation = 1.5 diff --git a/scenes/runner.tscn b/scenes/runner.tscn index 55d057b..4dd0ffd 100644 --- a/scenes/runner.tscn +++ b/scenes/runner.tscn @@ -116,3 +116,5 @@ script = ExtResource("7_jfat4") [node name="Walk" type="Node" parent="StateMachine"] unique_name_in_owner = true script = ExtResource("8_phh70") + +[connection signal="delta_synchronized" from="Sync" to="." method="_on_sync_delta_synchronized"] diff --git a/scripts/runner.gd b/scripts/runner.gd index b2edb39..e3b7301 100644 --- a/scripts/runner.gd +++ b/scripts/runner.gd @@ -19,10 +19,16 @@ extends CharacterBody3D @export var air_deceleration := 5.0 @export var rotation_speed := 20.0 -@export_group("Client Tweening") +@export_group("Client Smoothing") @export var client_smoothing := false @export var client_smoothing_speed := 10.0 @export var client_smoothing_rotation_speed := 25.0 +@export var client_prediction := false +@export var client_prediction_tolerance := 0.3 + +@export_group("Server variables") +@export var server_position := Vector3.ZERO +@export var server_rotation := Vector3.ZERO @onready var _camera_pivot: Node3D = %CameraPivot @onready var _camera_platform: Node3D = %CameraPlatform @@ -32,9 +38,8 @@ extends CharacterBody3D 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 +var predicted_position := Vector3.ZERO +var predicted_rotation := Vector3.ZERO func _ready() -> void: state_machine.set_subject(self) @@ -80,14 +85,24 @@ func _physics_process(delta: float) -> void: camera_input_direction = Vector2.ZERO 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) - else: - position = server_position - skin.global_rotation.y = server_rotation.y + if multiplayer.get_unique_id() == player_id and client_prediction: + predicted_position = position + predicted_rotation = skin.global_rotation + + if multiplayer.get_unique_id() != player_id or not client_prediction: + 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) + else: + position = server_position + skin.global_rotation.y = server_rotation.y if multiplayer.is_server(): server_position = position server_rotation = skin.global_rotation - #print("Velocity: %s" % velocity) + pass + +func _on_sync_delta_synchronized() -> void: + if client_prediction and server_position.distance_to(predicted_position) > client_prediction_tolerance: + print("%v VS %v" % [server_position, predicted_position]) + position = server_position diff --git a/scripts/states/fall.gd b/scripts/states/fall.gd index ee5ef35..4c22ecd 100644 --- a/scripts/states/fall.gd +++ b/scripts/states/fall.gd @@ -1,7 +1,7 @@ extends State func process_physics(delta: float) -> State: - if not multiplayer.is_server(): + if not multiplayer.is_server() and (multiplayer.get_unique_id() != subject.player_id or not subject.client_prediction): return var target_velocity = Vector3(0, subject.velocity.y, 0) diff --git a/scripts/states/idle.gd b/scripts/states/idle.gd index 7bfe6b3..415463d 100644 --- a/scripts/states/idle.gd +++ b/scripts/states/idle.gd @@ -1,7 +1,7 @@ extends State func process_physics(delta: float) -> State: - if not multiplayer.is_server(): + if not multiplayer.is_server() and (multiplayer.get_unique_id() != subject.player_id or not subject.client_prediction): return var target_velocity = Vector3(0, subject.velocity.y, 0) diff --git a/scripts/states/run.gd b/scripts/states/run.gd index 9d313e3..da26f49 100644 --- a/scripts/states/run.gd +++ b/scripts/states/run.gd @@ -1,7 +1,7 @@ extends State func process_physics(delta: float) -> State: - if not multiplayer.is_server(): + if not multiplayer.is_server() and (multiplayer.get_unique_id() != subject.player_id or not subject.client_prediction): return var input_direction = %Input.direction diff --git a/scripts/states/state_machine.gd b/scripts/states/state_machine.gd index 05f81c5..9b12467 100644 --- a/scripts/states/state_machine.gd +++ b/scripts/states/state_machine.gd @@ -14,7 +14,7 @@ func _change_state(new_state: State) -> void: current_state.exit() current_state = new_state - print("Entering: %s" % current_state.name) + #print("Entering: %s" % current_state.name) current_state.enter() func process_physics(delta: float) -> void: diff --git a/scripts/states/walk.gd b/scripts/states/walk.gd index 9f848a7..39cf93b 100644 --- a/scripts/states/walk.gd +++ b/scripts/states/walk.gd @@ -1,7 +1,7 @@ extends State func process_physics(delta: float) -> State: - if not multiplayer.is_server(): + if not multiplayer.is_server() and (multiplayer.get_unique_id() != subject.player_id or not subject.client_prediction): return var input_direction = %Input.direction