[GameFramework]教程08-Procedure的前世今生

本文探讨了GameFramework中Procedure的实现原理,包括ProcedureComponent如何生成Procedure子类实例,以及执行流程。通过分析源码,揭示了m_AvailableProcedureTypeNames和m_EntranceProcedureTypeName的作用,并解释了如何获取所有继承自ProcedureBase的子类。同时,文章还介绍了Procedure的执行顺序,重点讲解了Start方法中m_ProcedureManager的Initialize和StartProcedure在启动状态机过程中的作用。

经过前几节的学习,估计大家对Procedure与Fsm已经有了一定的了解,下面我们对Procedure进行初步的深入(说的有点大,就是看源码)

首先有几个问题是我比较困惑的:

1. Game Framework -> Procedure ->Procedure Component 下的各个继承自ProcedureBase的子类,是如何生成的?

跟随镜头,首先参观一下ProcedureComponent,没错,这就是我们在IDE中看到的那个脚本

[SerializeField]
private string[] m_AvailableProcedureTypeNames = null;

[SerializeField]
private string m_EntranceProcedureTypeName = null;

这两个参数,从字面意思就可以看出,m_AvailableProcedureTypeNames 为当前有效的Procedure,m_EntranceProcedureTypeName 也就是我们运行游戏第一个进入的Procedure。

然后本人看了一遍代码后,发现并没有实际能够取出所有Procedure的子类的东东,这是为何?最大函数也就是Start,这个我们后续再讲。(全局搜索吧!!m_AvailableProcedureTypeNames )

发现了ProcedureComponentInspector这个代码里竟然出现了!!(什么鬼?)

主意两个函数:

protected override void OnCompileComplete()
{
      base.OnCompileComplete();
      RefreshTypeNames();
}

private void OnEnable()
{
    m_AvailableProcedureTypeNames = serializedObject.FindProperty("m_AvailableProcedureTypeNames");
    m_EntranceProcedureTypeName = serializedObject.FindProperty("m_EntranceProcedureTypeName");
    RefreshTypeNames();
}

// 使用 serializedObject.FindProperty 方法 (这就能找到了?我不信,咋就那么智能了?)

// 获取 ProcedureComponent 中定义的 m_AvailableProcedureTypeNames

只通过这个方法还不足以,然后发现声明类的头部有一行代码:[CustomEditor(typeof(ProcedureComponent))]

这个就能找到 ProcedureComponent 中 对应的变量

继续看代码:

private void RefreshTypeNames()
{
    m_ProcedureTypeNames = Type.GetTypeNames(typeof(ProcedureBase));
    ReadAvailableProcedureTypeNames();
    int oldCount = m_CurrentAvailableProcedureTypeNames.Count;
    m_CurrentAvailableProcedureTypeNames = m_CurrentAvailableProcedureTypeNames.Where(x => m_ProcedureTypeNames.Contains(x)).ToList();
    if (m_CurrentAvailableProcedureTypeNames.Count != oldCount)
    {
        WriteAvailableProcedureTypeNames();
    }
    else if (!string.IsNullOrEmpty(m_EntranceProcedureTypeName.stringValue))
    {
        m_EntranceProcedureIndex = m_CurrentAvailableProcedureTypeNames.IndexOf(m_EntranceProcedureTypeName.stringValue);
        if (m_EntranceProcedureIndex < 0)
        {
            m_EntranceProcedureTypeName.stringValue = null;
        }
    }

    serializedObject.ApplyModifiedProperties();
}

通过 m_ProcedureTypeNames = Type.GetTypeNames(typeof(ProcedureBase)); 取出了所有继承自ProcedureBase的子类,也就是我们定义的那些进程。(原来在这里!对就在这里哇!)

2. 先执行那个Procedure,以及在执行过程中处理了哪些动动?

回到ProcedureComponent代码中,继续看Start (终于到这里了哇!!)

private IEnumerator Start()
{
    ProcedureBase[] procedures = new ProcedureBase[m_AvailableProcedureTypeNames.Length];
    for (int i = 0; i < m_AvailableProcedureTypeNames.Length; i++)
    {
        Type procedureType = Utility.Assembly.GetType(m_AvailableProcedureTypeNames[i]);
        if (procedureType == null)
        {
            Log.Error("Can not find procedure type '{0}'.", m_AvailableProcedureTypeNames[i]);
            yield break;
        }

        procedures[i] = (ProcedureBase)Activator.CreateInstance(procedureType);
        if (procedures[i] == null)
        {
            Log.Error("Can not create procedure instance '{0}'.", m_AvailableProcedureTypeNames[i]);
            yield break;
        }

        if (m_EntranceProcedureTypeName == m_AvailableProcedureTypeNames[i])
        {
            m_EntranceProcedure = procedures[i];
        }
    }

    if (m_EntranceProcedure == null)
    {
        Log.Error("Entrance procedure is invalid.");
        yield break;
    }

    m_ProcedureManager.Initialize(GameFrameworkEntry.GetModule<IFsmManager>(), procedures);

    yield return new WaitForEndOfFrame();

    m_ProcedureManager.StartProcedure(m_EntranceProcedure.GetType());
}

话不多说,直接看最后三行代码:

发现了初始化的地方 m_ProcedureManager.Initialize 和  m_ProcedureManager.StartProcedure 执行进程的地方!

(终于找到你,还好我没放弃!!)

这就得看GameFrameWork的源码了(打开吧!骚年们!)

public void Initialize(IFsmManager fsmManager, params ProcedureBase[] procedures)
{
    if (fsmManager == null)
    {
        throw new GameFrameworkException("FSM manager is invalid.");
    }

    m_FsmManager = fsmManager;
    m_ProcedureFsm = m_FsmManager.CreateFsm(this, procedures);
}

接着就是CreateFsm(终于创建状态机了哇)

public IFsm<T> CreateFsm<T>(string name, T owner, params FsmState<T>[] states) where T : class
{
    if (HasFsm<T>(name))
    {
        throw new GameFrameworkException(string.Format("Already exist FSM '{0}'.", Utility.Text.GetFullName<T>(name)));
    }

    Fsm<T> fsm = new Fsm<T>(name, owner, states);
    m_Fsms.Add(Utility.Text.GetFullName<T>(name), fsm);
    return fsm;
}

先到这吧!再往下降就涉及到了另外一个小的姿势点

接着的就是这个东东了:m_ProcedureManager.StartProcedure

public void StartProcedure(Type procedureType)
{
    if (m_ProcedureFsm == null)
    {
        throw new GameFrameworkException("You must initialize procedure first.");
    }

    m_ProcedureFsm.Start(procedureType);
}

继续看到了Fsm.cs文件

/// <summary>
/// 开始有限状态机。
/// </summary>
/// <typeparam name="TState">要开始的有限状态机状态类型。</typeparam>
public void Start<TState>() where TState : FsmState<T>
{
    if (IsRunning)
    {
        throw new GameFrameworkException("FSM is running, can not start again.");
    }

    FsmState<T> state = GetState<TState>();
    if (state == null)
    {
        throw new GameFrameworkException(string.Format("FSM '{0}' can not start state '{1}' which is not exist.", Utility.Text.GetFullName<T>(Name), typeof(TState).FullName));
    }

    m_CurrentStateTime = 0f;
    m_CurrentState = state;
    m_CurrentState.OnEnter(this);
}

到此为止,就看到了状态机的是如何启动的了,现在是不是清楚一些了?

(先看这两个吧,能说清楚就不错了)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值