video here
extends CharacterBody3D
# --- NODES ---
@onready var animation_player: AnimationPlayer = $visuals/character/AnimationPlayer
@onready var camera_mount := $camera_mount # Changed from SpringArm3D
@onready var camera := $camera_mount/Camera3D
# --- SETTINGS ---
const SPEED = 5.0
const JUMP_VELOCITY = 6.5
const SENSITIVITY = 0.005 # Adjust this for mouse speed
# Get the gravity from the project settings
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
enum State { idle, walk, jump }
var current_state: State = State.idle
func _ready():
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
animation_player.play("idle")
func _input(event: InputEvent) -> void:
# Release mouse with ESC
if event.is_action_pressed("ui_cancel"):
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
# Handle Rotation
if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
if event is InputEventMouseMotion:
# Rotate the whole Player left/right
rotate_y(-event.relative.x * SENSITIVITY)
# Rotate the camera_mount up/down
camera_mount.rotate_x(-event.relative.y * SENSITIVITY)
# Clamp the vertical look so you don't flip upside down
camera_mount.rotation.x = clamp(camera_mount.rotation.x, deg_to_rad(-60), deg_to_rad(60))
func _physics_process(delta: float) -> void:
# 1. Gravity
if not is_on_floor():
velocity.y -= gravity * delta
else:
velocity.y = -0.1
# 2. Jump
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
# 3. Movement
var input_dir := Input.get_vector("left", "right", "forward", "backward")
var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide()
# 4. Animations
update_animations()
func update_animations():
var new_state = current_state
if not is_on_floor():
new_state = State.jump
elif is_moving():
new_state = State.walk
else:
new_state = State.idle
if new_state != current_state:
current_state = new_state
match current_state:
State.idle:
animation_player.play("idle")
State.walk:
animation_player.play("walk")
State.jump:
animation_player.play("jump")
func is_moving() -> bool:
return abs(velocity.z) > 0.1 or abs(velocity.x) > 0.1