引言
上篇我们讲到了UE在World之上,继续抽象出了Player的概念,包含了本地的ULocalPlayer和网络的UNetConnection,并以此创建出了World中的PlayerController,从而实现了不同的玩家模式策略。一路向上,依照设计里一个最朴素的原理:自己是无法创建管理自身的,所以Player也需要一个创建管理和存储的地方。另一方面,上文提到Player固然可以负责一些跟玩家相关的业务逻辑,但是对于World之上协调管理的逻辑却也仍然无处安放。
如果是有一定的游戏开发实战经验的朋友也一定能体会到,在自己开发的游戏中,往往除了我们上文提到的Player类,常常会创建一个Game类,比如BattleGame、WarGame或HappyGame等等。Game之前的名词往往都是游戏的开发代号。这倒不是因为我们如此热衷创建各种Manager类,而是确实需要一个大管家来干一些协调的活。一般的游戏引擎都只会暴露给你它自己引擎的管理类,如Director,Engine或Application之类的,但是却不会主动在Game类的创建管理上为你提供方便。游戏引擎的出现,最开始其实只是因为一些人发现游戏做着做着,有一大部分功能是可以复用的,于是就把它抽离了出来方便做下一款游戏。在那个时候,人们对游戏还是处于开荒探索的阶段,游戏引擎只是一大堆功能的复合体,就像叮当猫的口袋一样,互相比谁掏出的工具最强大。然而即使到了现代,绝大部分的引擎的思想却还停留在上个世纪,仍然执着于罗列Feature列表,却忘了真正的游戏开发人员天天面对的游戏业务逻辑编写,没有思考在那方面如何也下一番功夫去帮助开发者。人们对比UE和其他游戏引擎时,也会常常说出的一句话是:“别忘了Epic自己也是做游戏的”(虚幻竞技场,战争机器,无尽之剑……)。从这一点也可以看出,UE很大的得益于Epic实战游戏开发的反哺,这一方面Unity就有点吃亏了,没有自己亲自下手干脏活累活,就不懂得急人民群众之所急。所以如果一个游戏引擎能把GamePlay也做好了,那就不止是口袋了,而是知你懂你的叮当猫本身。
GameInstance
简单的事情就不用多讲了,UE提供的方案是一以贯之的,为我们提供了一个GameInstance类。为了受益于UObject的反射创建能力,直接继承于UObject,这样就可以依据一个Class直接动态创建出来具体的GameInstance子类。
我并不想罗列所有的接口,UGameInstance里的接口大概有4类:
- 引擎的初始化加载,Init和ShutDown等(在引擎流程章节会详细叙述)
- Player的创建,如CreateLocalPlayer,GetLocalPlayers之类的。
- GameMode的重载修改,这是从4.14新增加进来改进,本来你只能为特定的某个Map配置好GameModeClass,但是现在GameInstance允许你重载它的PreloadContentForURL、CreateGameModeForURL和OverrideGameModeClass方法来hook改变这一流程。
- OnlineSession的管理,这部分逻辑跟网络的机
