You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
94 lines
3.5 KiB
94 lines
3.5 KiB
public partial class MovementController : Node |
|
{ |
|
[ExportGroup("Movement")] |
|
[Export] public float Acceleration { get; set; } = 4.0f; |
|
[Export] public float MaxSpeed { get; set; } = 2.1f; |
|
[Export] public float FrictionFloor { get; set; } = 12.0f; |
|
[Export] public float FrictionAir { get; set; } = 2.0f; |
|
public float Gravity { get; } = (float)ProjectSettings.GetSetting("physics/3d/default_gravity"); |
|
|
|
[ExportGroup("Jumping")] |
|
[Export] public float JumpVelocity { get; set; } = 4.0f; |
|
/// <summary> Time (in seconds) after pressing the jump button a jump may occur late. </summary> |
|
[Export] public float JumpEarlyTime { get; set; } = 0.0f; |
|
/// <summary> Time (in seconds) after leaving a jumpable surface when a jump may still occur. </summary> |
|
[Export] public float JumpCoyoteTime { get; set; } = 0.0f; |
|
|
|
public bool IsSprinting { get; private set; } |
|
/// <summary> The raw input movement vector with a maximum length of 1. </summary> |
|
[Export] public Vector2 InputVector { get; private set; } |
|
|
|
public bool IsMoving => LocalMoveVector.Length() > 0.01f; |
|
/// <summary> The actual amount the player is moving, relative to the world. Y is always 0. </summary> |
|
public Vector3 GlobalMoveVector { get; private set; } |
|
/// <summary> The actual amount the player is moving, relative to the player's viewpoint. Y is always 0. </summary> |
|
public Vector3 LocalMoveVector { get; private set; } |
|
/// <summary> </summary> |
|
public float LocalMoveAngle { get; private set; } |
|
|
|
public float TimeSinceJumpPressed { get; private set; } = float.PositiveInfinity; |
|
public float TimeSinceOnFloor { get; private set; } = float.PositiveInfinity; |
|
|
|
Player _player; |
|
public override void _Ready() |
|
=> _player = GetParent<Player>(); |
|
|
|
public override void _UnhandledInput(InputEvent @event) |
|
{ |
|
if (!_player.IsLocal) return; |
|
|
|
// TODO: Sprinting. |
|
|
|
if (@event.IsActionPressed("move_jump")) { |
|
TimeSinceJumpPressed = 0.0f; |
|
GetViewport().SetInputAsHandled(); |
|
} |
|
} |
|
|
|
public override void _PhysicsProcess(double delta) |
|
{ |
|
var velocity = _player.Velocity; |
|
velocity.Y -= Gravity * (float)delta; |
|
|
|
// Get the (normalized) movement vector from the current input. |
|
InputVector = _player.IsLocal |
|
? Input.GetVector("move_strafe_left", "move_strafe_right", "move_forward", "move_back") |
|
: Vector2.Zero; |
|
|
|
var horVelocity = velocity with { Y = 0 }; |
|
var basis = _player.Basis.Rotated(Vector3.Up, _player.Camera.CurrentYaw); |
|
var target = basis * new Vector3(InputVector.X, 0, InputVector.Y) * MaxSpeed; |
|
var isMoving = target.Dot(horVelocity) > 0.0f; |
|
|
|
var isOnFloor = _player.IsOnFloor(); |
|
var accel = isMoving ? Acceleration |
|
: isOnFloor ? FrictionFloor |
|
: FrictionAir; |
|
|
|
if (IsSprinting) { |
|
target *= 5; |
|
accel *= 5; |
|
} |
|
|
|
horVelocity = horVelocity.Lerp(target, accel * (float)delta); |
|
velocity.X = horVelocity.X; |
|
velocity.Z = horVelocity.Z; |
|
|
|
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(); |
|
|
|
// TODO: Very simplified, but works for now. |
|
GlobalMoveVector = _player.Velocity with { Y = 0 }; |
|
LocalMoveVector = _player.Basis.Inverse() * GlobalMoveVector; |
|
LocalMoveAngle = Vector3.Forward.SignedAngleTo(LocalMoveVector, Vector3.Up); |
|
} |
|
}
|
|
|