127 lines
3.9 KiB
GDScript
127 lines
3.9 KiB
GDScript
extends CharacterBody3D
|
|
|
|
const DIST_FLOOR_SNAP := Vector3.DOWN * 0.2
|
|
|
|
@onready var label : Label = $CanvasLayer/Label
|
|
@onready var synchroniser = $Networking/MultiplayerSynchronizer
|
|
|
|
@onready var body : Node3D = $Body
|
|
@onready var head : Node3D = $Body/Head
|
|
@onready var cam : Camera3D = $Body/Head/Camera3D
|
|
|
|
@export var mouse_sensitivity = 5.0
|
|
|
|
@export var stop_speed = 4.0
|
|
@export var move_speed = 20.0
|
|
@export var max_slope_angle = 50.0
|
|
|
|
@export var gravity = 60.0
|
|
@export var max_fall_speed = 50.0
|
|
@export var jump_height = 2.5
|
|
|
|
@export var accel_ground = 10.0
|
|
@export var accel_air = 1.0
|
|
#export var accel_water: float := 4.0
|
|
|
|
@export var friction_ground = 6.0
|
|
#export var friction_water: float := 1.0
|
|
|
|
|
|
var floor_snap := Vector3.ZERO
|
|
|
|
func _ready():
|
|
synchroniser.set_multiplayer_authority(str(name).to_int())
|
|
cam.current = is_local_authority()
|
|
|
|
func is_local_authority():
|
|
return synchroniser.get_multiplayer_authority() == multiplayer.get_unique_id()
|
|
|
|
func _process(_delta):
|
|
if not is_local_authority():
|
|
return
|
|
label.text = "H Velocity: %3.2f" % [Vector2(velocity.x, velocity.z).length()]
|
|
label.text += "\nV Velocity: %3.2f" % [velocity.y]
|
|
label.text += "\nOn floor: %s" % is_on_floor()
|
|
|
|
func get_move_direction() -> Vector3:
|
|
var input_dir := Vector2(
|
|
Input.get_action_strength("move_backward") - Input.get_action_strength("move_forward"),
|
|
Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
|
|
).normalized();
|
|
|
|
return input_dir.x * body.global_transform.basis.z + input_dir.y * body.global_transform.basis.x
|
|
|
|
func _input(event):
|
|
if is_local_authority():
|
|
if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED and event is InputEventMouseMotion:
|
|
rotate_look(event.relative * 0.001 * mouse_sensitivity)
|
|
|
|
func rotate_look(amount : Vector2) -> void:
|
|
body.rotation.y -= amount.x
|
|
head.rotation.x = clamp(head.rotation.x - amount.y, -PI * 0.5, PI * 0.5)
|
|
|
|
func _physics_process(delta):
|
|
if !is_local_authority():
|
|
|
|
move_and_slide()
|
|
return
|
|
|
|
|
|
var was_on_floor : bool = is_on_floor()
|
|
var h_target_dir : Vector3 = get_move_direction()
|
|
|
|
if is_on_floor():
|
|
apply_friction(delta)
|
|
accelerate(delta, h_target_dir, move_speed, accel_ground)
|
|
if Input.is_action_pressed("jump"):
|
|
velocity.y = sqrt(2 * jump_height * abs(gravity))
|
|
floor_snap = Vector3.ZERO
|
|
else:
|
|
# hack: only add gravity not checked ground, to prevent sliding checked slopes
|
|
# This works because move_and_slide_with_snap warps the player to the ground in other cases
|
|
velocity.y = max(-max_fall_speed, velocity.y - gravity * delta)
|
|
accelerate(delta, h_target_dir, move_speed, accel_air)
|
|
|
|
set_velocity(velocity)
|
|
# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `floor_snap`
|
|
set_up_direction(Vector3.UP)
|
|
set_floor_stop_on_slope_enabled(true)
|
|
set_max_slides(4)
|
|
set_floor_max_angle(deg_to_rad(max_slope_angle))
|
|
# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `false`
|
|
move_and_slide()
|
|
velocity = velocity
|
|
|
|
if !was_on_floor and is_on_floor():
|
|
floor_snap = DIST_FLOOR_SNAP
|
|
elif was_on_floor and !is_on_floor():
|
|
floor_snap = Vector3.ZERO
|
|
|
|
func accelerate(delta : float, p_target_dir : Vector3, p_target_speed : float, p_accel : float):
|
|
var current_speed : float = velocity.dot(p_target_dir)
|
|
var add_speed : float = p_target_speed - current_speed
|
|
if add_speed > 0:
|
|
var accel_speed : float = min(add_speed, p_accel * delta * p_target_speed)
|
|
velocity += p_target_dir * accel_speed
|
|
|
|
func apply_friction(delta : float):
|
|
|
|
#var vec : Vector3 = velocity
|
|
var speed : float = velocity.length()
|
|
if is_zero_approx(speed):
|
|
velocity = Vector3.ZERO
|
|
return
|
|
|
|
var drop : float = 0.0
|
|
var control : float = max(speed, stop_speed)
|
|
|
|
# ground friction
|
|
if is_on_floor():
|
|
drop += control * friction_ground * delta
|
|
|
|
# water friction not implemented
|
|
var new_speed : float = max(0.0, speed - drop)
|
|
new_speed /= speed
|
|
|
|
velocity *= new_speed
|