using Cirno.Scripts.Components.Actors; using Cirno.Scripts.Components.Actors._3D; using Cirno.Scripts.Utils; using Godot; using GodotPlugins.Game; namespace Cirno.Scripts.Components.FSM._3DPlayer; public partial class IsoMovementModule : ModuleBase { private IsoPlayerStorageModule PlayerStorage { get; set; } [Export] private InputProvider _inputProvider; [Export] public PlayerHitboxSpriteProvider3D HitboxSpriteProvider { get; private set; } [Export] public int Speed { get; set; } = 45; [Export] public int StrafeSpeed { get; set; } = 35; [Export] public float Acceleration = 8f; [Export] public float Deceleration = 8f; [Export] public float Gravity = -9.8f; [Export] public float FallSpeed = 20f; [Export] public float TurnResistance { get; set; } = 0.8f; [Export] public float AxisReleaseFriction { get; set; } = 0.5f; private bool _isStrafing; private float _accelerationPerSecond; private float _decelerationPerSecond; public int MovementSpeed => _isStrafing ? StrafeSpeed : Speed; public override void EnterState(PlayerState state) { _accelerationPerSecond = Speed / Acceleration; _decelerationPerSecond = Speed / Deceleration; } public override void ExitState(PlayerState state) { } public override void Init(IStateMachine machine) { base.Init(machine); PlayerStorage ??= StateMachine.GetModule(); } public override void Process(double delta) { } private void HandleMovementInput(double delta) { var movementInput = _inputProvider.GetMovementInput(); _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; PlayerStorage.AimingDirection = rightStickInput; } else if (movementInput != Vector2.Zero) // Fall back to movement direction { PlayerStorage.FacingDirection = movementInput; PlayerStorage.AimingDirection = rightStickInput; } // } var rotatedMovementDirection = movementInput.Rotated(Mathf.DegToRad(-45f)); //PlayerStorage.MovementDirection = new Vector3(rotatedMovementDirection.X, 0, rotatedMovementDirection.Y); PlayerStorage.MovementDirection = rotatedMovementDirection; HitboxSpriteProvider.SetVisibility(_isStrafing); } private Vector2 InterpolateVelocityAxes( Vector2 current, Vector2 target, float accel, float decel, float turnResist, float releaseFriction, float delta) { float newX = current.X; float newY = current.Y; // --- X Axis --- if (Mathf.IsZeroApprox(target.X) && !Mathf.IsZeroApprox(current.X)) { // No input on X → bleed velocity gradually instead of snapping to zero newX = Mathf.MoveToward(current.X, 0, decel * releaseFriction * delta); } else if (Mathf.Sign(target.X) == Mathf.Sign(current.X) || Mathf.IsZeroApprox(current.X)) { float step = (Mathf.Abs(target.X) > Mathf.Abs(current.X)) ? accel : decel; newX = Mathf.MoveToward(current.X, target.X, step * delta); } else { // Opposite direction → resistance float slowStep = decel * turnResist; newX = Mathf.MoveToward(current.X, 0, slowStep * delta); if (Mathf.IsZeroApprox(newX)) newX = Mathf.MoveToward(newX, target.X, accel * delta); } // --- Y Axis --- if (Mathf.IsZeroApprox(target.Y) && !Mathf.IsZeroApprox(current.Y)) { newY = Mathf.MoveToward(current.Y, 0, decel * releaseFriction * delta); } else if (Mathf.Sign(target.Y) == Mathf.Sign(current.Y) || Mathf.IsZeroApprox(current.Y)) { float step = (Mathf.Abs(target.Y) > Mathf.Abs(current.Y)) ? accel : decel; newY = Mathf.MoveToward(current.Y, target.Y, step * delta); } else { float slowStep = decel * turnResist; newY = Mathf.MoveToward(current.Y, 0, slowStep * delta); if (Mathf.IsZeroApprox(newY)) newY = Mathf.MoveToward(newY, target.Y, accel * delta); } return new Vector2(newX, newY); } public override void PhysicsProcess(double delta) { HandleMovementInput(delta); var v3 = MainObject.Velocity; var v = v3.ToVector2(); float dt = (float)delta; Vector2 inputDir = PlayerStorage.MovementDirection; if (inputDir.Length() > 1f) inputDir = inputDir.Normalized(); if (_isStrafing) { v = inputDir * StrafeSpeed; } else { v = inputDir * Speed; // Vector2 targetVel = inputDir * Speed; // v = InterpolateVelocityAxes(v, targetVel, Acceleration, Deceleration, TurnResistance, AxisReleaseFriction, dt); } float vy = Mathf.Clamp(v3.Y + Gravity * dt, -FallSpeed, FallSpeed); if (Input.IsKeyLabelPressed(Key.Z)) vy = 10; MainObject.Velocity = v.ToVector3(vy); MainObject.MoveAndSlide(); } }