class_name PlayerMovement extends Node const SPEED = 64.0 const FRICTION = 0.01 enum FacingDirection { SOUTH = 0, EAST = 1, NORTH = 2, WEST = 3 }; const FacingDirWalkAnimations = { FacingDirection.SOUTH: "walk_south", FacingDirection.EAST: "walk_east", FacingDirection.NORTH: "walk_north", FacingDirection.WEST: "walk_west" }; @export var player:CharacterBody3D @export var rotated:Node3D @export var sprite:AnimatedSprite3D var facingDir:FacingDirection = FacingDirection.SOUTH var inputDir:Vector2 = Vector2.ZERO func _enter_tree() -> void: if !sprite: return for dir in FacingDirWalkAnimations: if sprite.animation != FacingDirWalkAnimations[dir]: continue facingDir = dir break func canMove() -> bool: if PAUSE.isMovementPaused(): return false return true func applyFacingDir() -> void: if !sprite || inputDir.length() <= 0.01: return if inputDir.y > 0: if facingDir != FacingDirection.NORTH && inputDir.x != 0: if inputDir.x > 0 && facingDir == FacingDirection.EAST: facingDir = FacingDirection.EAST elif inputDir.x < 0 && facingDir == FacingDirection.WEST: facingDir = FacingDirection.WEST else: facingDir = FacingDirection.NORTH else: facingDir = FacingDirection.NORTH elif inputDir.y < 0: if facingDir != FacingDirection.SOUTH && inputDir.x != 0: if inputDir.x > 0 && facingDir == FacingDirection.EAST: facingDir = FacingDirection.EAST elif inputDir.x < 0 && facingDir == FacingDirection.WEST: facingDir = FacingDirection.WEST else: facingDir = FacingDirection.SOUTH else: facingDir = FacingDirection.SOUTH elif inputDir.x > 0: facingDir = FacingDirection.EAST else: facingDir = FacingDirection.WEST sprite.animation = FacingDirWalkAnimations[facingDir] func applyGravity() -> void: if !player.is_on_floor(): player.velocity += PHYSICS.GRAVITY * get_process_delta_time() func applyMovement() -> void: if !canMove(): return # Use camera orientation for movement direction var cam_basis = get_viewport().get_camera_3d().global_transform.basis # Forward and right vectors, ignore vertical component var forward = -cam_basis.z forward.y = 0 forward = forward.normalized() var right = cam_basis.x right.y = 0 right = right.normalized() var directionAdjusted = ( forward * inputDir.y + right * inputDir.x ).normalized() if directionAdjusted.length() <= 0.01: return if rotated: var targetRot = atan2(directionAdjusted.x, directionAdjusted.z) rotated.rotation.y = targetRot player.velocity.x = directionAdjusted.x * SPEED player.velocity.z = directionAdjusted.z * SPEED func applyFriction(delta:float) -> void: player.velocity.x *= delta * FRICTION player.velocity.z *= delta * FRICTION func _physics_process(delta:float) -> void: if !player: return var cameraCurrent = get_viewport().get_camera_3d() if !cameraCurrent: return applyGravity() applyFriction(delta) applyMovement() applyFacingDir() player.move_and_slide()