Migrated player state machine

This commit is contained in:
Marco 2025-03-05 10:55:14 +01:00
commit 9c3f22760b
19 changed files with 108 additions and 69 deletions

View file

@ -1,8 +1,9 @@
using Godot; using Godot;
using System; using System;
using Cirno.Scripts.Components.Actors; using Cirno.Scripts.Components.Actors;
using Cirno.Scripts.Components.FSM;
public partial class InteractionController : Area2D public partial class InteractionController : PlayerArea2DModule
{ {
[Export] public ActorResourceProvider Health { get; private set; } [Export] public ActorResourceProvider Health { get; private set; }
[Export] public ActorResourceProvider Shield { get; private set; } [Export] public ActorResourceProvider Shield { get; private set; }
@ -35,4 +36,19 @@ public partial class InteractionController : Area2D
public override void _Process(double delta) public override void _Process(double delta)
{ {
} }
public override void Init(IStateMachine<PlayerState, CharacterBody2D> machine)
{
}
public override void Process(double delta)
{
}
public override void PhysicsProcess(double delta)
{
}
} }

View file

@ -11,18 +11,18 @@ public partial class LevelTeleporter : Teleporter
[Export] [Export]
public string LevelPath {get; private set;} public string LevelPath {get; private set;}
protected override async Task Teleport(PlayerStateMachine player) protected override async Task Teleport(IStateMachine<PlayerState, CharacterBody2D> player)
{ {
if (string.IsNullOrWhiteSpace(LevelPath)) return; if (string.IsNullOrWhiteSpace(LevelPath)) return;
//player.RequestMovementDisable(true); //player.RequestMovementDisable(true);
player.SetState((int)PlayerState.Cutscene); player.SetState(PlayerState.Cutscene);
await TweenPlayer(player); await TweenPlayer(player.MainObject);
_particles.Emitting = true; _particles.Emitting = true;
//await player.Teleport(); //await player.Teleport();
player.SetState((int)PlayerState.UnTeleporting); player.SetState(PlayerState.UnTeleporting);
await Task.Delay((int)(0.6f * 1000)); await Task.Delay((int)(0.6f * 1000));
await Task.Delay((int)(TeleportAnimationLength * 1000)); await Task.Delay((int)(TeleportAnimationLength * 1000));

View file

@ -37,7 +37,7 @@ public partial class PlayerMover : ChainActivable
private async Task MovePlayer() private async Task MovePlayer()
{ {
//_gameManager.Player.RequestMovementDisable(true); //_gameManager.Player.RequestMovementDisable(true);
_gameManager.Player.SetState((int)PlayerState.Cutscene); _gameManager.Player.SetState(PlayerState.Cutscene);
Tween tween = GetTree().CreateTween(); Tween tween = GetTree().CreateTween();
tween.SetEase(EaseType); tween.SetEase(EaseType);
@ -48,7 +48,7 @@ public partial class PlayerMover : ChainActivable
await ToSignal(tween, "finished"); await ToSignal(tween, "finished");
//_gameManager.Player.RequestMovementDisable(false); //_gameManager.Player.RequestMovementDisable(false);
_gameManager.Player.SetState((int)PlayerState.Cutscene); _gameManager.Player.SetState(PlayerState.Cutscene);
ActivateTargets(); ActivateTargets();
} }

View file

@ -114,9 +114,10 @@ private AudioStreamPlayer2D _teleportEndSound;
_particleTimer = 0; _particleTimer = 0;
} }
private void _on_body_entered(CharacterBody2D area) private void _on_area_entered(Area2D area)
{ {
if (area is not PlayerStateMachine player) return; if (!IsEnabled) return;
if (area is not InteractionController interactionController) return;
if (!IsPrimed) if (!IsPrimed)
{ {
@ -130,16 +131,16 @@ private AudioStreamPlayer2D _teleportEndSound;
// Call Teleport here // Call Teleport here
_ = Teleport(player); _ = Teleport(interactionController.StateMachine);
} }
protected virtual async Task Teleport(PlayerStateMachine player) protected virtual async Task Teleport(IStateMachine<PlayerState, CharacterBody2D> player)
{ {
if (Target is null) return; if (Target is null) return;
//player.RequestMovementDisable(true); //player.RequestMovementDisable(true);
player.SetState((int)PlayerState.Cutscene); player.SetState(PlayerState.Cutscene);
await TweenPlayer(player); await TweenPlayer(player.MainObject);
PlayTeleportStartSound(); PlayTeleportStartSound();
@ -147,21 +148,21 @@ private AudioStreamPlayer2D _teleportEndSound;
FireParticles(); FireParticles();
//await player.Teleport(); //await player.Teleport();
player.SetState((int)PlayerState.Teleporting); player.SetState(PlayerState.Teleporting);
await Task.Delay((int)(0.6f * 1000)); await Task.Delay((int)(0.6f * 1000));
await Task.Delay((int)(TeleportAnimationLength * 1000)); await Task.Delay((int)(TeleportAnimationLength * 1000));
Target.PrepareForReceiving(); Target.PrepareForReceiving();
player.GlobalPosition = Target.GlobalPosition + TeleportOffset; player.MainObject.GlobalPosition = Target.GlobalPosition + TeleportOffset;
Target.PlayTeleportEndSound(); Target.PlayTeleportEndSound();
//await player.UnTeleport(); //await player.UnTeleport();
player.SetState((int)PlayerState.UnTeleporting); player.SetState(PlayerState.UnTeleporting);
await Task.Delay((int)(0.6f * 1000)); await Task.Delay((int)(0.6f * 1000));
//player.RequestMovementDisable(false); //player.RequestMovementDisable(false);
player.SetState((int)PlayerState.Active); player.SetState(PlayerState.Active);
} }
public void PlayTeleportStartSound() public void PlayTeleportStartSound()
@ -174,7 +175,7 @@ private AudioStreamPlayer2D _teleportEndSound;
_teleportEndSound?.Play(); _teleportEndSound?.Play();
} }
protected async Task TweenPlayer(PlayerStateMachine player) protected async Task TweenPlayer(CharacterBody2D player)
{ {
await player.TweenGlobalPosition(GlobalPosition + new Vector2(0, -4f), TeleportAnimationLength).PlayAsync(CancellationToken.None); await player.TweenGlobalPosition(GlobalPosition + new Vector2(0, -4f), TeleportAnimationLength).PlayAsync(CancellationToken.None);

View file

@ -23,7 +23,7 @@ public partial class ActivationProvider : Area2D
[Signal] [Signal]
public delegate void InteractableAreaExitedEventHandler(Interactable interactable); public delegate void InteractableAreaExitedEventHandler(Interactable interactable);
public void Init(ActorStateMachine actor) public void Init(CharacterBody2D actor)
{ {
if (SelectorScene is not null && _selector is null) if (SelectorScene is not null && _selector is null)
{ {

View file

@ -78,7 +78,7 @@ public partial class EnemyPossessionMovement : ActorFreeMovement
{ {
GameManager.Instance.CameraTargetObject(_parent); GameManager.Instance.CameraTargetObject(_parent);
//GameManager.Instance.Player.RequestMovementDisable(true); //GameManager.Instance.Player.RequestMovementDisable(true);
GameManager.Instance.Player.SetState((int)PlayerState.Controlling); GameManager.Instance.Player.SetState(PlayerState.Controlling);
_previousAiState = _actorAi.Ai; _previousAiState = _actorAi.Ai;
_actorAi.Ai = AiState.Controlled; _actorAi.Ai = AiState.Controlled;
@ -94,7 +94,7 @@ public partial class EnemyPossessionMovement : ActorFreeMovement
GameManager.Instance.CameraTargetPlayer(); GameManager.Instance.CameraTargetPlayer();
//GameManager.Instance.Player.RequestMovementDisable(false); //GameManager.Instance.Player.RequestMovementDisable(false);
GameManager.Instance.Player.SetState((int)PlayerState.Active); GameManager.Instance.Player.SetState(PlayerState.Active);
DamageReceiver.BulletGroup = BulletOwner.Enemy; DamageReceiver.BulletGroup = BulletOwner.Enemy;

View file

@ -35,6 +35,11 @@ public abstract partial class BaseState<TKey, TType> : Node2D, IState<TKey, TTyp
} }
} }
protected void ChangeState(TKey newState)
{
_stateMachine.SetState(newState);
}
public abstract void EnterState(); public abstract void EnterState();
public abstract void ExitState(); public abstract void ExitState();

View file

@ -4,8 +4,9 @@ using Godot;
namespace Cirno.Scripts.Components.FSM.Player; namespace Cirno.Scripts.Components.FSM.Player;
public partial class Active : PlayerFSMState public partial class Active : PlayerStateBase
{ {
public override PlayerState StateId => PlayerState.Active;
private Vector2 _movementDirection { get; set; } private Vector2 _movementDirection { get; set; }
public Vector2 FacingDirection { get; private set; } = Vector2.Down; public Vector2 FacingDirection { get; private set; } = Vector2.Down;
@ -36,18 +37,16 @@ public partial class Active : PlayerFSMState
public int MovementSpeed => _isStrafing ? StrafeSpeed : Speed; public int MovementSpeed => _isStrafing ? StrafeSpeed : Speed;
private PlayerStateMachine _player; private CharacterBody2D _player;
private Hud _hud; private Hud _hud;
public override void Init(ActorStateMachine stateMachine) public override void Init(IStateMachine<PlayerState, CharacterBody2D> machine)
{ {
base.Init(stateMachine); base.Init(machine);
_hud = Hud.Instance; _hud = Hud.Instance;
_player = (PlayerStateMachine)stateMachine;
_damageReceiver.Death += () => _damageReceiver.Death += () =>
{ {
ChangeState(PlayerState.Dead); ChangeState(PlayerState.Dead);
@ -70,12 +69,12 @@ public partial class Active : PlayerFSMState
_damageReceiver.RefillHealth(); _damageReceiver.RefillHealth();
_damageReceiver.RefillShield(); _damageReceiver.RefillShield();
_activationProvider.Init(stateMachine); _activationProvider.Init(MainObject);
//_weaponProvider = stateMachine.GetNode<PlayerWeaponProvider>("WeaponProvider"); //_weaponProvider = stateMachine.GetNode<PlayerWeaponProvider>("WeaponProvider");
//_animationProvider = stateMachine.GetNode<PlayerAnimationProvider>("AnimationProvider"); //_animationProvider = stateMachine.GetNode<PlayerAnimationProvider>("AnimationProvider");
_weaponProvider.Init(stateMachine); _weaponProvider.Init(MainObject);
} }
public override void EnterState() public override void EnterState()
@ -102,9 +101,9 @@ public partial class Active : PlayerFSMState
public override void PhysicsProcessState(double delta) public override void PhysicsProcessState(double delta)
{ {
_stateMachine.Velocity = _movementDirection * MovementSpeed; MainObject.Velocity = _movementDirection * MovementSpeed;
_stateMachine.MoveAndSlide(); MainObject.MoveAndSlide();
} }
public override void ProcessState(double delta) public override void ProcessState(double delta)
@ -130,7 +129,7 @@ public partial class Active : PlayerFSMState
} }
} }
_animationProvider.SetAnimation(_stateMachine.Velocity); _animationProvider.SetAnimation(MainObject.Velocity);
_crosshairProvider.UpdatePosition(FacingDirection); _crosshairProvider.UpdatePosition(FacingDirection);

View file

@ -2,8 +2,9 @@
namespace Cirno.Scripts.Components.FSM.Player; namespace Cirno.Scripts.Components.FSM.Player;
public partial class Controlling : PlayerFSMState public partial class Controlling : PlayerStateBase
{ {
public override PlayerState StateId => PlayerState.Controlling;
[Export] [Export]
private PlayerAnimationProvider _animationProvider; private PlayerAnimationProvider _animationProvider;

View file

@ -2,8 +2,9 @@
namespace Cirno.Scripts.Components.FSM.Player; namespace Cirno.Scripts.Components.FSM.Player;
public partial class Cutscene : PlayerFSMState public partial class Cutscene : PlayerStateBase
{ {
public override PlayerState StateId => PlayerState.Cutscene;
[Export] [Export]
private PlayerAnimationProvider _animationProvider; private PlayerAnimationProvider _animationProvider;
@ -19,7 +20,7 @@ public partial class Cutscene : PlayerFSMState
public override void ProcessState(double delta) public override void ProcessState(double delta)
{ {
_animationProvider.SetAnimation(_stateMachine.Velocity); _animationProvider.SetAnimation(MainObject.Velocity);
} }
public override void PhysicsProcessState(double delta) public override void PhysicsProcessState(double delta)

View file

@ -3,8 +3,10 @@ using Godot;
namespace Cirno.Scripts.Components.FSM.Player; namespace Cirno.Scripts.Components.FSM.Player;
public partial class Dead : PlayerFSMState public partial class Dead : PlayerStateBase
{ {
public override PlayerState StateId => PlayerState.Dead;
[Export] [Export]
private PlayerAnimationProvider _animationProvider; private PlayerAnimationProvider _animationProvider;
@ -14,29 +16,18 @@ public partial class Dead : PlayerFSMState
[Export] [Export]
private ActorResourceProvider _healthProvider; private ActorResourceProvider _healthProvider;
private GameManager _gameManager;
private Hud _hud;
public override void Init(ActorStateMachine stateMachine)
{
base.Init(stateMachine);
_gameManager = GameManager.Instance;
_hud = Hud.Instance;
}
public override void EnterState() public override void EnterState()
{ {
_animationProvider.PlayDeathAnimation(); _animationProvider.PlayDeathAnimation();
// show game over // show game over
_hud.ShowGameOver(); Hud.Instance.ShowGameOver();
} }
public override void ExitState() public override void ExitState()
{ {
// Hide game over // Hide game over
_hud.HideGameOver(); Hud.Instance.HideGameOver();
} }
public override void ProcessState(double delta) public override void ProcessState(double delta)
@ -55,10 +46,10 @@ public partial class Dead : PlayerFSMState
public void Respawn() public void Respawn()
{ {
_stateMachine.GlobalPosition = _gameManager.LastCheckpointPosition; MainObject.GlobalPosition = GameManager.Instance.LastCheckpointPosition;
_healthProvider.FillResource(); _healthProvider.FillResource();
_gameManager.ClearBullets(); GameManager.Instance.ClearBullets();
_stateMachine.SetState((int)PlayerState.Active); ChangeState(PlayerState.Active);
} }
} }

View file

@ -4,8 +4,10 @@ using Godot;
namespace Cirno.Scripts.Components.FSM.Player; namespace Cirno.Scripts.Components.FSM.Player;
public partial class Init : PlayerFSMState public partial class Init : PlayerStateBase
{ {
public override PlayerState StateId => PlayerState.Init;
[Export] [Export]
private PlayerAnimationProvider _animationProvider; private PlayerAnimationProvider _animationProvider;
public override void EnterState() public override void EnterState()
@ -32,6 +34,6 @@ public partial class Init : PlayerFSMState
private async Task AutoSwitchToStart() private async Task AutoSwitchToStart()
{ {
await Task.Delay(500); await Task.Delay(500);
_stateMachine.SetState((int)PlayerState.Active); StateMachine.SetState(PlayerState.Active);
} }
} }

View file

@ -0,0 +1,8 @@
using Godot;
namespace Cirno.Scripts.Components.FSM.Player;
public abstract partial class PlayerStateBase : BaseState<PlayerState, CharacterBody2D>
{
}

View file

@ -2,8 +2,10 @@
namespace Cirno.Scripts.Components.FSM.Player; namespace Cirno.Scripts.Components.FSM.Player;
public partial class Teleporting : PlayerFSMState public partial class Teleporting : PlayerStateBase
{ {
public override PlayerState StateId => PlayerState.Init;
[Export] [Export]
private PlayerAnimationProvider _animationProvider; private PlayerAnimationProvider _animationProvider;

View file

@ -2,8 +2,10 @@
namespace Cirno.Scripts.Components.FSM.Player; namespace Cirno.Scripts.Components.FSM.Player;
public partial class UnTeleporting : PlayerFSMState public partial class UnTeleporting : PlayerStateBase
{ {
public override PlayerState StateId => PlayerState.UnTeleporting
;
[Export] [Export]
private PlayerAnimationProvider _animationProvider; private PlayerAnimationProvider _animationProvider;

View file

@ -0,0 +1,18 @@
using Godot;
namespace Cirno.Scripts.Components.FSM;
public abstract partial class PlayerArea2DModule : Area2D, IModule<PlayerState, CharacterBody2D>
{
public IStateMachine<PlayerState, CharacterBody2D> StateMachine { get; private set; }
public CharacterBody2D CharacterBody => StateMachine.MainObject;
public virtual void Init(IStateMachine<PlayerState, CharacterBody2D> machine)
{
StateMachine = machine;
}
public abstract void Process(double delta);
public abstract void PhysicsProcess(double delta);
}

View file

@ -3,15 +3,8 @@ using Godot;
namespace Cirno.Scripts.Components.FSM; namespace Cirno.Scripts.Components.FSM;
public partial class PlayerStateMachine : ActorStateMachine public partial class PlayerStateMachine : StateMachineBase<PlayerState, CharacterBody2D>
{ {
[Export] [Export] public override PlayerState InitialState { get; protected set; } = PlayerState.Init;
public PlayerState InitialState { get; private set; }
public override void _Ready()
{
base._Ready();
this.SetState((int)InitialState);
}
} }

View file

@ -30,7 +30,7 @@ public partial class ControlEnemyEvent : EventResource
if (_parent.GetNode<Node2D>(Target) is Enemy enemy) if (_parent.GetNode<Node2D>(Target) is Enemy enemy)
{ {
_gameManager.CameraTargetObject(enemy); _gameManager.CameraTargetObject(enemy);
GameManager.Instance.Player.SetState((int)PlayerState.Controlling); GameManager.Instance.Player.SetState(PlayerState.Controlling);
// _gameManager.Player.RequestMovementDisable(true); // _gameManager.Player.RequestMovementDisable(true);
enemy.AssumeControl(); enemy.AssumeControl();
// TODO: Do this on the enemy as a module instead // TODO: Do this on the enemy as a module instead

View file

@ -35,7 +35,7 @@ public partial class MovePlayerEvent : EventResource
protected async Task MovePlayer() protected async Task MovePlayer()
{ {
GameManager.Instance.Player.SetState((int)PlayerState.Cutscene); GameManager.Instance.Player.SetState(PlayerState.Cutscene);
//_gameManager.Player.RequestMovementDisable(true); //_gameManager.Player.RequestMovementDisable(true);
Tween tween = _gameManager.GetTree().CreateTween(); Tween tween = _gameManager.GetTree().CreateTween();
@ -46,7 +46,7 @@ public partial class MovePlayerEvent : EventResource
// Wait for the tween to finish // Wait for the tween to finish
await ToSignal(tween, "finished"); await ToSignal(tween, "finished");
GameManager.Instance.Player.SetState((int)PlayerState.Active); GameManager.Instance.Player.SetState(PlayerState.Active);
//_gameManager.Player.RequestMovementDisable(false); //_gameManager.Player.RequestMovementDisable(false);
_isComplete = true; _isComplete = true;