Movement refactor

This commit is contained in:
2025-08-30 23:06:12 +02:00
committed by GitHub
parent d786ef4c22
commit 88c7a0a055
41 changed files with 656 additions and 122 deletions

View File

@@ -0,0 +1,28 @@
using Godot;
namespace Mr.BrickAdventures.scripts.components;
[GlobalClass]
public partial class GravityAbility : MovementAbility
{
public float AscendGravity { get; set; }
public float DescendGravity { get; set; }
private float _gravity;
public override void Initialize(PlayerController controller)
{
base.Initialize(controller);
_gravity = (float)ProjectSettings.GetSetting("physics/2d/default_gravity");
}
public override Vector2 ProcessMovement(Vector2 velocity, double delta)
{
if (_body.IsOnFloor()) return velocity;
var gravityToApply = velocity.Y < 0 ? AscendGravity : DescendGravity;
velocity.Y += gravityToApply * (float)delta;
return velocity;
}
}

View File

@@ -0,0 +1 @@
uid://chgw53qwt7rt8

View File

@@ -0,0 +1,26 @@
using Godot;
namespace Mr.BrickAdventures.scripts.components;
[GlobalClass]
public partial class GroundMovementAbility : MovementAbility
{
[Export] public float MaxSpeed { get; set; } = 300.0f;
[Export] public float Acceleration { get; set; } = 2000.0f;
[Export] public float Friction { get; set; } = 1500.0f;
public override Vector2 ProcessMovement(Vector2 velocity, double delta)
{
if (_input == null) return Vector2.Zero;
var direction = _input.MoveDirection.X;
var targetSpeed = direction * MaxSpeed;
if (direction != 0)
velocity.X = Mathf.MoveToward(velocity.X, targetSpeed, Acceleration * (float)delta);
else
velocity.X = Mathf.MoveToward(velocity.X, 0, Friction * (float)delta);
return velocity;
}
}

View File

@@ -0,0 +1 @@
uid://bf4yclropol43

View File

@@ -0,0 +1,41 @@
using Godot;
namespace Mr.BrickAdventures.scripts.components;
[GlobalClass]
public partial class JumpAbility : MovementAbility
{
[Export] public float JumpVelocity { get; set; } = -400.0f;
[Export] public int CoyoteFrames { get; set; } = 6;
private Timer _coyoteTimer;
private bool _wasOnFloor = false;
public override void Initialize(PlayerController controller)
{
base.Initialize(controller);
_coyoteTimer = new Timer { OneShot = true, WaitTime = CoyoteFrames / (float)Engine.GetPhysicsTicksPerSecond() };
AddChild(_coyoteTimer);
}
public override Vector2 ProcessMovement(Vector2 velocity, double delta)
{
if (!_body.IsOnFloor() && _wasOnFloor)
{
_coyoteTimer.Start();
}
if (_input.JumpHeld)
{
if (_body.IsOnFloor() || !_coyoteTimer.IsStopped())
{
velocity.Y = JumpVelocity;
_controller.EmitSignal(PlayerController.SignalName.JumpInitiated);
_coyoteTimer.Stop();
}
}
_wasOnFloor = _body.IsOnFloor();
return velocity;
}
}

View File

@@ -0,0 +1 @@
uid://d0bb48upefu20

View File

@@ -0,0 +1,38 @@
using Godot;
namespace Mr.BrickAdventures.scripts.components;
[GlobalClass]
public abstract partial class MovementAbility : Node
{
protected PlayerController _controller;
protected CharacterBody2D _body;
protected PlayerInputHandler _input;
public virtual void Initialize(PlayerController controller)
{
Name = $"{GetType().Name}";
_controller = controller;
if (_controller == null)
{
GD.PushError($"Movement ability '{Name}' must be a child of a PlayerController.");
SetProcess(false);
SetPhysicsProcess(false);
return;
}
_body = _controller;
_input = _controller.GetNode<PlayerInputHandler>("PlayerInputHandler");
if (_input == null)
{
GD.PushError($"PlayerController '{_controller.Name}' must have a PlayerInputHandler child.");
SetProcess(false);
SetPhysicsProcess(false);
}
_body.Velocity = Vector2.Zero;
}
public abstract Vector2 ProcessMovement(Vector2 currentVelocity, double delta);
}

View File

@@ -0,0 +1 @@
uid://cmlwisjpoxk7f

View File

@@ -0,0 +1,15 @@
using Godot;
namespace Mr.BrickAdventures.scripts.components;
[GlobalClass]
public partial class OneWayPlatformAbility : MovementAbility
{
public override Vector2 ProcessMovement(Vector2 velocity, double delta)
{
if (_input.DownHeld && _controller != null)
_controller.Position += new Vector2(0, 1);
return velocity;
}
}

View File

@@ -0,0 +1 @@
uid://ck6kmnbwhsttt

View File

@@ -0,0 +1,28 @@
using Godot;
namespace Mr.BrickAdventures.scripts.components;
[GlobalClass]
public partial class PlayerInputHandler : Node
{
public Vector2 MoveDirection { get; private set; } = Vector2.Zero;
public bool JumpPressed { get; private set; }
public bool JumpReleased { get; private set; }
public bool JumpHeld { get; private set; }
public bool DownPressed { get; private set; }
public bool DownReleased { get; private set; }
public bool DownHeld { get; private set; }
public override void _Process(double delta)
{
MoveDirection = Input.GetVector("left", "right", "up", "down");
JumpPressed = Input.IsActionJustPressed("jump");
JumpReleased = Input.IsActionJustReleased("jump");
JumpHeld = Input.IsActionPressed("jump");
DownPressed = Input.IsActionJustPressed("down");
DownReleased = Input.IsActionJustReleased("down");
DownHeld = Input.IsActionPressed("down");
}
}

View File

@@ -0,0 +1 @@
uid://dssa2taiwktis

View File

@@ -0,0 +1,29 @@
using Godot;
namespace Mr.BrickAdventures.scripts.components;
[GlobalClass]
public partial class SpaceshipMovementAbility : MovementAbility
{
[Export] public float MaxSpeed { get; set; } = 300f;
[Export] public float Acceleration { get; set; } = 2000f;
[Export] public float Friction { get; set; } = 1700f;
public override Vector2 ProcessMovement(Vector2 currentVelocity, double delta)
{
if (_input == null) return Vector2.Zero;
var inputVector = _input.MoveDirection;
if (inputVector != Vector2.Zero)
{
currentVelocity = currentVelocity.MoveToward(inputVector * MaxSpeed, Acceleration * (float)delta);
}
else
{
currentVelocity = currentVelocity.MoveToward(Vector2.Zero, Friction * (float)delta);
}
return currentVelocity;
}
}

View File

@@ -0,0 +1 @@
uid://drgwa5q5k2tbm

View File

@@ -0,0 +1,68 @@
using Godot;
namespace Mr.BrickAdventures.scripts.components;
[GlobalClass]
public partial class VariableJumpAbility : MovementAbility
{
[ExportGroup("Jump Design")]
[Export] public float JumpHeight { get; set; } = 100f;
[Export] public float JumpTimeToPeak { get; set; } = 0.5f;
[Export] public float JumpTimeToDescent { get; set; } = 0.4f;
[ExportGroup("Jump Feel")]
// How much to reduce upward velocity when the jump button is released mid-air.
[Export(PropertyHint.Range, "0.0, 1.0, 0.05")] public float JumpCutMultiplier { get; set; } = 0.5f;
[Export(PropertyHint.Range, "0,10,1")] public int CoyoteFrames { get; set; } = 6;
private float _jumpVelocity;
private bool _wasOnFloor = false;
private bool _hasJumpedInAir = false;
private Timer _coyoteTimer;
public float AscendGravity { get; private set; }
public float DescendGravity { get; private set; }
public override void Initialize(PlayerController controller)
{
base.Initialize(controller);
_jumpVelocity = (2.0f * JumpHeight) / JumpTimeToPeak * -1.0f;
AscendGravity = (-2.0f * JumpHeight) / (JumpTimeToPeak * JumpTimeToPeak) * -1.0f;
DescendGravity = (-2.0f * JumpHeight) / (JumpTimeToDescent * JumpTimeToDescent) * -1.0f;
_coyoteTimer = new Timer { OneShot = true, WaitTime = CoyoteFrames / (float)Engine.GetPhysicsTicksPerSecond() };
AddChild(_coyoteTimer);
}
public override Vector2 ProcessMovement(Vector2 velocity, double delta)
{
var isGrounded = _body.IsOnFloor();
if (!isGrounded && _wasOnFloor) _coyoteTimer.Start();
if (isGrounded) _hasJumpedInAir = false;
if (_input.JumpHeld && !_hasJumpedInAir)
{
if (isGrounded || !_coyoteTimer.IsStopped())
{
velocity.Y = _jumpVelocity;
_controller.EmitSignal(PlayerController.SignalName.JumpInitiated);
_coyoteTimer.Stop();
_hasJumpedInAir = true;
}
}
if (_input.JumpReleased)
{
if (velocity.Y < 0.0f)
{
velocity.Y *= JumpCutMultiplier;
}
}
_wasOnFloor = isGrounded;
return velocity;
}
}

View File

@@ -0,0 +1 @@
uid://ccksp2e76s7sr

View File

@@ -0,0 +1,37 @@
using Godot;
namespace Mr.BrickAdventures.scripts.components;
[GlobalClass]
public partial class WallJumpAbility : MovementAbility
{
[ExportGroup("Wall Jump Design")]
[Export] public Vector2 WallJumpVelocity { get; set; } = new(500.0f, -350.0f);
[ExportGroup("Wall Slide Feel")]
[Export(PropertyHint.Range, "0.0, 1.0, 0.05")] public float WallSlideGravityMultiplier { get; set; } = 0.7f;
[Export] public float MaxWallSlideSpeed { get; set; } = 150.0f;
public override Vector2 ProcessMovement(Vector2 velocity, double delta)
{
var isOnWall = _body.IsOnWall();
if (isOnWall && !_body.IsOnFloor() && velocity.Y > 0f)
{
var gravity = (float)ProjectSettings.GetSetting("physics/2d/default_gravity");
var newYVelocity = velocity.Y + gravity * WallSlideGravityMultiplier * (float)delta;
velocity.Y = Mathf.Min(newYVelocity, MaxWallSlideSpeed);
}
if (isOnWall && _input.JumpHeld)
{
var wallNormal = _body.GetWallNormal();
_controller.EmitSignal(PlayerController.SignalName.JumpInitiated);
velocity = new Vector2(wallNormal.X * WallJumpVelocity.X, WallJumpVelocity.Y);
}
return velocity;
}
}

View File

@@ -0,0 +1 @@
uid://6foetukqmyoe