2025-06-10 16:33:43 +02:00
|
|
|
|
using Cirno.Scripts.Components.Actors;
|
2025-06-26 15:38:28 +02:00
|
|
|
|
using Cirno.Scripts.Components.Actors._3D;
|
2025-06-29 12:35:19 +02:00
|
|
|
|
using Cirno.Scripts.Utils;
|
2025-06-10 16:33:43 +02:00
|
|
|
|
using Godot;
|
2025-06-29 12:35:19 +02:00
|
|
|
|
using GodotPlugins.Game;
|
2025-06-10 16:33:43 +02:00
|
|
|
|
|
|
|
|
|
|
namespace Cirno.Scripts.Components.FSM._3DPlayer;
|
|
|
|
|
|
|
|
|
|
|
|
public partial class IsoMovementModule : ModuleBase<PlayerState, CharacterBody3D>
|
|
|
|
|
|
{
|
|
|
|
|
|
[Export] public IsoPlayerStorageModule PlayerStorage { get; private set; }
|
|
|
|
|
|
[Export] private InputProvider _inputProvider;
|
|
|
|
|
|
|
2025-06-26 15:38:28 +02:00
|
|
|
|
[Export] public PlayerHitboxSpriteProvider3D HitboxSpriteProvider { get; private set; }
|
|
|
|
|
|
|
2025-06-10 16:33:43 +02:00
|
|
|
|
[Export] public int Speed { get; set; } = 45;
|
|
|
|
|
|
[Export] public int StrafeSpeed { get; set; } = 35;
|
|
|
|
|
|
[Export] public float Acceleration = 8f;
|
|
|
|
|
|
[Export] public float Deceleration = 8f;
|
2025-06-11 15:28:26 +02:00
|
|
|
|
[Export] public float Gravity = -9.8f;
|
|
|
|
|
|
[Export] public float FallSpeed = 20f;
|
2025-06-10 16:33:43 +02:00
|
|
|
|
|
|
|
|
|
|
private bool _isStrafing;
|
|
|
|
|
|
private float _accelerationPerSecond;
|
|
|
|
|
|
private float _decelerationPerSecond;
|
|
|
|
|
|
|
|
|
|
|
|
public int MovementSpeed => _isStrafing ? StrafeSpeed : Speed;
|
|
|
|
|
|
|
|
|
|
|
|
private IStateMachine<PlayerState, CharacterBody3D> _stateMachine;
|
|
|
|
|
|
private CharacterBody3D MainObject => _stateMachine.MainObject;
|
|
|
|
|
|
|
|
|
|
|
|
public override void EnterState(PlayerState state)
|
|
|
|
|
|
{
|
|
|
|
|
|
_accelerationPerSecond = Speed / Acceleration;
|
|
|
|
|
|
_decelerationPerSecond = Speed / Deceleration;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void ExitState(PlayerState state)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
|
|
|
|
|
|
{
|
|
|
|
|
|
_stateMachine = machine;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void Process(double delta)
|
|
|
|
|
|
{
|
2025-06-11 15:28:26 +02:00
|
|
|
|
var movementInput = _inputProvider.GetMovementInput();
|
2025-06-10 16:33:43 +02:00
|
|
|
|
|
2025-06-11 15:28:26 +02:00
|
|
|
|
_isStrafing = _inputProvider.GetStrafePressed();
|
|
|
|
|
|
var rightStickInput = _inputProvider.GetAimInput().Normalized();
|
|
|
|
|
|
|
|
|
|
|
|
// Update Facing Direction
|
|
|
|
|
|
// if (!_isStrafing)
|
|
|
|
|
|
// {
|
|
|
|
|
|
if (rightStickInput.Length() > 0.1f) // If the right stick is moved
|
|
|
|
|
|
{
|
|
|
|
|
|
PlayerStorage.FacingDirection = rightStickInput;
|
2025-06-18 18:09:30 +02:00
|
|
|
|
PlayerStorage.AimingDirection = rightStickInput;
|
2025-06-11 15:28:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
else if (movementInput != Vector2.Zero) // Fall back to movement direction
|
|
|
|
|
|
{
|
|
|
|
|
|
PlayerStorage.FacingDirection = movementInput;
|
2025-06-18 18:09:30 +02:00
|
|
|
|
PlayerStorage.AimingDirection = rightStickInput;
|
2025-06-11 15:28:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
var rotatedMovementDirection = movementInput.Rotated(Mathf.DegToRad(-45f));
|
|
|
|
|
|
|
2025-06-29 12:35:19 +02:00
|
|
|
|
//PlayerStorage.MovementDirection = new Vector3(rotatedMovementDirection.X, 0, rotatedMovementDirection.Y);
|
|
|
|
|
|
PlayerStorage.MovementDirection = rotatedMovementDirection;
|
2025-06-26 15:38:28 +02:00
|
|
|
|
|
|
|
|
|
|
HitboxSpriteProvider.SetVisibility(_isStrafing);
|
2025-06-10 16:33:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-14 17:50:11 +02:00
|
|
|
|
private Vector2 InterpolateVelocityAxes(
|
|
|
|
|
|
Vector2 current, Vector2 target, float accel, float decel, float delta)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Accelerate when we're increasing magnitude toward target on that axis; otherwise decelerate.
|
|
|
|
|
|
float stepX = (Mathf.Abs(target.X) > Mathf.Abs(current.X)) ? accel : decel;
|
|
|
|
|
|
float stepY = (Mathf.Abs(target.Y) > Mathf.Abs(current.Y)) ? accel : decel;
|
|
|
|
|
|
|
|
|
|
|
|
float newX = Mathf.MoveToward(current.X, target.X, stepX * delta);
|
|
|
|
|
|
float newY = Mathf.MoveToward(current.Y, target.Y, stepY * delta);
|
|
|
|
|
|
return new Vector2(newX, newY);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-10 16:33:43 +02:00
|
|
|
|
public override void PhysicsProcess(double delta)
|
|
|
|
|
|
{
|
2025-08-14 17:50:11 +02:00
|
|
|
|
var v3 = MainObject.Velocity;
|
|
|
|
|
|
Vector2 v = v3.ToVector2();
|
|
|
|
|
|
float dt = (float)delta;
|
|
|
|
|
|
|
|
|
|
|
|
// Read desired input direction for this physics tick
|
|
|
|
|
|
Vector2 inputDir = PlayerStorage.MovementDirection;
|
|
|
|
|
|
|
|
|
|
|
|
// Clamp diagonal magnitude so diagonals aren't faster (helps remove jittery speed jumps)
|
|
|
|
|
|
float len = inputDir.Length();
|
|
|
|
|
|
if (len > 1f)
|
|
|
|
|
|
inputDir /= len;
|
|
|
|
|
|
|
2025-06-10 16:33:43 +02:00
|
|
|
|
if (_isStrafing)
|
|
|
|
|
|
{
|
2025-08-14 17:50:11 +02:00
|
|
|
|
// Strafing stays instant/responsive if you want that behavior
|
|
|
|
|
|
v = inputDir * StrafeSpeed;
|
2025-06-10 16:33:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-08-14 17:50:11 +02:00
|
|
|
|
// Build a target *velocity* (not just direction)
|
|
|
|
|
|
Vector2 targetVel = inputDir * Speed;
|
|
|
|
|
|
|
|
|
|
|
|
// Per-axis interpolation prevents direction snaps when keys change
|
|
|
|
|
|
v = InterpolateVelocityAxes(v, targetVel, Acceleration, Deceleration, dt);
|
2025-06-10 16:33:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-14 17:50:11 +02:00
|
|
|
|
// Y (gravity)
|
|
|
|
|
|
float vy = Mathf.Clamp(v3.Y + Gravity * dt, -FallSpeed, FallSpeed);
|
|
|
|
|
|
if (Input.IsKeyLabelPressed(Key.Z)) vy = 10;
|
2025-06-11 15:28:26 +02:00
|
|
|
|
|
2025-08-14 17:50:11 +02:00
|
|
|
|
MainObject.Velocity = v.ToVector3(vy);
|
2025-06-10 16:33:43 +02:00
|
|
|
|
MainObject.MoveAndSlide();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|