GameFramework框架 (三) 流程组件 ProcedureComponent

前言

ProcedureComponent 组件是上一份笔记中的 21个组件之一, 在Awake中注册到了 GameEntry的组件列表中, 今天来学习这个组件的执行逻辑和内部实现

状态机

先复习一下第一篇中的内容:

有限状态机 (FSM) – 提供创建、使用和销毁有限状态机的功能,一些适用于有限状态机机制的游戏逻辑,使用此模块将是一个不错的选择。

状态机大白话:

举个栗子: 游戏中的角色会有各种状态: 比如 走路, 跑步, 死亡;

玩家会在不同状态之间切换;

当玩家进入走路状态时,播放走路动画;

当玩家从走路状态切换到跑步状态时,退出走路动画, 播放跑步动画;

当玩家从任意状态死亡时,退出当前状态的动画,播放死亡动画

状态机就是负责 管理这些状态和状态切换的 类

总结一下:

          有各种状态, 封装一个状态的共同基类, 每个状态都有进入和退出两种行为

          玩家只能处于 一个状态, 即 当前状态

          状态切换: 前一个状态执行退出操作, 后一个状态执行Enter操作, 当前状态修改为后一个状态

为了简化,删了部分代码, 状态类封装代码

  //为了简化,删了很多代码
public abstract class FsmState<T> where T : class
    {
       
        /// 有限状态机状态初始化时调用。
        protected internal virtual void OnInit(IFsm<T> fsm)
        {
        }

        /// 有限状态机状态进入时调用。
        protected internal virtual void OnEnter(IFsm<T> fsm)
        {
        }

        /// 有限状态机状态轮询时调用。
        protected internal virtual void OnUpdate(IFsm<T> fsm, float elapseSeconds, float realElapseSeconds)
        {
        }

        /// 有限状态机状态离开时调用。
        protected internal virtual void OnLeave(IFsm<T> fsm, bool isShutdown)
        {
        }

        /// 有限状态机状态销毁时调用。
        protected internal virtual void OnDestroy(IFsm<T> fsm)
        {
        }

        /// 切换当前有限状态机状态。
        protected void ChangeState<TState>(IFsm<T> fsm) where TState : FsmState<T>
        {
            Fsm<T> fsmImplement = (Fsm<T>)fsm;
            fsmImplement.ChangeState<TState>();
        }

       ...
    }

为了简化,删了部分代码, 状态机类封装代码:

使用字典容器保存所有的状态,切换状态实质就是执行上一个状态的退出操作,修改当前状态为下一个状态, 执行下一个状态的进入操作,是不是很简单

// 为了简化,删了很多代码
internal sealed class Fsm<T> : FsmBase, IReference, IFsm<T> where T : class
    {

        private readonly Dictionary<Type, FsmState<T>> m_States;  
        private FsmState<T> m_CurrentState;


        /// 创建有限状态机。
        public static Fsm<T> Create(string name, T owner, params FsmState<T>[] states)
        {
          
            Fsm<T> fsm = ReferencePool.Acquire<Fsm<T>>();
            foreach (FsmState<T> state in states)
            {         
                Type stateType = state.GetType();          
                fsm.m_States.Add(stateType, state);
                state.OnInit(fsm);
            }

            return fsm;
        }

        

        /// <summary>
        /// 清理有限状态机。
        /// </summary>
        public void Clear()
        {
            if (m_CurrentState != null)
            {
                m_CurrentState.OnLeave(this, true);
            }

            foreach (KeyValuePair<Type, FsmState<T>> state in m_States)
            {
                state.Value.OnDestroy(this);
            }

             ...
        }

        /// 开始有限状态机。
        public void Start(Type stateType)
        {
            
            FsmState<T> state = GetState(stateType);       
            m_CurrentState = state;
            m_CurrentState.OnEnter(this);
        }
       
        /// 获取有限状态机状态。
        public FsmState<T> GetState(Type stateType)
        {
           
            FsmState<T> state = null;
            if (m_States.TryGetValue(stateType, out state))
            {
                return state;
            }
            return null;
        }
  
   
        /// 有限状态机轮询 
        internal override void Update(float elapseSeconds, float realElapseSeconds)
        {         
            m_CurrentStateTime += elapseSeconds;
            m_CurrentState.OnUpdate(this, elapseSeconds, realElapseSeconds);
        }

        /// 关闭并清理有限状态机。
        internal override void Shutdown()
        {
            ReferencePool.Release(this);
        }

        /// 切换当前有限状态机状态。
        internal void ChangeState(Type stateType)
        {
         
            FsmState<T> state = GetState(stateType);        
            m_CurrentState.OnLeave(this, false);
            m_CurrentState = state;
            m_CurrentState.OnEnter(this);
        }
    }

在游戏中,很多地方都可以使用状态机的概念, 再举个栗子:

场景切换: 每一个场景,我们可以认为是一个状态, 前一个场景执行退出操作,后一个场景执行加载和初始化操作,都可以使用状态机来实现;

流程

整个程序的生命周期中,一些重要的操作,也可以视为状态,GF框架将这些操作封装为流程, 流程本质上就是一个状态机。

流程 (Procedure) – 是贯穿游戏运行时整个生命周期的有限状态机。通过流程,将不同的游戏状态进行解耦将是一个非常好的习惯。对于网络游戏,你可能需要如检查资源流程、更新资源流程、检查服务器列表流程、选择服务器流程、登录服务器流程、创建角色流程等流程,而对于单机游戏,你可能需要在游戏选择菜单流程和游戏实际玩法流程之间做切换。如果想增加流程,只要派生自 ProcedureBase 类并实现自己的流程类即可使用

 //流程继承自FSMState, 一个流程就是一个状态
public abstract class ProcedureBase : FsmState<IProcedureManager>
    {

        protected internal override void OnInit(ProcedureOwner procedureOwner)
        {
            base.OnInit(procedureOwner);
        }

        /// 进入状态时调用。
        protected internal override void OnEnter(ProcedureOwner procedureOwner)
        {
            base.OnEnter(procedureOwner);
        }

        /// 状态轮询时调用。
        protected internal override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
        {
            base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
        }

        /// 离开状态时调用。
        protected internal override void OnLeave(ProcedureOwner procedureOwner, bool isShutdown)
        {
            base.OnLeave(procedureOwner, isShutdown);
        }

        /// 状态销毁时调用。
        protected internal override void OnDestroy(ProcedureOwner procedureOwner)
        {
            base.OnDestroy(procedureOwner);
        }

流程管理器, 实现类,请自行查看 ProcedureManager.cs

public interface IProcedureManager
    {
        /// 获取当前流程。
        ProcedureBase CurrentProcedure
        {
            get;
        }

        /// 获取当前流程持续时间。
        float CurrentProcedureTime
        {
            get;
        }

        /// 初始化流程管理器。
        void Initialize(IFsmManager fsmManager, params ProcedureBase[] procedures);

        /// 开始流程。
        void StartProcedure<T>() where T : ProcedureBase;


        /// 是否存在流程。
        bool HasProcedure<T>() where T : ProcedureBase;


        /// 获取流程。
        ProcedureBase GetProcedure<T>() where T : ProcedureBase;

    }

StarForce执行流程

在ProceduceComponent的Start中,使用反射实例化所有的流程(状态), 调用m_ProcedureManager.Initialize把状态数组传入,创建状态机,状态机中的字典容器内容就是流程数组传递过来的值

m_ProcedureManager.StartProcedure, 设置当前状态,执行OnEnter

// procedureComponent.cs 


protected override void Awake()
        {
            base.Awake();

            m_ProcedureManager = GameFrameworkEntry.GetModule<IProcedureManager>();
            if (m_ProcedureManager == null)
            {
                Log.Fatal("Procedure manager is invalid.");
                return;
            }
        }

        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_EnterProceduce,执行OnEnter方法
            m_ProcedureManager.StartProcedure(m_EntranceProcedure.GetType());
        }

面板中设置的入口流程为 ProcedureLauncher,即 m_EntranceProceduce

 m_ProcedureManager.StartProcedure(m_EntranceProcedure.GetType());  之后会调用ProceduceLauncher.OnEnter函数

 在Launch流程OnEnter中初始化了一些配置, 在OnUpdate轮询中,切换到了 Splash流程

 Splash流程,在编辑器模式,直接跳到 PreLoad流程

 在PreLoad流程中,加载了配置文件, 配置文件加载完成后, 设置NextSceneID为 Menu, 跳转到 ChangeScene流程

在ChangeScene流程中,加载Menu场景,场景加载完成后, 跳转到ProcedureMenu流程

 在Menu流程中,调用GameEntry.UI.OpenUIForm(UIFormId.MenuForm, this), 打开了UI界面;

自定义流程

自定义流程只需要继承自 Procedurebase即可

//我的自定义流程,必须继承ProcedureBase
 public class ProcedureILRuntime : ProcedureBase
    {
        public override bool UseNativeDialog
        {
            get
            {
                return false;
            }
        }

        //private IMethod m_Update;

        //private IMethod m_Shutdown;

        protected override void OnEnter(IFsm<IProcedureManager> procedureOwner)
        {
            base.OnEnter(procedureOwner);

            //GameEntry.ILRuntime.LoadHotfixDll();
        }

        protected override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds, float realElapseSeconds)
        {
            base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
            //GameEntry.ILRuntime.InvokeUpdate();
        }

        protected override void OnLeave(IFsm<IProcedureManager> procedureOwner, bool isShutdown)
        {
            base.OnLeave(procedureOwner, isShutdown);
            //GameEntry.ILRuntime.InvokeShutdown();
        }
    }

如果需要在代码中使用自定义流程,在unity编辑器,必须启用自定义流程,在前面打勾即可

然后再代码中就可以切换到自定义流程了

  if (GameEntry.ILRuntime.ILRuntimeMode)
            {
                ChangeState<ProcedureILRuntime>(procedureOwner);              
            }
            else
            {
                procedureOwner.SetData<VarInt32>(Constant.ProcedureData.NextSceneId, (int)SceneId.Start);
                ChangeState<ProcedureChangeScene>(procedureOwner);
            }

下一篇开始学时 事件EventComponent,敬请期待,如有错误或不解的地方,还请留言,谢谢! 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值