using System; using Cirno.Scripts.Components.Actors; using Cirno.Scripts.Utils; using Godot; namespace Cirno.Scripts.Components.FSM.Player; public partial class Active : PlayerStateBase { public override PlayerState StateId => PlayerState.Active; private Vector2 _movementDirection { get; set; } public Vector2 FacingDirection { get => _storageModule.FacingDirection; private set => _storageModule.FacingDirection = value; } [Export] public int Speed { get; set; } = 45; [Export] public int StrafeSpeed { get; set; } = 35; [Export] public float Acceleration = 8f; [Export] public float Deceleration = 8f; // Providers previously exported on the state — resolve them from the actor via the state machine private PlayerWeaponProvider _weaponProvider; private PlayerAnimationProvider _animationProvider; private PlayerCrosshairProvider _crosshairProvider; private PlayerHitboxSpriteProvider _hitboxSprite_provider; private InputProvider _inputProvider; private PlayerDamageReceiver _damageReceiver; private ActivationProvider _activationProvider; private InteractionController _interaction_controller; private PlayerStorageModule _storageModule; private bool _isStrafing; public int MovementSpeed => _isStrafing ? StrafeSpeed : Speed; private CharacterBody2D _player; private Hud _hud; public override void Init(IStateMachine machine) { base.Init(machine); _hud = Hud.Instance; // Resolve modules from the actor attached to this state machine _weaponProvider ??= StateMachine.GetModule(); _animationProvider ??= StateMachine.GetModule(); _crosshairProvider ??= StateMachine.GetModule(); _hitboxSprite_provider ??= StateMachine.GetModule(); _inputProvider ??= StateMachine.GetModule(); _damageReceiver ??= StateMachine.GetModule(); _activationProvider ??= StateMachine.GetModule(); _interaction_controller ??= StateMachine.GetModule(); _storageModule ??= StateMachine.GetModule(); if (_damageReceiver != null) { _damageReceiver.Death += () => { ChangeState(PlayerState.Dead); }; _damageReceiver.HealthDecreased += (_, _, _) => { _animationProvider?.Blink(); //_hud.UpdateHealth(value, maxValue); }; _damageReceiver.ShieldDecreased += (_, _, _) => { _animationProvider?.PlayShieldAnimation(); //_hud.UpdateShield(value, maxValue); }; _damageReceiver.Init(StateMachine); _damageReceiver.RefillHealth(); _damageReceiver.RefillShield(); } _activationProvider?.Init(MainObject); _weaponProvider?.Init(MainObject); } public override void EnterState() { base.EnterState(); // enable sprite // enable crosshair _crosshairProvider?.Show(); _animationProvider?.ShowSprite(); if (_damageReceiver != null) _damageReceiver.Enabled = true; if (_activationProvider != null) _activationProvider.Enabled = true; if (_interaction_controller != null) _interaction_controller.Enabled = true; _accelerationPerSecond = Speed / Acceleration; _decelerationPerSecond = Speed / Deceleration; } public override void ExitState() { base.ExitState(); _animationProvider?.SetAnimationSpeed(Vector2.Zero); //_animation_provider.SetAnimation(Vector2.Zero); _crosshairProvider?.Hide(); _hitboxSprite_provider?.Hide(); if (_damageReceiver != null) _damageReceiver.Enabled = false; if (_activationProvider != null) _activationProvider.Enabled = false; if (_interaction_controller != null) _interaction_controller.Enabled = false; } private float _accelerationPerSecond; private float _decelerationPerSecond; public override void PhysicsProcessState(double delta) { // Reset at start of frame //MainObject.Velocity = Vector2.Zero; // Process modules base.PhysicsProcessState(delta); if (_isStrafing) { // Instant movement at strafe speed MainObject.Velocity = _movementDirection * StrafeSpeed; } else { Vector2 targetVelocity = _movementDirection * Speed; if (_movementDirection != Vector2.Zero) { MainObject.Velocity = MainObject.Velocity.MoveToward(targetVelocity, Acceleration * (float)delta); } else { MainObject.Velocity = MainObject.Velocity.MoveToward(Vector2.Zero, Deceleration * (float)delta); } } //MainObject.Velocity += _movementDirection * MovementSpeed; MainObject.MoveAndSlide(); } public override void ProcessState(double delta) { base.ProcessState(delta); _movementDirection = _inputProvider.GetMovementInput().Normalized(); _isStrafing = _inputProvider.GetStrafePressed(); // Toggle visibility of the hitbox sprite based on strafing _hitboxSprite_provider?.SetVisibility(_isStrafing); var rightStickInput = _inputProvider.GetAimInput().Normalized(); // Update Facing Direction // if (!_isStrafing) // { if (rightStickInput.Length() > 0.1f) // If the right stick is moved { FacingDirection = rightStickInput; } else if (_movementDirection != Vector2.Zero) // Fall back to movement direction { FacingDirection = _movementDirection; } // } _animationProvider?.SetAnimationSpeed(MainObject.Velocity); _animationProvider?.SetAnimation(FacingDirection); HandleWeaponSwitch(); _weaponProvider?.Update(delta); //_crosshair_provider.UpdatePosition(FacingDirection); HandleShoot(); HandleInteraction(); // FindInteractable(); // _crosshair.Position = CalculateCrosshairPosition(); if (_inputProvider.GetInventoryJustPressed()) { GameStateManager.SetState(GameState.Inventory); } if (_inputProvider.GetPauseJustPressed()) { //CallDeferred(MethodName.PauseDeferred); PauseDeferred(); } } private void PauseDeferred() { GameStateManager.Instance.Pause(); } private void HandleShoot() { if (_inputProvider.GetReloadJustPressed()) { _weaponProvider?.Reload(); return; } if (!_inputProvider.GetShootPressed()) return; _weaponProvider?.Shoot(this.FacingDirection); } private void HandleInteraction() { _activationProvider?.HandleInteraction(); } private void HandleWeaponSwitch() { if (_inputProvider.GetWeaponNextJustPressed()) { _weaponProvider?.NextWeapon(); } else if (_inputProvider.GetWeaponPreviousJustPressed()) { _weaponProvider?.PreviousWeapon(); } } }