class_name EntityMovement 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" }; const FacingDirAngle = { FacingDirection.SOUTH: 0.0, FacingDirection.EAST: PI / 2, FacingDirection.NORTH: PI, FacingDirection.WEST: -PI / 2 }; @export var body:CharacterBody3D @export var rotate: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: 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 !body.is_on_floor(): body.velocity += PHYSICS.GRAVITY * get_process_delta_time() func applyMovement() -> void: if !canMove(): return var cameraCurrent = get_viewport().get_camera_3d() if !cameraCurrent: return # Use camera orientation for movement direction var camBasis = cameraCurrent.global_transform.basis # Forward and right vectors, ignore vertical component var forward = -camBasis.z forward.y = 0 forward = forward.normalized() var right = camBasis.x right.y = 0 right = right.normalized() var directionAdjusted = ( forward * inputDir.y + right * inputDir.x ).normalized() if directionAdjusted.length() <= 0.01: return if rotate: var targetRot = atan2(directionAdjusted.x, directionAdjusted.z) rotate.rotation.y = targetRot body.velocity.x = directionAdjusted.x * SPEED body.velocity.z = directionAdjusted.z * SPEED func applyFriction(delta:float) -> void: body.velocity.x *= delta * FRICTION body.velocity.z *= delta * FRICTION func _physics_process(delta:float) -> void: if !body: return applyGravity() applyFriction(delta) applyMovement() applyFacingDir() body.move_and_slide()