public partial class MovementController : Node { [ExportGroup("Movement")] [Export] public float Acceleration { get; set; } = 2.5f; [Export] public float MaxSpeed { get; set; } = 3.0f; [Export] public float FrictionFloor { get; set; } = 3.5f; [Export] public float FrictionAir { get; set; } = 1.0f; [Export] public float SprintMultiplier { get; set; } = 2.0f; [ExportGroup("Jumping")] [Export] public float JumpVelocity { get; set; } = 4.0f; /// Time (in seconds) after pressing the jump button a jump may occur late. [Export] public float JumpEarlyTime { get; set; } = 0.2f; /// Time (in seconds) after leaving a jumpable surface when a jump may still occur. [Export] public float JumpCoyoteTime { get; set; } = 0.2f; public float TimeSinceJumpPressed { get; private set; } = float.PositiveInfinity; public float TimeSinceOnFloor { get; private set; } = float.PositiveInfinity; private CharacterBody3D Player; public override void _Ready() { Player = GetParent(); } public override void _UnhandledInput(InputEvent ev) { if (ev.IsActionPressed("move_jump")) { TimeSinceJumpPressed = 0.0f; GetViewport().SetInputAsHandled(); } } public override void _PhysicsProcess(double delta) { var velocity = Player.Velocity; var horVelocity = new Vector2(velocity.X, velocity.Z); var gravity = (float)ProjectSettings.GetSetting("physics/3d/default_gravity"); velocity.Y -= gravity * (float)delta; var input = Input.GetVector("move_left", "move_right", "move_forward", "move_back"); var camera = GetViewport().GetCamera3D(); var target = input.Rotated(-camera.GlobalRotation.Y) * MaxSpeed; var isOnFloor = Player.IsOnFloor(); var isMoving = target.Dot(horVelocity) > 0.0f; var isSprinting = Input.IsActionPressed("move_sprint"); var accel = isMoving ? Acceleration : isOnFloor ? FrictionFloor : FrictionAir; if (isSprinting) { target *= SprintMultiplier; accel *= SprintMultiplier; } horVelocity = horVelocity.Lerp(target, accel * (float)delta); velocity.X = horVelocity.X; velocity.Z = horVelocity.Y; if (isOnFloor) TimeSinceOnFloor = 0.0f; else TimeSinceOnFloor += (float)delta; if ((TimeSinceJumpPressed <= JumpEarlyTime) && (TimeSinceOnFloor <= JumpCoyoteTime)) { TimeSinceJumpPressed = TimeSinceOnFloor = float.PositiveInfinity; velocity.Y = JumpVelocity; } else TimeSinceJumpPressed += (float)delta; Player.Velocity = velocity; Player.MoveAndSlide(); } public override void _Process(double delta) { } }