com.alicizax.unity.framework/Runtime/FSM/SimpleFSM.cs

260 lines
5.7 KiB
C#
Raw Normal View History

2025-09-05 19:46:30 +08:00
using System;
using System.Runtime.CompilerServices;
using AlicizaX;
public interface IState : IMemory
{
IUltraFSM Fsm { get; set; }
bool IsRegistered { get; set; }
void Init();
void Enter();
void Exit();
void Update(float deltaTime);
void Destroy();
}
public abstract class StateBase<TState> : IState where TState : Enum
{
public void Clear()
{
IsRegistered = false;
Fsm = null;
}
public bool fromPool { get; set; }
public IUltraFSM Fsm { get; set; }
public bool IsRegistered { get; set; }
protected virtual void OnInit()
{
}
protected virtual void OnEnter()
{
}
protected virtual void OnExit()
{
}
protected virtual void OnUpdate(float deltaTime)
{
}
protected virtual void OnDestroy()
{
}
void IState.Init()
{
OnInit();
}
void IState.Enter()
{
OnEnter();
}
void IState.Exit()
{
OnExit();
}
void IState.Update(float deltaTime)
{
OnUpdate(deltaTime);
}
void IState.Destroy()
{
IsRegistered = false;
OnDestroy();
}
protected void SwitchState(TState newStateId)
{
(Fsm as SimpleFSM<TState>).SwitchState(newStateId);
}
}
public interface IUltraFSM
{
string Name { get; }
string StateName { get; }
void Update(float deltaTime);
void Dispose();
}
public sealed class SimpleFSM<TState> : IUltraFSM where TState : Enum
{
private IState[] _states;
private string _name;
private int _currentIndex = -1;
private int _registeredCount;
private TState _currentState;
public string Name
{
get => _name;
}
public string StateName
{
get
{
if (_currentIndex == -1)
{
return "None";
}
return CurrentState.ToString();
}
}
public TState CurrentState
{
get
{
if (_currentIndex == -1)
throw new InvalidOperationException("No current state.");
return _currentState;
}
}
public SimpleFSM()
{
Initialize("None", 16);
}
internal int Capacity => _states?.Length ?? 0;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static int CalculateCapacity(int requested)
{
if (requested < 16) return 16;
requested--;
requested |= requested >> 1;
requested |= requested >> 2;
requested |= requested >> 4;
requested |= requested >> 8;
requested |= requested >> 16;
return requested + 1;
}
internal void Initialize(string name, int minCapacity)
{
_name = name;
int newCapacity = CalculateCapacity(minCapacity);
_states ??= new IState[newCapacity];
}
private void Resize(int minCapacity)
{
int newCapacity = CalculateCapacity(minCapacity);
if (_states != null && _states.Length >= newCapacity) return;
Array.Resize(ref _states, newCapacity);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Register<T>(TState stateId) where T : class, IMemory, IState, new()
{
int stateIdValue = Convert.ToInt32(stateId);
if (stateIdValue < 0)
throw new ArgumentException("State ID must be non-negative.");
if (stateIdValue >= _states.Length)
Resize(stateIdValue + 1);
// 检查当前状态是否已注册,若存在则先释放
var existingState = _states[stateIdValue];
if (existingState != null && existingState.IsRegistered)
{
existingState.Destroy();
MemoryPool.Release(existingState);
_registeredCount--;
}
IState state = default;
state = new T();
_states[stateIdValue] = state;
if (!state.IsRegistered)
{
state.Fsm = this;
state.Init();
state.IsRegistered = true;
_registeredCount++;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SwitchState(TState newStateId)
{
int newStateIdValue = Convert.ToInt32(newStateId);
if (newStateIdValue < 0 || newStateIdValue >= _states.Length)
throw new ArgumentOutOfRangeException(nameof(newStateId), "State ID is out of range.");
int prevIndex = _currentIndex;
int newIndex = newStateIdValue;
if (prevIndex == newIndex) return;
ExitState(prevIndex);
EnterState(newIndex);
_currentIndex = newIndex;
_currentState = newStateId;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(float deltaTime)
{
if ((uint)_currentIndex < (uint)_states.Length)
_states[_currentIndex]?.Update(deltaTime);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ExitState(int index)
{
if ((uint)index < (uint)_states.Length)
_states[index]?.Exit();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void EnterState(int index)
{
if ((uint)index < (uint)_states.Length)
{
IState state = _states[index];
if (state.IsRegistered)
state.Enter();
}
}
public void Dispose()
{
if (_states == null) return;
for (int i = 0; i < _states.Length; i++)
{
IState state = _states[i];
if (state != null && state.IsRegistered)
{
state.Destroy();
}
}
// 清空数组引用,帮助 GC 回收内存
Array.Clear(_states, 0, _states.Length);
_states = null;
_currentIndex = -1;
_registeredCount = 0;
}
}