• GameFrameWork框架(Unity3D)使用笔记(五)游戏主流程ProcedureMain


    目录

    前言:

    一、切换到ProcedureMain流程

    二、场景布置

    三、生成主角

    1、EntityLogic

    2、EntityData

    (1)Id

    (2)TypeId

    (3)Position

    (4)Rotation

     成功!


    前言:

            前面已经完成了UI界面切换等功能,但是真正的游戏内容主体部分还没有开始,下面就来实现游戏的主流程。

            本篇的内容又用到了GF的一个新模块:Entity。这一次我们主要实现的就是在场景中生成主角。


    一、切换到ProcedureMain流程

            首先先给“开始”按钮按钮增加一下切换到ProcedureMain的功能。

            之前已经写过了,按下开始按钮会设置m_StartGametrue:

    //MenuForm.cs

    //ProcedureMenu.cs然后就是在菜单流程中的OnUpdate里面检测m_StartGame,如果是true则利用转换流程ProcedureChangeScene到主流程:

    1. protected override void OnUpdate(IFsm procedureOwner, float elapseSeconds, float realElapseSeconds)
    2. {
    3. base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
    4. if (m_StartGame)
    5. {
    6. //先设置要转换的下一个场景的ID:
    7. procedureOwner.SetData("NextSceneId",GameEntry.Config.GetInt("Scene.Main"));
    8. //然后进行场景切换流程
    9. ChangeState(procedureOwner);
    10. }
    11. }

     然后在场景切换流程里面,写好了切换到主流程的逻辑:

    1. #ProcedureChangeScene.cs
    2. protected override void OnUpdate(IFsm procedureOwner, float elapseSeconds, float realElapseSeconds)
    3. {
    4. base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
    5. if (!m_IsChangeSceneComplete)
    6. {
    7. return; //还没完成场景切换
    8. }
    9. if (m_ChangeToMenu)
    10. {
    11. ChangeState(procedureOwner); //菜单
    12. }else
    13. {
    14. ChangeState(procedureOwner); //游戏运行主流程
    15. }
    16. }

    别忘了加到Build Settings里面: 

    然后测试试试:

     

    从结果可以看出,场景确实切换了,但是UI并没有关闭, 经过调查是上次自己在测试的时候注释掉了“在菜单流程结束的时候关闭菜单UI界面”的逻辑,恢复后就解决了:

    1. ProcedureMenu.cs
    2. protected override void OnLeave(IFsm procedureOwner, bool isShutdown)
    3. {
    4. base.OnLeave(procedureOwner, isShutdown);
    5. GameEntry.Event.Unsubscribe(OpenUIFormSuccessEventArgs.EventId, OnOpenUIFormSuccess);
    6. Log.Info("退出菜单流程!");
    7. if (m_MenuForm != null)
    8. {
    9. m_MenuForm.Close(isShutdown);
    10. m_MenuForm = null;
    11. }
    12. }

     然后就切换到主游戏场景和流程了。


    二、场景布置

            目前场景是空的,因为我们这个是2D游戏所以先在场景上把简单的关卡墙体啥的摆好:

            (我直接拿以前的项目的东西来做了,包括一些2D游戏需要的插件的安装这里省去了,因为文字内容重点在GF框架)。

            ​​​​​​​

    这个关卡的任务很简单,就是主角从左下角出生,然后走到门进去,通关!


    三、生成主角

            之前主角的控制脚本都是直接一把梭的,既然这里用了框架最好就是用状态机复刻一下。并且把逻辑和数据分离(参考StarForce),不过这里为了节约时间就直接用之前做好的预制体,主要是用来展示一下实体的生成方式。        

    然后预制体:

    1、EntityLogic

    然后,和UI的使用方法很类似(需要实现一个继承UIFormLogic的类),我们需要为这个实体写一个继承EntityLogic 类的脚本:

     然后,我们在游戏流程里加上生成实体的语句。

    在此之前,因为所有实体都有一个唯一的ID用来标识,为了方便统一地生成这个ID,我们先写一个扩展方法:

                                                                ​​​

    然后我们就可以在主流程里写生成实体的语句:

    然后运行,点击开始游戏按钮:

    发现人物并没有出现。

    其实如果经验够丰富的话,你应该能猜到为啥没有出现。实际上人物实体已经生成了,但是我们并没有指定它的初始位置,所以我们打开框架下的Entity模块可以找到生成的Character:

    而它的位置是预制体中设置的位置:

    那怎么才能在生成这个玩家Entity的时候指定它所生成的位置呢?

    首先,一个比较完整的实体,应该包含逻辑(Logic)数据(Data)吧。我们刚才写了这个Player的逻辑(Logic)(继承了EntityLogic),是不是还缺少数据部分(EntityData)?

    那我们下面就来实现数据部分。

    2、EntityData

    EntityLogic使用方法不同的是,框架里面没有可以让我们来继承的EntityData类,所以我们需要自己实现自己的EntityData类。

    先实现一个抽象类EntityData,让其它实体去继承它。所以我们需要考虑所有实体都共有的属性。这里我们参照StarForce的EntityData的实现:

    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System;
    5. [Serializable]
    6. public abstract class EntityData
    7. {
    8. [SerializeField]
    9. private int m_Id = 0;
    10. [SerializeField]
    11. private int m_TypeId = 0;
    12. [SerializeField]
    13. private Vector3 m_Position = Vector3.zero;
    14. [SerializeField]
    15. private Quaternion m_Rotation = Quaternion.identity;
    16. public EntityData(int entityId, int typeId)
    17. {
    18. m_Id = entityId;
    19. m_TypeId = typeId;
    20. }
    21. ///
    22. /// 实体编号。
    23. ///
    24. public int Id
    25. {
    26. get
    27. {
    28. return m_Id;
    29. }
    30. }
    31. ///
    32. /// 实体类型编号。
    33. ///
    34. public int TypeId
    35. {
    36. get
    37. {
    38. return m_TypeId;
    39. }
    40. }
    41. ///
    42. /// 实体位置。
    43. ///
    44. public Vector3 Position
    45. {
    46. get
    47. {
    48. return m_Position;
    49. }
    50. set
    51. {
    52. m_Position = value;
    53. }
    54. }
    55. ///
    56. /// 实体朝向。
    57. ///
    58. public Quaternion Rotation
    59. {
    60. get
    61. {
    62. return m_Rotation;
    63. }
    64. set
    65. {
    66. m_Rotation = value;
    67. }
    68. }
    69. }

     当然目录结构也要管理好:

    下面来解释一下这个EntityData的内容:

    里面有四个属性,都是在Unity中生成的实体所共有的特点。

    (1)Id

            实体编号

            用于唯一标识一个实体,所有实体的ID互不相同。

    (2)TypeId

            实体类型编号

            首先这里需要明白一件事情,根据框架作者的项目可以看出,游戏中所有对象(如怪物、玩家)都是从配置文件(数据表)中加载配置,然后再创建出来。

            然后,举个例子,策划设计了史莱姆怪物,然后为它们写数据表Shilaimu.txt。然后史莱姆怪物分好多种类,比如雷史莱姆,草史莱姆,风史莱姆,火史莱姆,岩史莱姆, 冰史莱姆,然后在配置表中,大概是这样:

            每一种怪物都有个ID,具体体现就是数据表的第一列的ID,这个就是TypeId

            那TypeIdId的区别是啥呢?Id是在整个实体框架里面唯一标识一个实体,而TypeId则标识了一个种类。比如场景中可能有两个雷史莱姆,他们的TypeId是一样的,因为它们种类一样,但是他们的Id不一样,因为他们是不同的个体。

    (3)Position

            位置

            每个在场景里的物体一定都有个位置,是一个三维向量。

    (4)Rotation

            旋转

            每个在场景里的物体一定都有个朝向,是一个四元数。     

            抽象基类写好了下面就来写PlayerPlayerData类。:

           

    目前我们的目的只是把玩家显示到特定位置,所以这里暂且先继承一下写好的抽象基类就行。

    然后改一改显示实体的代码,在playerData里面设置了初始位置。

    然后运行看看:

    (红色报错可以无视,是角色动画部分复制过来的时候没设置好)

     emm角色还是不在场景里面。原因是这样的:

    虽然我们设置了Player这个实体的数据部分PlayerDataPosition信息,但是这个信息只是被实体的playerData携带了,并没有”应用“出来,而要把生成的实体“移动”到我们规定的位置,还需要在实体的EntityLogic部分对其进行实现(Player.cs)。

    所以我们在Player类里面的Init()函数里面加上改变实体位置到playerData.Position处的逻辑:

    CachedTransform是父类里的一个属性,缓存的是实体的Transform。这里的意思就是在实体初始化的时候设置好TransformPosition为之前在playerData里设置的Position(ShowEntity函数传递进去的playerData最终会到达这里函数的userData参数)

    然后运行看看结果:

     成功!


    这次成功将实体加载到了场景里面,鉴于篇幅本篇先到这里为止。接下来要做的工作将围绕继续完成这一关的流程进行。

     

     

     


                                                                     

     

     

     

     

     

     

     

            

            

  • 相关阅读:
    ValueError: unsupported format character ‘;‘ (0x3b) at index 625
    蓝桥杯:分巧克力
    演讲实录:大模型时代,我们需要什么样的AI算力系统?
    s域和z域的频域响应分析
    mysql—查询加强练习
    MVC分页
    离线强化学习(Offline RL)系列7: (状态处理) OfflineRL中的状态空间的数据增强(7种增强方案)
    前端模糊搜索
    ubuntu下mysql常用命令
    第二章:Pythonocc官方demo 案例45(几何轴向曲线偏置)
  • 原文地址:https://blog.csdn.net/HowToPause/article/details/127489522