260 lines
5.7 KiB
C#
260 lines
5.7 KiB
C#
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;
|
|
}
|
|
}
|