增加procedure模块

This commit is contained in:
陈思海 2025-11-18 16:15:11 +08:00
parent e31dda94ce
commit 958364080f
16 changed files with 259 additions and 262 deletions

View File

@ -1,6 +1,4 @@
// ===================== FSMDebugger Window (unchanged API, auto-binding now) ===================== using AlicizaX;
using AlicizaX.Fsm;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;

View File

@ -1,10 +1,10 @@
using AlicizaX; using AlicizaX;
using AlicizaX.Fsm;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace AlicizaX.Fsm.Runtime namespace AlicizaX
{ {
/// <summary> /// <summary>
/// 有限状态机组件。 /// 有限状态机组件。

View File

@ -5,7 +5,7 @@ using UnityEngine;
using UnityEngine.Scripting; using UnityEngine.Scripting;
using Object = UnityEngine.Object; using Object = UnityEngine.Object;
namespace AlicizaX.Fsm.Runtime namespace AlicizaX
{ {
[Preserve] [Preserve]
internal sealed class FsmModule : IFsmModule internal sealed class FsmModule : IFsmModule

View File

@ -4,7 +4,7 @@ using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading; using System.Threading;
namespace AlicizaX.Fsm namespace AlicizaX
{ {
internal interface IFsmRunner : IDisposable, IMemory internal interface IFsmRunner : IDisposable, IMemory
{ {

View File

@ -1,7 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace AlicizaX.Fsm.Runtime namespace AlicizaX
{ {
public interface IFsmModule : IModule, IModuleUpdate, IModuleAwake, IModuleLateUpdate public interface IFsmModule : IModule, IModuleUpdate, IModuleAwake, IModuleLateUpdate
{ {

View File

@ -1,251 +0,0 @@
using System;
using System.Runtime.CompilerServices;
using AlicizaX;
public interface IState
{
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 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, 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();
_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;
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 064e59389d6a4e61816e12e5de6848ed
timeCreated: 1756985353

3
Runtime/Procedure.meta Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 131e0fd9dfe2470394ebf46fd2a9c781
timeCreated: 1763450210

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
namespace AlicizaX
{
public interface IProcedureModule:IModule,IModuleUpdate
{
void InitializeProcedure(List<IProcedure> availableProcedures, Type defaultProcedureType);
void ClearAllProcedures();
bool SwitchProcedure<T>() where T : IProcedure;
bool SwitchProcedure(Type procedureType);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 18d5ca3d17384612b2d2023084b6a97b
timeCreated: 1763451617

View File

@ -0,0 +1,72 @@
namespace AlicizaX
{
public interface IProcedure
{
IProcedureModule ProcedureModule { get; set; }
void Init();
void Enter();
void Leave();
void Update();
void Destroy();
}
/// <summary>
/// 流程基类 - 使用模板方法模式定义流程生命周期
/// </summary>
public abstract class ProcedureBase : IProcedure
{
public IProcedureModule ProcedureModule { get; set; }
void IProcedure.Init()
{
OnInit();
}
void IProcedure.Enter()
{
OnEnter();
}
void IProcedure.Leave()
{
OnLeave();
}
void IProcedure.Update()
{
OnUpdate();
}
void IProcedure.Destroy()
{
OnDestroy();
}
protected virtual void OnInit()
{
}
protected virtual void OnEnter()
{
}
protected virtual void OnLeave()
{
}
protected virtual void OnUpdate()
{
}
protected virtual void OnDestroy()
{
}
protected internal void SwitchProcedure<T>() where T : ProcedureBase
{
ProcedureModule.SwitchProcedure<T>();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 367e3373495c49da9c1d85e9c5a68bf3
timeCreated: 1763450223

View File

@ -0,0 +1,21 @@
using UnityEngine;
namespace AlicizaX
{
[DisallowMultipleComponent]
[AddComponentMenu("Game Framework/Procedure")]
public sealed class ProcedureComponent : MonoBehaviour
{
private IProcedureModule _mProcedureModule = null;
private void Awake()
{
_mProcedureModule = ModuleSystem.RegisterModule<IProcedureModule, ProcedureModule>();
if (_mProcedureModule == null)
{
Log.Error("Procedure Module is invalid.");
return;
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c0a419f3af614cdda5267671f803dfdb
timeCreated: 1763451994

View File

@ -0,0 +1,132 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace AlicizaX
{
internal class ProcedureModule : IProcedureModule
{
private readonly Dictionary<Type, IProcedure> _procedures = new Dictionary<Type, IProcedure>();
private IProcedure _currentProcedure;
private IProcedure _defaultProcedure;
public void InitializeProcedure(List<IProcedure> availableProcedures, Type defaultProcedureType)
{
_procedures.Clear();
foreach (var procedure in availableProcedures)
{
var type = procedure.GetType();
_procedures[type] = procedure;
procedure.ProcedureModule = this;
procedure.Init();
}
if (_procedures.ContainsKey(defaultProcedureType))
{
_defaultProcedure = _procedures[defaultProcedureType];
SwitchProcedure(defaultProcedureType);
}
else
{
Log.Info($"默认流程 {defaultProcedureType.Name} 未注册!");
}
}
/// <summary>
/// <summary>
/// 清除所有流程
/// </summary>
public void ClearAllProcedures()
{
if (_procedures != null)
{
foreach (var procedure in _procedures.Values)
{
procedure.Destroy();
}
_procedures.Clear();
}
_currentProcedure = null;
_defaultProcedure = null;
}
public bool SwitchProcedure<T>() where T : IProcedure
{
if (HasProcedure<T>())
{
return SwitchProcedure(typeof(T));
}
if (_defaultProcedure != null)
{
Debug.LogWarning($"流程 {typeof(T).Name} 不存在,切换到默认流程");
return SwitchToDefault();
}
return false;
}
public bool SwitchProcedure(Type procedureType)
{
var nextProcedure = _procedures[procedureType];
var lastProcedure = _currentProcedure;
if (lastProcedure == nextProcedure)
return true;
if (lastProcedure != null)
{
lastProcedure.Leave();
}
nextProcedure.Enter();
_currentProcedure = nextProcedure;
return true;
}
/// <summary>
/// 切换到默认流程
/// </summary>
private bool SwitchToDefault()
{
if (_defaultProcedure != null)
{
return SwitchProcedure(_defaultProcedure.GetType());
}
return false;
}
/// <summary>
/// 检查是否存在指定类型的流程
/// </summary>
private bool HasProcedure<T>() where T : IProcedure
{
return _procedures.ContainsKey(typeof(T));
}
void IModule.Dispose()
{
ClearAllProcedures();
}
public int Priority { get; }
void IModuleUpdate.Update(float elapseSeconds, float realElapseSeconds)
{
if (_currentProcedure != null)
{
_currentProcedure.Update();
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4272c5c31b6b4a459f1da37a228cfd3f
timeCreated: 1763450372