现代游戏引擎 - 如何构建游戏世界(三)
前言
如何让游戏世界活动起来
游戏对象类型
- 现代游戏中的对象通常分为:动态物体、静态物体、地形系统以及其它物件。
- 为了统一游戏中对象,我们通常会用GameObject来指代游戏中的所有对象。
游戏对象功能组织
以面向对象的思维,一个游戏对象由属性和行为组成。 但游戏中的对象十分复杂,通过水陆两栖坦克继承车还是船的案例表达难以清晰得区分继承关系。
游戏引擎中通常使用组件化的方式,抽离行为逻辑,使得游戏对象的设计更加方便。通过接口、组合的方法更加符合人的直觉。
基于组件化的思想,我们通常会抽象出一个ComponentBase,不同组件实现基类的方法,所有组件由统一的外部管理对象调用。
装备不同功能的组件实现不同的无人机
- 在游戏世界中,一切都是一个GameObject对象
- 游戏对象可以以基于组件的方式来描述
逻辑何时执行
Tick的方式:
- 基于对象为基础的Tick
- 基于组件为基础的Tick
现代游戏引擎中通常不是按照GameObject来执行Tick,而是根据功能系统。这样能够处理连续内存数据,效率更高。(类似ECS思路)
对象通讯
想想这样一个场景:一辆坦克被炮弹击中,坦克爆炸需要对周围单位造成伤害。
一种处理方案是,找到坦克周围的对象,依次处理受击逻辑。
这样的处理方式对于复杂的游戏来说,难以阅读维护成本很高。
通常会使用event机制来解耦这些逻辑:坦克发出爆炸消息,受影响的对象自己接受消息,并执行逻辑。相当于把事件解耦成发生和处理。
如何管理游戏对象
游戏对象是处于游戏场景中的,游戏对象通过唯一id来进行识别:unique ID(uid),游戏对象处于特定位置。
继续上述的例子,当坦克发生爆炸时,所有接收到事件的对象都会进行处理。但游戏场景中存在大量对象时,
这样的处理方式难以适用(每个游戏对象都可能和其它游戏对象互动,此时算法复杂度为n^2)。
因此就需要根据游戏对象在场景中的分布进行管理,以优化场景对象的查找。
简单的场景可以通过画格子的方式处理。
常见场景对象数据结构:二分树、四叉树(八叉树)、BVH。游戏引擎一般实现多种算法供上层开发选择。
其他需要处理的负责情况(时序问题)
不同系统之间可能相互影响,出现循环依赖。比如人在行走时,踢到一块石头,触发物理系统,同时反过来影响动画系统。此时就会涉及到逻辑处理的时序问题。
现代引擎是在多核CPU上行执行的,也可能出现两个对象相互影响,出现时序问题。
例子:引入一个邮局,通过将事件发送到邮局统一处理后分发到对应GO处理(通常的处理方式是引入第三方,隔帧处理)
引用
- 本文作者:樱白 - Cherry White
- 本文链接:https://cherry-white.github.io/posts/4d443f2a.html
- 版权声明:本博客所有文章均采用 BY-NC-SA 许可协议,转载请注明出处!