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 { [Export] public IsoPlayerStorageModule PlayerStorage { get; private 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; private bool _isStrafing; private float _accelerationPerSecond; private float _decelerationPerSecond; public int MovementSpeed => _isStrafing ? StrafeSpeed : Speed; private IStateMachine _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 machine) { _stateMachine = machine; } public override void Process(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 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); } public override void PhysicsProcess(double delta) { 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; if (_isStrafing) { // Strafing stays instant/responsive if you want that behavior v = inputDir * StrafeSpeed; } else { // 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); } // Y (gravity) float vy = Mathf.Clamp(v3.Y + Gravity * dt, -FallSpeed, FallSpeed); if (Input.IsKeyLabelPressed(Key.Z)) vy = 10; MainObject.Velocity = v.ToVector3(vy); MainObject.MoveAndSlide(); } }