refactor: movement system - MovementPreset, decouple abilities, fix timing

This commit is contained in:
2026-03-19 02:45:26 +01:00
parent adaeb35fdd
commit 814d9736d0
11 changed files with 58 additions and 95 deletions

View File

@@ -1,6 +1,7 @@
using System.Linq;
using Godot;
using Mr.BrickAdventures.scripts.components;
using Mr.BrickAdventures.scripts.Resources;
namespace Mr.BrickAdventures.scripts;
@@ -8,17 +9,17 @@ namespace Mr.BrickAdventures.scripts;
public partial class PacXonLevel : Node
{
[Export] public PlayerController Player { get; set; }
[Export] public MovementPreset GridPreset { get; set; }
[Export] public PacXonGridManager GridManager { get; set; }
[Export] public Node GhostContainer { get; set; }
[Export] public Label PercentageLabel { get; set; }
private const float WinPercentage = 0.90f;
public override void _Ready()
{
var ghosts = GhostContainer.GetChildren().OfType<Node2D>().ToList();
Player.ClearMovementAbilities();
Player.SetGridMovement();
Player.ApplyPreset(GridPreset);
foreach (var ghost in ghosts)
{

View File

@@ -0,0 +1,9 @@
using Godot;
namespace Mr.BrickAdventures.scripts.Resources;
[GlobalClass]
public partial class MovementPreset : Resource
{
[Export] public PackedScene[] Abilities { get; set; } = [];
}

View File

@@ -5,26 +5,16 @@ namespace Mr.BrickAdventures.scripts.components;
[GlobalClass]
public partial class DoubleJumpAbility : MovementAbility
{
[Export] public float JumpHeight { get; set; } = 100f;
[Export] public float JumpTimeToPeak { get; set; } = 0.5f;
private bool _hasDoubleJumped = false;
private float _jumpVelocity;
public override void Initialize(PlayerController controller)
{
base.Initialize(controller);
foreach (var ability in _controller.GetActiveAbilities())
{
if (ability is VariableJumpAbility jumpAbility)
{
_jumpVelocity = (2.0f * jumpAbility.JumpHeight) / jumpAbility.JumpTimeToPeak * -1.0f;
break;
}
}
if (_jumpVelocity == 0)
{
_jumpVelocity = -400.0f;
}
_jumpVelocity = (2.0f * JumpHeight) / JumpTimeToPeak * -1.0f;
}
public override Vector2 ProcessMovement(Vector2 velocity, double delta)

View File

@@ -5,8 +5,8 @@ namespace Mr.BrickAdventures.scripts.components;
[GlobalClass]
public partial class GravityAbility : MovementAbility
{
public float AscendGravity { get; set; }
public float DescendGravity { get; set; }
[Export] public float AscendGravity { get; set; } = 980f;
[Export] public float DescendGravity { get; set; } = 1960f;
private float _gravity;

View File

@@ -26,8 +26,6 @@ public partial class GridMovementAbility : MovementAbility
public override Vector2 ProcessMovement(Vector2 currentVelocity, double delta)
{
GD.Print($"Player position: {_body.Position}, {_body.GlobalPosition}");
var inputDirection = _input.MoveDirection;
var newDirection = Vector2.Zero;

View File

@@ -30,8 +30,6 @@ public abstract partial class MovementAbility : Node
SetProcess(false);
SetPhysicsProcess(false);
}
_body.Velocity = Vector2.Zero;
}
public abstract Vector2 ProcessMovement(Vector2 currentVelocity, double delta);

View File

@@ -13,7 +13,7 @@ public partial class PlayerInputHandler : Node
public bool DownReleased { get; private set; }
public bool DownHeld { get; private set; }
public override void _Process(double delta)
public override void _PhysicsProcess(double delta)
{
MoveDirection = Input.GetVector("left", "right", "up", "down");

View File

@@ -7,19 +7,26 @@ 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;
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)
{
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;
var newYVelocity = velocity.Y + _gravity * WallSlideGravityMultiplier * (float)delta;
velocity.Y = Mathf.Min(newYVelocity, MaxWallSlideSpeed);
}

View File

@@ -1,8 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Godot;
using Mr.BrickAdventures.Autoloads;
using Mr.BrickAdventures.scripts.Resources;
namespace Mr.BrickAdventures.scripts.components;
@@ -10,15 +9,7 @@ namespace Mr.BrickAdventures.scripts.components;
public partial class PlayerController : CharacterBody2D
{
[Export] private Node MovementAbilitiesContainer { get; set; }
[ExportGroup("Movement Ability Scenes")]
[Export] public PackedScene GroundMovementScene { get; set; }
[Export] public PackedScene JumpMovementScene { get; set; }
[Export] public PackedScene GravityScene { get; set; }
[Export] public PackedScene OneWayPlatformScene { get; set; }
[Export] public PackedScene SpaceshipMovementScene { get; set; }
[Export] public PackedScene WallJumpScene { get; set; }
[Export] public PackedScene GridMovementScene { get; set; }
[Export] public MovementPreset DefaultPreset { get; set; }
[Signal] public delegate void JumpInitiatedEventHandler();
[Signal] public delegate void MovementAbilitiesChangedEventHandler();
@@ -48,16 +39,10 @@ public partial class PlayerController : CharacterBody2D
}
_inputHandler = GetNode<PlayerInputHandler>("PlayerInputHandler");
foreach (var child in MovementAbilitiesContainer.GetChildren())
{
if (child is MovementAbility ability)
{
ability.Initialize(this);
_abilities.Add(ability);
}
}
_ = ConnectJumpAndGravityAbilities();
if (DefaultPreset != null)
ApplyPreset(DefaultPreset);
EmitSignalMovementAbilitiesChanged();
EventBus.EmitPlayerSpawned(this);
}
@@ -81,6 +66,19 @@ public partial class PlayerController : CharacterBody2D
MoveAndSlide();
}
public void ApplyPreset(MovementPreset preset)
{
if (preset == null) return;
ClearMovementAbilities();
Velocity = Vector2.Zero;
foreach (var scene in preset.Abilities)
{
if (scene != null)
AddAbility(scene.Instantiate<MovementAbility>());
}
EmitSignalMovementAbilitiesChanged();
}
public void AddAbility(MovementAbility ability)
{
MovementAbilitiesContainer.AddChild(ability);
@@ -110,46 +108,4 @@ public partial class PlayerController : CharacterBody2D
}
}
}
public void SetPlatformMovement()
{
ClearMovementAbilities();
if (GroundMovementScene != null) AddAbility(GroundMovementScene.Instantiate<MovementAbility>());
if (JumpMovementScene != null) AddAbility(JumpMovementScene.Instantiate<MovementAbility>());
if (GravityScene != null) AddAbility(GravityScene.Instantiate<MovementAbility>());
if (OneWayPlatformScene != null) AddAbility(OneWayPlatformScene.Instantiate<MovementAbility>());
_ = ConnectJumpAndGravityAbilities();
EmitSignalMovementAbilitiesChanged();
}
public void SetSpaceshipMovement()
{
ClearMovementAbilities();
if (SpaceshipMovementScene != null) AddAbility(SpaceshipMovementScene.Instantiate<MovementAbility>());
EmitSignalMovementAbilitiesChanged();
}
public void SetGridMovement()
{
ClearMovementAbilities();
if (GridMovementScene != null) AddAbility(GridMovementScene.Instantiate<MovementAbility>());
EmitSignalMovementAbilitiesChanged();
}
private async Task ConnectJumpAndGravityAbilities()
{
await ToSignal(GetTree(), SceneTree.SignalName.ProcessFrame);
var jumpAbility = _abilities.OfType<VariableJumpAbility>().FirstOrDefault();
var gravityAbility = _abilities.OfType<GravityAbility>().FirstOrDefault();
if (jumpAbility != null && gravityAbility != null)
{
gravityAbility.AscendGravity = jumpAbility.AscendGravity;
gravityAbility.DescendGravity = jumpAbility.DescendGravity;
}
}
}
}

View File

@@ -1,10 +1,12 @@
using Godot;
using Mr.BrickAdventures.scripts.Resources;
namespace Mr.BrickAdventures.scripts.components;
[GlobalClass]
public partial class SpaceshipEnterComponent : Area2D
{
[Export] public MovementPreset Preset { get; set; }
[Signal] public delegate void SpaceshipEnteredEventHandler();
public override void _Ready()
@@ -15,7 +17,7 @@ public partial class SpaceshipEnterComponent : Area2D
private void OnBodyEntered(Node2D body)
{
if (body is not PlayerController player) return;
player.SetSpaceshipMovement();
player.ApplyPreset(Preset);
EmitSignalSpaceshipEntered();
QueueFree();
}

View File

@@ -1,12 +1,14 @@
using Godot;
using Mr.BrickAdventures.scripts.Resources;
namespace Mr.BrickAdventures.scripts.components;
[GlobalClass]
public partial class SpaceshipExitComponent : Area2D
{
[Export] public MovementPreset Preset { get; set; }
[Signal] public delegate void SpaceshipExitEventHandler();
public override void _Ready()
{
BodyEntered += OnBodyEntered;
@@ -16,6 +18,6 @@ public partial class SpaceshipExitComponent : Area2D
{
if (body is not PlayerController player) return;
EmitSignalSpaceshipExit();
player.SetPlatformMovement();
player.ApplyPreset(Preset);
}
}