笨木头  2018-02-27 17:15     Unity3D,Game Framework     阅读(15277)     评论(15)
转载请注明,原文地址: http://www.benmutou.com/archives/2521
文章来源:笨木头与游戏开发
本文 Game Framework 版本:3.1.0

本文 Unity3D 版本:2017.3

更多GF教程和实例:https://github.com/mutouzdl/gameframework_demo.git

 
转载请注明,原文地址:http://www.benmutou.com/archives/2521 文章来源:笨木头与游戏开发
通过上一篇的研究,我们已经了解到玩家飞机和怪物是怎么加载出来的(根据配置id读取配置文件,创建实体)。

我们来回忆一下,玩家飞机是怎么创建的:GameEntry.Entity.ShowMyAircraft

现在,为了知道玩家飞机的逻辑是在哪里处理,我跟进了ShowMyAircraft函数,又发现了框架作者的秘密。

1.GameEntry.Entity来源

ShowMyAircraft函数是通过GameEntry.Entity调用的,那我们自然要先知道这里的Entity是什么东西。

如果大家还记得最开始的文章的话,应该对GameEntry不陌生——它是游戏初始化入口。

在GameEntry的InitBuiltinComponents函数里,对Enitity属性进行了赋值:
Entity = UnityGameFramework.Runtime.GameEntry.GetComponent<EntityComponent>();
我们现在知道了,Entity是一个EntityComponet类型的对象。

至于EntityComponent,它是游戏组件,继承了GameFrameworkComponent,它在初始化的时候会调用GameEntry.RegisterComponent(this)注册自身:



必须是先进行了注册的组件,UnityGameFramework.Runtime.GameEntry.GetComponent才能获取到。

不过,现在不理解也没关系,我们只要知道,GameEntry.Entity是什么就好了。

注意,UnityGameFramework.Runtime.GameEntry和StarForce.GameEntry不是同一个对象,只是类名相同而已。

2.调用顺序

ShowMyAircraft函数进行了很多层的封装,不得不吐槽一下,一个demo做得这么复杂,我对框架的推广有点担忧…当然,并不是说这样不好,只是觉得针对demo级别,有点繁琐而已。

首先调用的是EntityExtension里的ShowMyAircraft函数,这里主要是为了从配置文件中加载飞机实体的配置数据(上一篇讲解过了)。

接下来才是调用EntityComponent的ShowEntity函数:



EntityComponent的ShowEntity函数又调用了IEntityManager的ShowEntity函数,留意最后一个参数(ShowEntityInfo),这个参数最终会通过实体对象的生命周期函数传回来。

这里的IEntityManager是什么?我又得给大家解释一下了:

3.IEntityManager

EntityComponent有一个类型为IEntityManager的属性,m_entityManager。

IEntityManager是一个接口,在EntityComponent的Awake里进行了初始化:
m_EntityManager = GameFrameworkEntry.GetModule<IEntityManager>();
具体GetModule是做了什么事情,我们暂时不深入了解,只要知道,它是用于获取游戏框架模块的,这里返回的对象是EntityManager(实体管理器)。

4.EntityManagerShowEnity函数

于是,我们又回到ShowEntity函数,EntityManager的ShowEntity函数主要做了下面几件事情:
a.根据配置数据,创建实体(从预制体创建)

b.调用实体对象的OnInit、OnShow生命周期函数,这里会把第2步提到的最后一个参数(new ShowEntityInfo(entityLogicType, userData))传递回来

c.还做了一些其他操作,我们暂时忽略

5.DefaultEntityHepler

等等,我们说了这么久,好像还没说到本篇的主题——飞机逻辑处理类

是的,为了知道逻辑处理类是如何绑定到实体上的,我们必须先了解实体是怎么创建的。

现在我们已经知道实体如何创建了,接下来,是最后一步,逻辑处理类是怎么和创建的实体对象关联起来的?

在EntityComponent类的Awake函数中,我们创建了EntityManager对象:



在Start函数里,还绑定了一个EntityHelper对象,这个EntityHelper对象就是实体管理器具体创建实体时要利用的工具类。代码比较多,我只截取其中一部分:



其中m_EntityHelperTypeName是这个Helper类的类型名字:



所以,我们知道了,EntityManage绑定的EntityHelper对象是DefaultEntityHelper。

DefaultEntityHelper是自定义的一个类,继承了EntityHelperBase。

 

如果以上你都没有看懂,那么,全部忽略吧(旁白:那我到底是为了什么要看你的文章啊喂!

我们只要知道,最终EntityManager创建实体的时候会调用DefaultEntityHelper的CreateEntity函数即可。

 

但是,到此为止还是不能找到逻辑处理类在哪里绑定的,我们还要继续研究。(旁白:说好的最后一步呢?!

6.最终的DefaultEntityHelperCreateEntity函数

经过重重难关,我们终于找到了逻辑处理类是如何与实体对象绑定的,那就是DefaultEntityHelper的CreateEntity函数:



entityInstance即为实体对象,但这个对象是由框架底层创建,这个不是重点。

重点是最后一行代码,就是这一行代码,把Entity对象添加到了实体对象身上。

你以为这样就结束了吗?不,还有一步。(旁白:大家别拦着我!

7.最终终极真的是最后一个关键地方——Entity

我们先别激动,虽然我们已经知道了Entity会绑定到创建的实体对象(GameObject)上(旁白:不,我有点懵,我不知道,实体对象是什么?Entity又是什么?!)。

如果大家不是很明白实体对象和Entity的关系,那我举个简单的例子:在Unity的IDE里创建一个空的GameObject对象,然后把脚本Entity拖到这个对象身上。

这就是我所说的实体对象和Entity的关系了。

 

好,我们再回忆一下,EntityManager的ShowEntity函数做了哪些事情:
a.根据配置数据,创建实体(从预制体创建)

b.调用实体对象的OnInit、OnShow生命周期函数,这里会把第2步提到的最后一个参数(new ShowEntityInfo(entityLogicType, userData))传递回来
各位,对不起,其实之前说的第b步,是我瞎掰的,实际上并不是调用实体对象生命周期函数,而是调用实体对象所绑定的脚本(Entity)的生命周期函数。

 

EnityManager的ShowEntity函数,会执行下面的代码:



首先是调用了m_EntityHelper(在这里就是DefaultEntityHelper类)的CreateEntity函数,这个函数返回的并不是一个GameObject,而是一个IEntity类型,具体到DefaultEntityHelper的CreateEntity函数,就是返回Entity对象。

 

所以,准确的说法是,在EntityManage的ShowEntity执行的过程中,会调用Entity的生命周期函数。

好,这个是重点,也是我们这篇文章要做的第一步(旁白:我觉得我第一步要做的就是关掉这篇文章)。

 

接下来就是要看看Entity的OnInit函数做了什么事情了:



为了更清晰地看逻辑,我删掉了很多代码,留下了三个关键的地方。

Entity的OnInit函数基本上就做一件事情——把逻辑处理类绑定到实体对象身上。

至于逻辑处理类的类型,是在一开始就通过参数传递的(EntityExtension的ShowMyAircraft函数):

8.结束

至于MyAircraft做了什么事情,那就是我们自己的事情了,它就是处理逻辑的,想怎么处理是我们自己定的。

这个Demo里无非就是控制移动、发射子弹,只是做的封装比较多。

时间关系,我就不继续介绍了。

 

至此,Game Framework的Demo项目StarForce的介绍,到此为止。

希望这系列的文章能稍微让大家了解了Game Framework的基础思路。

可能Demo中还有很多框架的使用细节没有说到,但我个人也是没有实际使用过这个框架,所以不想太过细致地去研究这个Demo,我希望未来在使用的过程中再去了解更多细节。

 

有机会的话,我会用尽量少的封装写一个Demo,这样学习起来会更加方便。

嗯,有机会的话……旁白:所以为什么要用省略号,感觉完全没有机会的样子了!
15 条评论
  • 小学生 2023-07-31 18:52:45

    哎呦前面我还能看懂,现在咋感觉知识进不了我的脑子了
    0回复
    • 博主 笨木头 2023-08-01 13:56:49

      我的问题,内容太乱,写得不够清晰易懂
      0回复
      • 小学生 2023-08-02 10:43:32

        没有的事儿,GF相关的教程我看了几个,就木头大佬的写的有趣能看进去,别的太枯燥咯,然后还没你的思路清晰
        0回复
      • 小学生 2023-08-02 10:45:13

        哈哈,如果木头大佬专门开班教学,我觉得可能是个好老师,我初学者看完了都准备自己做个小游戏啦。
        0回复
        • 博主 笨木头 2023-08-03 09:13:28

          哈哈,谢谢认可,我都骄傲了
          0回复
  • longsl 2019-02-18 21:22:02

    木头大佬,请问IEntityManager这个接口类的具体实现在哪,全文都围绕这个接口类在说,我找了一圈只找到了这个https://ws1.sinaimg.cn/large/005EsThygy1g0aw3z3rjxj31bq03uaa2.jpg,新手 望赐教~ 另外我用的gameframework版本是3.1.8
    0回复
    • 博主 笨木头 2019-02-19 07:36:13

      EntityManager在GameFramework的源码里才有,你得下载源码才能看到咯:https://github.com/EllanJiang/GameFramework
      0回复
      • longsl 2019-02-19 12:11:03

        木头大佬,我能看到的IEntityManager接口类是在 UnityProject\StarForce\Assets\GameFramework\Libraries\GameFramework.dll 路径下的这个dll文件中,我没有找到这个接口类的实现类,我本地已经有GameFramework的源码啦,但是还是没找到,是我的方法有问题么?
        0回复
        • 博主 笨木头 2019-02-19 13:49:40

          嗯嗯,是的,你找的方法有问题,实现在这:https://github.com/EllanJiang/GameFramework/blob/master/GameFramework/Entity/EntityManager.cs

          至于m_EntityManager赋值,我没有深入去看,猫仙人有写过,你参考一下:https://blog.csdn.net/qq_32821435/article/details/80469985
          0回复
          • tom 2019-02-21 16:26:39

            你可以通过将dll文件拖入ilspy软件进行反编译找到
            0回复
      • longsl 2019-02-19 12:15:45

        另外,我没有找到文章中 “4.EntityManager的ShowEnity函数” 中所提到的EntityManager类,我看代码是在EntityComponent类中,直接通过“private IEntityManager m_EntityManager = null;“声明为IEntityManager接口类型,然后通过 “m_EntityManager = GameFrameworkEntry.GetModule(); “实例化,这里没有出现EntityManager类,btw 我应该是漏了什么,请木头指点下,谢谢~
        0回复
  • Ikobe 2018-04-28 10:28:05

    木头大佬。 cocos一直跟着你学。非常崇拜。。。 但是这个框架,看到这儿我已经要放弃了,“太复杂“”太臃肿了“(恕我愚昧),能简单点评下这个框架吗?
    0回复
    • 博主 笨木头 2018-04-28 15:21:47

      如果觉得Starforce解读很难懂的话,那是正常的,你可以跳过,直接从Demo教程开始看。
      框架作者把Starforce封装地很复杂,除了要理解框架的使用方式以外,还需要了解作者的开发思路,所以有点累。

      这个框架还是很不错的,不过不建议新手学习咯(不知道你是新手还是老手呢),新手直接学习怎么用Unity3D写游戏就可以了,学习框架还为时尚早。
      0回复
      • Ikobe 2018-05-02 12:23:37

        感谢木头大佬回复, 新手但是还算能看懂,只是没明白这样复杂封装的好处在哪儿。。。。
        0回复
        • 博主 笨木头 2018-05-02 12:37:07

          如果只是针对Starforce这种级别的项目,这个封装是没有什么好处的。

          但如果是实际开发的项目,这种封装还是有意义的(但也不是说100%就要按它来),就拿ShowEntity来说,如果不封装一下,那么在创建不同实体的时候会有很多看起来差不多的代码段,这样的代码段写多了,开发者自然会觉得不舒服。
          所以,这样的代码段通常都会封装起来,方便维护和修改。
          1回复
发表评论
粤ICP备16043700号

本博客基于 BlazorAnt Design Blazor 开发