Implemented physics interpolation
This commit is contained in:
parent
ca7fa120ea
commit
489a14061a
@ -11,6 +11,6 @@ var terrain: Terrain3D
|
|||||||
var instance_id: int
|
var instance_id: int
|
||||||
|
|
||||||
func _enter_tree():
|
func _enter_tree():
|
||||||
instance_id = 0
|
instance_id = OS.get_process_id() % 2
|
||||||
account = Account.new()
|
account = Account.new()
|
||||||
account.name = "user%d" % instance_id
|
account.name = "user%d" % instance_id
|
||||||
|
@ -28,6 +28,7 @@ process_thread_group = 2
|
|||||||
process_thread_group_order = 0
|
process_thread_group_order = 0
|
||||||
process_thread_messages = 0
|
process_thread_messages = 0
|
||||||
script = ExtResource("2_8hxcx")
|
script = ExtResource("2_8hxcx")
|
||||||
|
host = "akyoto.dev"
|
||||||
|
|
||||||
[node name="Ping" type="Node" parent="Client"]
|
[node name="Ping" type="Node" parent="Client"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
@ -84,8 +85,6 @@ process_thread_group_order = 0
|
|||||||
process_thread_messages = 0
|
process_thread_messages = 0
|
||||||
autostart = true
|
autostart = true
|
||||||
|
|
||||||
[node name="Camera" parent="." instance=ExtResource("12_aljdh")]
|
|
||||||
|
|
||||||
[node name="World" parent="." instance=ExtResource("13_sqmhj")]
|
[node name="World" parent="." instance=ExtResource("13_sqmhj")]
|
||||||
process_thread_group = 2
|
process_thread_group = 2
|
||||||
process_thread_group_order = 0
|
process_thread_group_order = 0
|
||||||
@ -95,8 +94,20 @@ process_thread_messages = 0
|
|||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
script = ExtResource("16_dp6bj")
|
script = ExtResource("16_dp6bj")
|
||||||
|
|
||||||
|
[node name="UpdatePlayers" type="Timer" parent="Players"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
process_priority = 1
|
||||||
|
wait_time = 0.25
|
||||||
|
autostart = true
|
||||||
|
|
||||||
|
[node name="Camera" parent="." instance=ExtResource("12_aljdh")]
|
||||||
|
process_priority = 100
|
||||||
|
process_physics_priority = 100
|
||||||
|
|
||||||
[node name="UI" parent="." instance=ExtResource("17_43qhq")]
|
[node name="UI" parent="." instance=ExtResource("17_43qhq")]
|
||||||
process_mode = 3
|
process_mode = 3
|
||||||
|
process_priority = 100
|
||||||
|
process_physics_priority = 100
|
||||||
|
|
||||||
[connection signal="timeout" from="Client/Ping/Timer" to="Client/Ping" method="send_ping"]
|
[connection signal="timeout" from="Client/Ping/Timer" to="Client/Ping" method="send_ping"]
|
||||||
[connection signal="timeout" from="Client/Login/Timer" to="Client/Login" method="send_login"]
|
[connection signal="timeout" from="Client/Login/Timer" to="Client/Login" method="send_login"]
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
class_name DeathComponent
|
class_name DeathComponent
|
||||||
extends Node
|
extends CharacterComponent
|
||||||
|
|
||||||
@export var health: HealthComponent
|
@export var health: HealthComponent
|
||||||
@export var hud: HUDComponent
|
@export var hud: HUDComponent
|
||||||
@ -10,7 +10,7 @@ extends Node
|
|||||||
var respawn_position: Vector3
|
var respawn_position: Vector3
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
respawn_position = owner.global_position
|
respawn_position = character.global_position
|
||||||
health.death.connect(on_death)
|
health.death.connect(on_death)
|
||||||
|
|
||||||
func on_death():
|
func on_death():
|
||||||
@ -21,20 +21,20 @@ func on_death():
|
|||||||
|
|
||||||
func drop_loot():
|
func drop_loot():
|
||||||
var loot := drop.instantiate() as Node3D
|
var loot := drop.instantiate() as Node3D
|
||||||
owner.get_parent().add_child(loot)
|
character.get_parent().add_child(loot)
|
||||||
loot.global_position = owner.global_position + loot.position
|
loot.global_position = character.global_position + loot.position
|
||||||
|
|
||||||
func die():
|
func die():
|
||||||
DeathComponent.set_physics(owner, false)
|
DeathComponent.set_physics(character, false)
|
||||||
hud.visible = false
|
hud.visible = false
|
||||||
animation.play("slime_death")
|
animation.play("slime_death")
|
||||||
|
|
||||||
func revive():
|
func revive():
|
||||||
health.restore()
|
health.restore()
|
||||||
DeathComponent.set_physics(owner, true)
|
DeathComponent.set_physics(character, true)
|
||||||
hud.visible = true
|
hud.visible = true
|
||||||
(owner as Node3D).transform = Transform3D.IDENTITY
|
character.transform = Transform3D.IDENTITY
|
||||||
owner.global_position = respawn_position
|
character.global_position = respawn_position
|
||||||
animation.play("slime_idle")
|
animation.play("slime_idle")
|
||||||
|
|
||||||
static func set_physics(obj: Node3D, alive: bool):
|
static func set_physics(obj: Node3D, alive: bool):
|
||||||
|
@ -24,7 +24,7 @@ func _process(delta):
|
|||||||
if !collected_by:
|
if !collected_by:
|
||||||
return
|
return
|
||||||
|
|
||||||
global_position = Math.damp(global_position, Global.player.global_position + Vector3.UP, 0.75 * delta)
|
global_position = Math.damp_vector(global_position, Global.player.global_position + Vector3.UP, 0.75 * delta)
|
||||||
|
|
||||||
func on_body_entered(body: Node3D):
|
func on_body_entered(body: Node3D):
|
||||||
if not body is Player:
|
if not body is Player:
|
||||||
|
@ -1,17 +1,20 @@
|
|||||||
class_name Math
|
class_name Math
|
||||||
|
|
||||||
static func damp(from: Variant, to: Variant, weight: float):
|
static func damp(from: Variant, to: Variant, weight: float) -> Variant:
|
||||||
return lerp(from, to, 1 - exp(-weight))
|
return lerp(from, to, 1 - exp(-weight))
|
||||||
|
|
||||||
static func dampf(from: float, to: float, weight: float):
|
static func dampf(from: float, to: float, weight: float) -> float:
|
||||||
return lerpf(from, to, 1 - exp(-weight))
|
return lerpf(from, to, 1 - exp(-weight))
|
||||||
|
|
||||||
static func damp_angle(from: float, to: float, weight: float):
|
static func damp_angle(from: float, to: float, weight: float) -> float:
|
||||||
return lerp_angle(from, to, 1 - exp(-weight))
|
return lerp_angle(from, to, 1 - exp(-weight))
|
||||||
|
|
||||||
static func damp_spherical(from: Vector3, to: Vector3, weight: float):
|
static func damp_spherical(from: Vector3, to: Vector3, weight: float) -> Vector3:
|
||||||
return from.slerp(to, 1 - exp(-weight))
|
return from.slerp(to, 1 - exp(-weight))
|
||||||
|
|
||||||
|
static func damp_vector(from: Vector3, to: Vector3, weight: float) -> Vector3:
|
||||||
|
return from.lerp(to, 1 - exp(-weight))
|
||||||
|
|
||||||
static func from_to_rotation(from: Vector3, to: Vector3) -> Quaternion:
|
static func from_to_rotation(from: Vector3, to: Vector3) -> Quaternion:
|
||||||
var axis := from.cross(to).normalized()
|
var axis := from.cross(to).normalized()
|
||||||
var angle := from.angle_to(to)
|
var angle := from.angle_to(to)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
class_name Character
|
class_name Character
|
||||||
extends CharacterBody3D
|
extends Node3D
|
||||||
|
|
||||||
signal controlled(Controller)
|
signal controlled(Controller)
|
||||||
|
|
||||||
|
9
client/player/CharacterComponent.gd
Normal file
9
client/player/CharacterComponent.gd
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
class_name CharacterComponent
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
var character: Character
|
||||||
|
|
||||||
|
func _enter_tree():
|
||||||
|
assert(owner, "owner not set")
|
||||||
|
assert(owner is Character, "owner must be a character")
|
||||||
|
character = owner
|
@ -7,10 +7,16 @@ var id: String
|
|||||||
## Components
|
## Components
|
||||||
var movement: MovementComponent
|
var movement: MovementComponent
|
||||||
var state: StateComponent
|
var state: StateComponent
|
||||||
|
var performance: PerformanceComponent
|
||||||
|
var animation: AnimationComponent
|
||||||
|
var physics: CharacterBody3D
|
||||||
|
|
||||||
func _enter_tree():
|
func _enter_tree():
|
||||||
movement = $Movement
|
movement = $Movement
|
||||||
state = $State
|
state = $State
|
||||||
|
performance = $Performance
|
||||||
|
animation = $Animation
|
||||||
|
physics = $Physics
|
||||||
|
|
||||||
## Name
|
## Name
|
||||||
signal name_changed(new_name: String)
|
signal name_changed(new_name: String)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
[gd_scene load_steps=31 format=3 uid="uid://2lcnu3dy54lx"]
|
[gd_scene load_steps=32 format=3 uid="uid://2lcnu3dy54lx"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://player/Player.gd" id="1_8gebs"]
|
[ext_resource type="Script" path="res://player/Player.gd" id="1_8gebs"]
|
||||||
[ext_resource type="PackedScene" uid="uid://c8j7t4yg7anb0" path="res://assets/female/Female.blend" id="2_8nah6"]
|
[ext_resource type="PackedScene" uid="uid://c8j7t4yg7anb0" path="res://assets/female/Female.blend" id="2_8nah6"]
|
||||||
@ -26,6 +26,7 @@
|
|||||||
[ext_resource type="AudioStream" uid="uid://cdywep3dxm0y3" path="res://assets/audio/footsteps/Footsteps-Human-Dirt-07.wav" id="19_vvmo0"]
|
[ext_resource type="AudioStream" uid="uid://cdywep3dxm0y3" path="res://assets/audio/footsteps/Footsteps-Human-Dirt-07.wav" id="19_vvmo0"]
|
||||||
[ext_resource type="AudioStream" uid="uid://bp8pka7qhcetq" path="res://assets/audio/footsteps/Footsteps-Human-Dirt-08.wav" id="20_srjtb"]
|
[ext_resource type="AudioStream" uid="uid://bp8pka7qhcetq" path="res://assets/audio/footsteps/Footsteps-Human-Dirt-08.wav" id="20_srjtb"]
|
||||||
[ext_resource type="AudioStream" uid="uid://bgdodasvt7ier" path="res://assets/audio/footsteps/Footsteps-Human-Dirt-01.wav" id="21_a8ikg"]
|
[ext_resource type="AudioStream" uid="uid://bgdodasvt7ier" path="res://assets/audio/footsteps/Footsteps-Human-Dirt-01.wav" id="21_a8ikg"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://b5yfm1sektkv" path="res://player/performance/PerformanceComponent.tscn" id="22_iqcgj"]
|
||||||
[ext_resource type="PackedScene" uid="uid://sx4ein0bju6m" path="res://player/state/StateComponent.tscn" id="28_0i0of"]
|
[ext_resource type="PackedScene" uid="uid://sx4ein0bju6m" path="res://player/state/StateComponent.tscn" id="28_0i0of"]
|
||||||
[ext_resource type="PackedScene" uid="uid://csidusk3jpq0m" path="res://player/voice/VoiceComponent.tscn" id="28_iolce"]
|
[ext_resource type="PackedScene" uid="uid://csidusk3jpq0m" path="res://player/voice/VoiceComponent.tscn" id="28_iolce"]
|
||||||
|
|
||||||
@ -58,10 +59,16 @@ stream_8/weight = 1.0
|
|||||||
stream_9/stream = ExtResource("21_a8ikg")
|
stream_9/stream = ExtResource("21_a8ikg")
|
||||||
stream_9/weight = 1.0
|
stream_9/weight = 1.0
|
||||||
|
|
||||||
[node name="Player" type="CharacterBody3D" groups=["player"]]
|
[node name="Player" type="Node3D"]
|
||||||
|
script = ExtResource("1_8gebs")
|
||||||
|
|
||||||
|
[node name="Physics" type="CharacterBody3D" parent="."]
|
||||||
collision_layer = 512
|
collision_layer = 512
|
||||||
collision_mask = 769
|
collision_mask = 769
|
||||||
script = ExtResource("1_8gebs")
|
|
||||||
|
[node name="Collision" type="CollisionShape3D" parent="Physics"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.8, 0)
|
||||||
|
shape = SubResource("CapsuleShape3D_2f50n")
|
||||||
|
|
||||||
[node name="Model" type="Node3D" parent="."]
|
[node name="Model" type="Node3D" parent="."]
|
||||||
|
|
||||||
@ -97,10 +104,6 @@ bone_idx = 44
|
|||||||
[node name="Heirloom" parent="Model/Female/Armature/GeneralSkeleton/Weapon" instance=ExtResource("7_u8433")]
|
[node name="Heirloom" parent="Model/Female/Armature/GeneralSkeleton/Weapon" instance=ExtResource("7_u8433")]
|
||||||
transform = Transform3D(-4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0, 0, 1, 0.197644, 0, 0)
|
transform = Transform3D(-4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0, 0, 1, 0.197644, 0, 0)
|
||||||
|
|
||||||
[node name="Collision" type="CollisionShape3D" parent="."]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.8, 0)
|
|
||||||
shape = SubResource("CapsuleShape3D_2f50n")
|
|
||||||
|
|
||||||
[node name="HUD" parent="." node_paths=PackedStringArray("health") instance=ExtResource("7_fwgtd")]
|
[node name="HUD" parent="." node_paths=PackedStringArray("health") instance=ExtResource("7_fwgtd")]
|
||||||
layers = 512
|
layers = 512
|
||||||
visibility_range_end = 50.0
|
visibility_range_end = 50.0
|
||||||
@ -129,10 +132,14 @@ footsteps = SubResource("AudioStreamRandomizer_4yj1k")
|
|||||||
[node name="Health" parent="." instance=ExtResource("2_np5ag")]
|
[node name="Health" parent="." instance=ExtResource("2_np5ag")]
|
||||||
max_value = 100.0
|
max_value = 100.0
|
||||||
|
|
||||||
[node name="Movement" parent="." instance=ExtResource("8_25qd0")]
|
[node name="Movement" parent="." node_paths=PackedStringArray("body") instance=ExtResource("8_25qd0")]
|
||||||
|
body = NodePath("../Physics")
|
||||||
|
|
||||||
|
[node name="Performance" parent="." node_paths=PackedStringArray("animation") instance=ExtResource("22_iqcgj")]
|
||||||
|
animation = NodePath("../Animation")
|
||||||
|
|
||||||
[node name="Rotation" parent="." node_paths=PackedStringArray("root") instance=ExtResource("9_agxqu")]
|
[node name="Rotation" parent="." node_paths=PackedStringArray("root") instance=ExtResource("9_agxqu")]
|
||||||
root = NodePath("..")
|
root = NodePath("../Model")
|
||||||
|
|
||||||
[node name="Skills" parent="." instance=ExtResource("14_6idcf")]
|
[node name="Skills" parent="." instance=ExtResource("14_6idcf")]
|
||||||
skills = Array[Resource("res://skill/Skill.gd")]([ExtResource("2_x58e1"), ExtResource("3_l76ly"), null, ExtResource("5_pnues")])
|
skills = Array[Resource("res://skill/Skill.gd")]([ExtResource("2_x58e1"), ExtResource("3_l76ly"), null, ExtResource("5_pnues")])
|
||||||
|
@ -1,16 +1,27 @@
|
|||||||
class_name AnimationComponent
|
class_name AnimationComponent
|
||||||
extends Node
|
extends CharacterComponent
|
||||||
|
|
||||||
|
@export var skip_frames: int = 0
|
||||||
|
|
||||||
var animations: AnimationPlayer
|
var animations: AnimationPlayer
|
||||||
var state: StateComponent
|
var state: StateComponent
|
||||||
|
var accumulated_delta: float
|
||||||
|
var skipped_frames: int
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
state = owner.get_node("State")
|
state = character.get_node("State")
|
||||||
state.transitioned.connect(on_transition)
|
state.transitioned.connect(on_transition)
|
||||||
animations = %AnimationPlayer
|
animations = %AnimationPlayer
|
||||||
|
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
animations.advance(delta)
|
accumulated_delta += delta
|
||||||
|
|
||||||
|
if skipped_frames >= skip_frames:
|
||||||
|
animations.advance(accumulated_delta)
|
||||||
|
accumulated_delta = 0
|
||||||
|
skipped_frames = 0
|
||||||
|
else:
|
||||||
|
skipped_frames += 1
|
||||||
|
|
||||||
func on_transition(_from: StateComponent.State, to: StateComponent.State):
|
func on_transition(_from: StateComponent.State, to: StateComponent.State):
|
||||||
match to:
|
match to:
|
||||||
|
@ -1,22 +1,25 @@
|
|||||||
class_name ProxyController
|
class_name ProxyController
|
||||||
extends Controller
|
extends Controller
|
||||||
|
|
||||||
@export var interpolation_speed := 5.0
|
@export var interpolation_speed := 20.0
|
||||||
|
|
||||||
var player: Player
|
var player: Player
|
||||||
|
var movement: MovementComponent
|
||||||
var server_position: Vector3
|
var server_position: Vector3
|
||||||
|
|
||||||
func _init(new_player: Player):
|
func _init(new_player: Player):
|
||||||
player = new_player
|
player = new_player
|
||||||
|
movement = player.movement
|
||||||
name = "Controller"
|
name = "Controller"
|
||||||
|
process_physics_priority = 1
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
server_position = player.position
|
server_position = player.position
|
||||||
|
|
||||||
func _physics_process(delta: float):
|
func _physics_process(delta: float):
|
||||||
if absf(server_position.x - player.position.x) < 0.001 && absf(server_position.z - player.position.z) < 0.001:
|
if absf(server_position.x - movement.physics_position.x) < 0.001 && absf(server_position.z - movement.physics_position.z) < 0.001:
|
||||||
return
|
return
|
||||||
|
|
||||||
var time := interpolation_speed * delta
|
var time := interpolation_speed * delta
|
||||||
player.position.x = Math.dampf(player.position.x, server_position.x, time)
|
movement.physics_position.x = Math.dampf(movement.physics_position.x, server_position.x, time)
|
||||||
player.position.z = Math.dampf(player.position.z, server_position.z, time)
|
movement.physics_position.z = Math.dampf(movement.physics_position.z, server_position.z, time)
|
@ -1,24 +1,30 @@
|
|||||||
class_name MovementComponent
|
class_name MovementComponent
|
||||||
extends Node
|
extends CharacterComponent
|
||||||
|
|
||||||
|
static var ticks_per_second := ProjectSettings.get_setting("physics/common/physics_ticks_per_second") as float
|
||||||
|
static var gravity := ProjectSettings.get_setting("physics/3d/default_gravity") as float
|
||||||
|
|
||||||
|
@export var body: CharacterBody3D
|
||||||
@export var move_speed := 4.5
|
@export var move_speed := 4.5
|
||||||
@export var jump_velocity := 4.5
|
@export var jump_velocity := 4.5
|
||||||
@export var deceleration_speed := 20
|
@export var deceleration_speed := 20
|
||||||
|
|
||||||
var body: Character
|
|
||||||
var direction: Vector3
|
var direction: Vector3
|
||||||
var gravity: float
|
var physics_position: Vector3
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
|
physics_position = character.position
|
||||||
body = owner as Character
|
character.controlled.connect(on_controlled)
|
||||||
body.controlled.connect(on_controlled)
|
|
||||||
|
|
||||||
func on_controlled(controller: Controller):
|
func _process(delta: float):
|
||||||
controller.direction_changed.connect(on_direction_changed)
|
character.position = Math.damp_vector(character.position, physics_position, ticks_per_second * delta)
|
||||||
controller.jumped.connect(jump)
|
|
||||||
|
|
||||||
func _physics_process(delta):
|
func _physics_process(delta: float):
|
||||||
|
begin_physics()
|
||||||
|
move(delta)
|
||||||
|
end_physics()
|
||||||
|
|
||||||
|
func move(delta: float):
|
||||||
if direction:
|
if direction:
|
||||||
body.velocity.x = direction.x * move_speed
|
body.velocity.x = direction.x * move_speed
|
||||||
body.velocity.z = direction.z * move_speed
|
body.velocity.z = direction.z * move_speed
|
||||||
@ -34,11 +40,22 @@ func _physics_process(delta):
|
|||||||
|
|
||||||
body.move_and_slide()
|
body.move_and_slide()
|
||||||
|
|
||||||
func on_direction_changed(new_direction: Vector3):
|
func begin_physics():
|
||||||
direction = new_direction
|
body.global_position = physics_position
|
||||||
|
|
||||||
|
func end_physics():
|
||||||
|
physics_position = body.global_position
|
||||||
|
body.position = Vector3.ZERO
|
||||||
|
|
||||||
func can_jump() -> bool:
|
func can_jump() -> bool:
|
||||||
return body.is_on_floor()
|
return body.is_on_floor()
|
||||||
|
|
||||||
func jump():
|
func jump():
|
||||||
body.velocity.y = jump_velocity
|
body.velocity.y = jump_velocity
|
||||||
|
|
||||||
|
func on_controlled(controller: Controller):
|
||||||
|
controller.direction_changed.connect(on_direction_changed)
|
||||||
|
controller.jumped.connect(jump)
|
||||||
|
|
||||||
|
func on_direction_changed(new_direction: Vector3):
|
||||||
|
direction = new_direction
|
||||||
|
72
client/player/performance/PerformanceComponent.gd
Normal file
72
client/player/performance/PerformanceComponent.gd
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
class_name PerformanceComponent
|
||||||
|
extends VisibleOnScreenNotifier3D
|
||||||
|
|
||||||
|
const SKIP_FRAMES_INVISIBLE := 16
|
||||||
|
const SKIP_FRAMES_VISIBLE := 8
|
||||||
|
|
||||||
|
static var quality_budget: Array[int] = [
|
||||||
|
10, # 0 skipped frames
|
||||||
|
10, # 1 skipped frame
|
||||||
|
10, # 2 skipped frames
|
||||||
|
10, # 3 skipped frames
|
||||||
|
10, # 4 skipped frames
|
||||||
|
10, # 5 skipped frames
|
||||||
|
10, # 6 skipped frames
|
||||||
|
10, # 7 skipped frames
|
||||||
|
]
|
||||||
|
|
||||||
|
@export var animation: AnimationComponent
|
||||||
|
|
||||||
|
var camera_distance_squared: float
|
||||||
|
var on_screen: bool
|
||||||
|
var skip_frames_visible: int
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
assert(animation)
|
||||||
|
screen_entered.connect(on_screen_entered)
|
||||||
|
screen_exited.connect(on_screen_exited)
|
||||||
|
|
||||||
|
func on_screen_entered():
|
||||||
|
on_screen = true
|
||||||
|
animation.skip_frames = skip_frames_visible
|
||||||
|
|
||||||
|
func on_screen_exited():
|
||||||
|
on_screen = false
|
||||||
|
animation.skip_frames = SKIP_FRAMES_INVISIBLE
|
||||||
|
|
||||||
|
static func update_all_animations():
|
||||||
|
var visible_players: Array[Player] = []
|
||||||
|
|
||||||
|
for player in Global.players.id_to_player.values():
|
||||||
|
player.performance.camera_distance_squared = player.global_position.distance_squared_to(Global.camera.global_position)
|
||||||
|
|
||||||
|
if player.performance.on_screen:
|
||||||
|
visible_players.append(player)
|
||||||
|
else:
|
||||||
|
player.performance.animation.skip_frames = SKIP_FRAMES_INVISIBLE
|
||||||
|
|
||||||
|
if Global.player:
|
||||||
|
Global.player.performance.camera_distance_squared = 0
|
||||||
|
|
||||||
|
visible_players.sort_custom(PerformanceComponent.distance_sort)
|
||||||
|
|
||||||
|
var skip_frames := 0
|
||||||
|
var count := 0
|
||||||
|
|
||||||
|
for player in visible_players:
|
||||||
|
if skip_frames >= quality_budget.size():
|
||||||
|
player.performance.skip_frames_visible = SKIP_FRAMES_VISIBLE
|
||||||
|
player.animation.skip_frames = SKIP_FRAMES_VISIBLE
|
||||||
|
continue
|
||||||
|
|
||||||
|
player.performance.skip_frames_visible = skip_frames
|
||||||
|
player.animation.skip_frames = skip_frames
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
if count >= quality_budget[skip_frames]:
|
||||||
|
skip_frames += 1
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
static func distance_sort(a: Player, b: Player) -> bool:
|
||||||
|
return a.performance.camera_distance_squared < b.performance.camera_distance_squared
|
||||||
|
|
7
client/player/performance/PerformanceComponent.tscn
Normal file
7
client/player/performance/PerformanceComponent.tscn
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://b5yfm1sektkv"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://player/performance/PerformanceComponent.gd" id="1_vp0dv"]
|
||||||
|
|
||||||
|
[node name="Performance" type="VisibleOnScreenNotifier3D"]
|
||||||
|
aabb = AABB(-1, 0, -1, 2, 2, 2)
|
||||||
|
script = ExtResource("1_vp0dv")
|
@ -1,5 +1,5 @@
|
|||||||
class_name RotationComponent
|
class_name RotationComponent
|
||||||
extends Node
|
extends CharacterComponent
|
||||||
|
|
||||||
@export var root: Node3D
|
@export var root: Node3D
|
||||||
@export var rotation_speed: float = 15.0
|
@export var rotation_speed: float = 15.0
|
||||||
@ -8,8 +8,9 @@ var direction: Vector3
|
|||||||
var angle: float
|
var angle: float
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
assert(root, "Rotation root needs to be set")
|
assert(root, "rotation root needs to be set")
|
||||||
(owner as Character).controlled.connect(on_controlled)
|
assert(rotation_speed > 0, "rotation speed must be greater than zero")
|
||||||
|
character.controlled.connect(on_controlled)
|
||||||
|
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
if absf(angle_difference(root.rotation.y, angle)) < 0.001:
|
if absf(angle_difference(root.rotation.y, angle)) < 0.001:
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
class_name SkillsComponent
|
class_name SkillsComponent
|
||||||
extends Node
|
extends CharacterComponent
|
||||||
|
|
||||||
@export var skills: Array[Skill]
|
@export var skills: Array[Skill]
|
||||||
|
|
||||||
var character: Character
|
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
character = owner
|
|
||||||
character.controlled.connect(on_controlled)
|
character.controlled.connect(on_controlled)
|
||||||
|
|
||||||
func on_controlled(controller: Controller):
|
func on_controlled(controller: Controller):
|
||||||
@ -25,4 +22,4 @@ func use_skill(slot: int):
|
|||||||
return
|
return
|
||||||
|
|
||||||
var scene := skill.scene.instantiate()
|
var scene := skill.scene.instantiate()
|
||||||
owner.add_child(scene)
|
character.add_child(scene)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
class_name StateComponent
|
class_name StateComponent
|
||||||
extends Node
|
extends CharacterComponent
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
None,
|
None,
|
||||||
@ -17,7 +17,7 @@ var _current: State
|
|||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
current = State.Idle
|
current = State.Idle
|
||||||
movement = owner.get_node("Movement")
|
movement = character.get_node("Movement")
|
||||||
|
|
||||||
func _process(_delta):
|
func _process(_delta):
|
||||||
if current == State.Skill:
|
if current == State.Skill:
|
||||||
|
@ -24,4 +24,4 @@ func _physics_process(_delta):
|
|||||||
body.velocity.x = direction.x * movement.move_speed * 3.0
|
body.velocity.x = direction.x * movement.move_speed * 3.0
|
||||||
body.velocity.y = 0
|
body.velocity.y = 0
|
||||||
body.velocity.z = direction.z * movement.move_speed * 3.0
|
body.velocity.z = direction.z * movement.move_speed * 3.0
|
||||||
body.move_and_slide()
|
body.move_and_slide()
|
||||||
|
@ -25,4 +25,6 @@ func on_focus_exited():
|
|||||||
func on_text_submitted(message: String):
|
func on_text_submitted(message: String):
|
||||||
text = ""
|
text = ""
|
||||||
release_focus()
|
release_focus()
|
||||||
(owner as Chat).message_submitted.emit(message)
|
|
||||||
|
var chat := owner as Chat
|
||||||
|
chat.message_submitted.emit(message)
|
||||||
|
@ -4,6 +4,6 @@ extends Label
|
|||||||
func _ready():
|
func _ready():
|
||||||
text = get_parent().name + ":"
|
text = get_parent().name + ":"
|
||||||
|
|
||||||
func _get_configuration_warnings():
|
func _get_configuration_warnings() -> PackedStringArray:
|
||||||
text = get_parent().name + ":"
|
text = get_parent().name + ":"
|
||||||
return []
|
return []
|
||||||
|
@ -4,4 +4,4 @@ func _process(_delta):
|
|||||||
if Global.player == null:
|
if Global.player == null:
|
||||||
return
|
return
|
||||||
|
|
||||||
text = str(Global.player.velocity)
|
text = str(Global.player.physics.velocity)
|
||||||
|
@ -1,27 +1,33 @@
|
|||||||
class_name PlayerManager
|
class_name PlayerManager
|
||||||
extends Node3D
|
extends Node3D
|
||||||
|
|
||||||
var players = {}
|
var id_to_player = {}
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
Global.players = self
|
Global.players = self
|
||||||
|
|
||||||
|
var timer := %UpdatePlayers as Timer
|
||||||
|
timer.timeout.connect(tick)
|
||||||
|
|
||||||
|
func tick():
|
||||||
|
PerformanceComponent.update_all_animations()
|
||||||
|
|
||||||
func add(player: Player):
|
func add(player: Player):
|
||||||
if has(player.id):
|
if has(player.id):
|
||||||
return
|
return
|
||||||
|
|
||||||
add_child(player)
|
add_child(player)
|
||||||
players[player.id] = player
|
id_to_player[player.id] = player
|
||||||
|
|
||||||
func get_player(id: String) -> Player:
|
func get_player(id: String) -> Player:
|
||||||
return players[id] as Player
|
return id_to_player[id] as Player
|
||||||
|
|
||||||
func has(id: String) -> bool:
|
func has(id: String) -> bool:
|
||||||
return players.has(id)
|
return id_to_player.has(id)
|
||||||
|
|
||||||
func remove(id: String):
|
func remove(id: String):
|
||||||
if !players.has(id):
|
if !id_to_player.has(id):
|
||||||
return
|
return
|
||||||
|
|
||||||
players[id].queue_free()
|
id_to_player[id].queue_free()
|
||||||
players.erase(id)
|
id_to_player.erase(id)
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -49,7 +50,8 @@ func udpClient(wg *sync.WaitGroup, id int) {
|
|||||||
|
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
loginRequest := [2]string{fmt.Sprintf("user%d", id+1), sha256Text("password")}
|
username := fmt.Sprintf("user%d", id+1)
|
||||||
|
loginRequest := [2]string{username, sha256Text("password")}
|
||||||
data, err := json.Marshal(loginRequest)
|
data, err := json.Marshal(loginRequest)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -69,6 +71,10 @@ func udpClient(wg *sync.WaitGroup, id int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if rand.Float32() > 0.5 {
|
||||||
|
conn.Write([]byte{13})
|
||||||
|
}
|
||||||
|
|
||||||
time.Sleep(*sleepTime)
|
time.Sleep(*sleepTime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user