Add FSM components for player and enemy state management, including initialization and module resolution

This commit is contained in:
MaddoScientisto 2026-02-26 23:13:57 +01:00
commit b6cc5a00e8
57 changed files with 526 additions and 506 deletions

View file

@ -21,19 +21,20 @@ public partial class Active : PlayerStateBase
[Export] public float Acceleration = 8f;
[Export] public float Deceleration = 8f;
[ExportCategory("Providers")] [Export] private PlayerWeaponProvider _weaponProvider;
[Export] private PlayerAnimationProvider _animationProvider;
[Export] private PlayerCrosshairProvider _crosshairProvider;
[Export] private PlayerHitboxSpriteProvider _hitboxSpriteProvider;
// 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;
[Export] private InputProvider _inputProvider;
private InputProvider _inputProvider;
[Export] private PlayerDamageReceiver _damageReceiver;
[Export] private ActivationProvider _activationProvider;
private PlayerDamageReceiver _damageReceiver;
private ActivationProvider _activationProvider;
[Export] private InteractionController _interactionController;
private InteractionController _interaction_controller;
[Export] private PlayerStorageModule _storageModule;
private PlayerStorageModule _storageModule;
private bool _isStrafing;
@ -49,31 +50,46 @@ public partial class Active : PlayerStateBase
_hud = Hud.Instance;
_damageReceiver.Death += () => { ChangeState(PlayerState.Dead); };
// Resolve modules from the actor attached to this state machine
_weaponProvider ??= StateMachine.GetModule<PlayerWeaponProvider>();
_animationProvider ??= StateMachine.GetModule<PlayerAnimationProvider>();
_crosshairProvider ??= StateMachine.GetModule<PlayerCrosshairProvider>();
_hitboxSprite_provider ??= StateMachine.GetModule<PlayerHitboxSpriteProvider>();
_damageReceiver.HealthDecreased += (value, newValue, maxValue) =>
_inputProvider ??= StateMachine.GetModule<InputProvider>();
_damageReceiver ??= StateMachine.GetModule<PlayerDamageReceiver>();
_activationProvider ??= StateMachine.GetModule<ActivationProvider>();
_interaction_controller ??= StateMachine.GetModule<InteractionController>();
_storageModule ??= StateMachine.GetModule<PlayerStorageModule>();
if (_damageReceiver != null)
{
_animationProvider.Blink();
//_hud.UpdateHealth(value, maxValue);
};
_damageReceiver.Death += () => { ChangeState(PlayerState.Dead); };
_damageReceiver.ShieldDecreased += (value, newValue, maxValue) =>
{
_animationProvider.PlayShieldAnimation();
//_hud.UpdateShield(value, maxValue);
};
_damageReceiver.HealthDecreased += (_, _, _) =>
{
_animationProvider?.Blink();
//_hud.UpdateHealth(value, maxValue);
};
_damageReceiver.Init(StateMachine);
_damageReceiver.ShieldDecreased += (_, _, _) =>
{
_animationProvider?.PlayShieldAnimation();
//_hud.UpdateShield(value, maxValue);
};
_damageReceiver.RefillHealth();
_damageReceiver.RefillShield();
_damageReceiver.Init(StateMachine);
_activationProvider.Init(MainObject);
_damageReceiver.RefillHealth();
_damageReceiver.RefillShield();
}
//_weaponProvider = stateMachine.GetNode<PlayerWeaponProvider>("WeaponProvider");
//_animationProvider = stateMachine.GetNode<PlayerAnimationProvider>("AnimationProvider");
_activationProvider?.Init(MainObject);
_weaponProvider.Init(MainObject);
_weaponProvider?.Init(MainObject);
}
public override void EnterState()
@ -81,11 +97,11 @@ public partial class Active : PlayerStateBase
base.EnterState();
// enable sprite
// enable crosshair
_crosshairProvider.Show();
_animationProvider.ShowSprite();
_damageReceiver.Enabled = true;
_activationProvider.Enabled = true;
_interactionController.Enabled = true;
_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;
@ -94,14 +110,14 @@ public partial class Active : PlayerStateBase
public override void ExitState()
{
base.ExitState();
_animationProvider.SetAnimationSpeed(Vector2.Zero);
//_animationProvider.SetAnimation(Vector2.Zero);
_crosshairProvider.Hide();
_hitboxSpriteProvider.Hide();
_animationProvider?.SetAnimationSpeed(Vector2.Zero);
//_animation_provider.SetAnimation(Vector2.Zero);
_crosshairProvider?.Hide();
_hitboxSprite_provider?.Hide();
_damageReceiver.Enabled = false;
_activationProvider.Enabled = false;
_interactionController.Enabled = false;
if (_damageReceiver != null) _damageReceiver.Enabled = false;
if (_activationProvider != null) _activationProvider.Enabled = false;
if (_interaction_controller != null) _interaction_controller.Enabled = false;
}
private float _accelerationPerSecond;
@ -147,7 +163,7 @@ public partial class Active : PlayerStateBase
_isStrafing = _inputProvider.GetStrafePressed();
// Toggle visibility of the hitbox sprite based on strafing
_hitboxSpriteProvider.SetVisibility(_isStrafing);
_hitboxSprite_provider?.SetVisibility(_isStrafing);
var rightStickInput = _inputProvider.GetAimInput().Normalized();
@ -164,13 +180,13 @@ public partial class Active : PlayerStateBase
}
// }
_animationProvider.SetAnimationSpeed(MainObject.Velocity);
_animationProvider.SetAnimation(FacingDirection);
_animationProvider?.SetAnimationSpeed(MainObject.Velocity);
_animationProvider?.SetAnimation(FacingDirection);
HandleWeaponSwitch();
_weaponProvider.Update(delta);
_weaponProvider?.Update(delta);
//_crosshairProvider.UpdatePosition(FacingDirection);
//_crosshair_provider.UpdatePosition(FacingDirection);
HandleShoot();
@ -200,28 +216,28 @@ public partial class Active : PlayerStateBase
{
if (_inputProvider.GetReloadJustPressed())
{
_weaponProvider.Reload();
_weaponProvider?.Reload();
return;
}
if (!_inputProvider.GetShootPressed()) return;
_weaponProvider.Shoot(this.FacingDirection);
_weaponProvider?.Shoot(this.FacingDirection);
}
private void HandleInteraction()
{
_activationProvider.HandleInteraction();
_activationProvider?.HandleInteraction();
}
private void HandleWeaponSwitch()
{
if (_inputProvider.GetWeaponNextJustPressed())
{
_weaponProvider.NextWeapon();
_weaponProvider?.NextWeapon();
}
else if (_inputProvider.GetWeaponPreviousJustPressed())
{
_weaponProvider.PreviousWeapon();
_weaponProvider?.PreviousWeapon();
}
}
}

View file

@ -6,11 +6,13 @@ public partial class Drowning : PlayerStateBase
{
public override PlayerState StateId => PlayerState.Drowning;
[Export]
private PlayerAnimationProvider _animationProvider;
public override void EnterState()
{
_animationProvider ??= StateMachine.GetModule<PlayerAnimationProvider>();
if (_animationProvider is null) return;
_animationProvider.PlayDrowningAnimation();
// Wait for animation to be over and switch to death
@ -19,6 +21,7 @@ public partial class Drowning : PlayerStateBase
private void AnimationProviderOnOnAnimationEnded(StringName animationName)
{
if (_animationProvider is null) return;
if (animationName != _animationProvider.DrowningAnimationName) return;
_animationProvider.OnAnimationEnded -= AnimationProviderOnOnAnimationEnded;

View file

@ -1,5 +1,3 @@
using System;
using System.Threading.Tasks;
using Godot;
namespace Cirno.Scripts.Components.FSM.Player;
@ -8,16 +6,27 @@ public partial class Init : PlayerStateBase
{
public override PlayerState StateId => PlayerState.Init;
[Export]
private PlayerAnimationProvider _animationProvider;
[Export] private PlayerStorageModule _storageModule;
private PlayerStorageModule _storageModule;
public override void EnterState()
{
_storageModule.FacingDirection = ((PlayerStateMachine)StateMachine).StartingDirection;
_animationProvider.PlayUnteleportAnimation();
_ = AutoSwitchToStart();
// Resolve modules lazily to avoid method/class name conflicts with Init
_animationProvider ??= StateMachine.GetModule<PlayerAnimationProvider>();
_storageModule ??= StateMachine.GetModule<PlayerStorageModule>();
if (_storageModule != null)
_storageModule.FacingDirection = ((PlayerStateMachine)StateMachine).StartingDirection;
if (_animationProvider != null)
{
_animationProvider.PlayUnteleportAnimation();
// If you need to wait for animation end, subscribe here
}
var timer = GetTree().CreateTimer(0.5f);
timer.Timeout += () => StateMachine.SetState(PlayerState.Active);
}
public override void ExitState()
@ -34,10 +43,4 @@ public partial class Init : PlayerStateBase
{
}
private async Task AutoSwitchToStart()
{
await Task.Delay(500);
StateMachine.SetState(PlayerState.Active);
}
}

View file

@ -1,5 +1,4 @@
using System;
using Cirno.Scripts.Components.Actors;
using Cirno.Scripts.Components.Actors;
using Cirno.Scripts.Resources;
using Godot;
@ -13,7 +12,7 @@ public partial class PlayerFSMItemUseModule : ModuleBase<PlayerState, CharacterB
[Export]
public ActorResourceProvider Shield { get; set; }
[Export] private PlayerStorageModule _storageModule;
private PlayerStorageModule _storageModule;
public Vector2 FacingDirection
{
@ -21,7 +20,7 @@ public partial class PlayerFSMItemUseModule : ModuleBase<PlayerState, CharacterB
private set => _storageModule.FacingDirection = value;
}
public bool Enabled { get; set; } = false;
public bool Enabled { get; set; }
public override void EnterState(PlayerState state)
{
@ -40,6 +39,7 @@ public partial class PlayerFSMItemUseModule : ModuleBase<PlayerState, CharacterB
{
InventoryManager.Instance.ItemUsed += this.UseItem;
_machine = machine;
_storageModule ??= StateMachine.GetModule<PlayerStorageModule>();
}
private void UseItem(LootItem item, int totalcount)
@ -48,94 +48,8 @@ public partial class PlayerFSMItemUseModule : ModuleBase<PlayerState, CharacterB
GD.Print($"Used {item.ItemName} in player");
item.ItemEffect?.Execute(this, item);
return;
// switch (item.Item)
// {
// case ItemTypes.KeycardRed:
// break;
// case ItemTypes.KeycardBlue:
// break;
// case ItemTypes.KeycardGreen:
// break;
// case ItemTypes.Ammo:
// break;
// case ItemTypes.Medkit:
// Heal(item);
// break;
// case ItemTypes.FrogBomb:
// SpawnSpiderBomb(item);
// break;
// case ItemTypes.Bomb:
// SpawnBomb(item);
// break;
// case ItemTypes.Mine:
// break;
// case ItemTypes.Battery:
// RechargeShield(item);
// break;
// case ItemTypes.Weapon:
// break;
// case ItemTypes.Power:
// break;
// case ItemTypes.Points:
// break;
// case ItemTypes.Credits:
// break;
// case ItemTypes.KeyItem:
// break;
// }
}
// private void SpawnBomb(LootItem item)
// {
// GD.Print("Spawned bomb");
// }
//
// private void Heal(LootItem item)
// {
// Health.CurrentResource += Mathf.CeilToInt(Health.MaxResource * 25 / 100);
// }
//
// private void RechargeShield(LootItem item)
// {
// Shield.CurrentResource += Mathf.CeilToInt(Health.MaxResource * 25 / 100);
// }
//
// private void SpawnSpiderBomb(LootItem item)
// {
// //var bullet = item.WeaponData.BulletData.BulletScene.Instantiate<Bullet>();
// //bullet.Initialize(item.WeaponData.BulletData.MakeBullet(this.GlobalPosition, 1,0, 0), GameManager.Instance);
//
//
// //InventoryManager.Instance.RemoveItem(item.ItemKey, 1);
// // emit projectile
// var bullet = this.CreateChildOf<Bullet>(GameManager.Instance.BulletsContainer, item.WeaponData.BulletData.BulletScene, this.GlobalPosition);
//
// var bulletData = item.WeaponData.MakeBullet(this.GlobalPosition);
//
// bullet.Initialize(bulletData, GameManager.Instance);
// bullet.SetDirection(FacingDirection);
// bullet.RotateSpriteDegrees(-90);
// //bullet.SetDirection(_facingDirection);
// bullet.Speed = item.WeaponData.BulletData.BulletSpeed;
//
// _machine.SetState(PlayerState.Controlling);
//
// //RequestMovementDisable(true);
// // set camera
// GameManager.Instance.CameraTargetObject(bullet);
// // set event destroy
// bullet.OnDestroy += () =>
// {
// GameManager.Instance.CameraTargetPlayer();
// _machine.SetState(PlayerState.Active);
// //RequestMovementDisable(false);
// };
// }
public override void Process(double delta)
{

View file

@ -6,12 +6,12 @@ public partial class Teleporting : PlayerStateBase
{
public override PlayerState StateId => PlayerState.Teleporting;
[Export]
private PlayerAnimationProvider _animationProvider;
public override void EnterState()
{
_animationProvider.PlayTeleportAnimation();
_animationProvider ??= StateMachine.GetModule<PlayerAnimationProvider>();
_animationProvider?.PlayTeleportAnimation();
}
public override void ExitState()

View file

@ -4,14 +4,13 @@ namespace Cirno.Scripts.Components.FSM.Player;
public partial class UnTeleporting : PlayerStateBase
{
public override PlayerState StateId => PlayerState.UnTeleporting
;
[Export]
public override PlayerState StateId => PlayerState.UnTeleporting;
private PlayerAnimationProvider _animationProvider;
public override void EnterState()
{
_animationProvider.PlayUnteleportAnimation();
_animationProvider ??= StateMachine.GetModule<PlayerAnimationProvider>();
_animationProvider?.PlayUnteleportAnimation();
}
public override void ExitState()