@tool class_name EntityMovement extends Node const FRICTION = 0.01 const WALK_SPEED_DEFAULT = 8 const RUN_SPEED_DEFAULT = 12 var _inputDir:Vector2 = Vector2.ZERO var _running:bool = false @export var body:CharacterBody3D @export var rotate:Node3D @export var walkSpeed:float = WALK_SPEED_DEFAULT @export var runSpeed:float = RUN_SPEED_DEFAULT # # Private Methods # 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 var speed = walkSpeed if _running: speed = runSpeed 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 # # Protected Methods # func canMove() -> bool: return true # # Callbacks # func _enter_tree() -> void: pass func _physics_process(delta:float) -> void: if Engine.is_editor_hint(): return if !body: return _applyGravity() _applyFriction(delta) _applyMovement() body.move_and_slide()