extends CharacterBody3D const DIST_FLOOR_SNAP := Vector3.DOWN * 0.2 @onready var label : Label = $CanvasLayer/Label @onready var networking = $Networking @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 _enter_tree(): $Networking/MultiplayerSynchronizer.set_multiplayer_authority(str(name).to_int()) $Body/Head/Camera3D.current = is_local_authority() if is_local_authority(): Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) func init(): $Body/Head/Hand.set_weapons() func is_local_authority(): return $Networking/MultiplayerSynchronizer.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() if(multiplayer.get_unique_id() == 1): label.text += "\nNetwork ID: HOST" else: label.text += "\nNetwork ID: %d " % multiplayer.get_unique_id() label.text += "(%dms)" % Network.delta_latency 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(): if not networking.processed_position: position = networking.sync_position networking.processed_position = true velocity = networking.sync_velocity 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 networking.sync_position = position networking.sync_velocity = velocity 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