开源游戏学习二 - OA.D.游戏引擎一览

简介:

Pyrogenesis 是OA.D.的游戏引擎。设计目标包括:跨平台、高效(3D图形的硬件加速)、好的扩展性(mods和脚本)。核心的引擎使用C++写的。但是,大部分高层游戏逻辑和用户借口是用js脚本实现的,这篇文档关注C++引擎这块。我们首先了解下游戏的“生命周期”和不同引擎组件直接的相互作用。然后我们提供每个引擎组件的预览。

游戏Session的生命周期

当你开始运行O A.D,游戏首先会载入binaries/data目录下一些纯文本文件的集合,类似有相同作用的zip压缩文件。虚拟文件系统(VFS)组件(lib/file中实现)使得不论压缩文件还是普通文件在游戏中看起来都是一样的文件对象。游戏加载完后,会显示一个主菜单。GUI引擎是gui组件实现的。它支持用XML定义一个GUI的页面并且用js来应答事件。这些文件在\binaries\data\mods\public\gui中。它通过使用C++组件暴露出的脚本函数与游戏进行交互。在主菜单中,玩家可以开始一个单人游戏、创建一个多人游戏,加入一个多人游戏。

游戏逻辑代码不论游戏是多人还是单人都是相同的工作原理 - 所有的不同就在于指令如何处理。在详细介绍如何建立多人游戏之前我们会介绍游戏逻辑代码如何组织。游戏逻辑在模拟组件中实现,特别是CSimulation,处理所有的更新。CEntity代表并且更新游戏中的对象(但愿,建筑物,等等)。在多人和单人游戏中,游戏状态是以轮来更新的(大概是0.1。每轮大概150毫秒。每一轮,对象都会移动到新的位置上,单元可能产生资源或者销毁(按照他们的产生速度),等等。每轮都在CSimulation::Update方法中处理,此外,在每轮之间,游戏中的图形对象以帧的速度通过插值在两个时间片之间快速连续的运动。这是通过CSimulation::Interpolate来完成的。会有一个CTurnManager的对象会设定什么时候是新时间片(模拟器每帧查询一次这个对象)。当游戏在运行的时候,玩家的指令(通过GUI得到的)使用CTurnManager::QueueLocalCommand。每个时间片,时间片管理器依照队列的先后提供一批指令给模拟组件。单人游戏和多人游戏的唯一不同在于使用哪个时间片管理器:多人玩家时间片管理器发送指令给主机,主机缓存一批指令然后广播给所有玩家,这样保证所有客户端得到相同批次的指令,保证他们的模拟组件步调一致。单人游戏的时间片管理器发送指令直接到模拟组件。所有的指令在执行之前都是验证狗的,来防止作弊。当AI实现后,AI将发送指令就像人玩家一样。


总结一下,游戏运行就像这样:

1、初始化

2、无限循环

检查当前时间

如果时间片管理器说该到新时间片了,调用CSimulation::Update

没到的话调用CSimulation::Interpolate

处理输入(队列化指令)

渲染新帧

大多数游戏逻辑在CEntity和它的相关脚本中(binaries/data/mods/official/entity_functions.js)和helper类文件中(像CEntityManager)。所有与玩家交互的对象是实体 - 包括单元、建筑物、树木、任何影响寻路的因素,等等。每个实体在游戏世界中用一个actor来表示 - 一个图形网格上连接了几个网格(类似于盾牌,武器,马之类的)。也有一部分不是实体,纯粹是装饰物,例如草叶或灌木,他们通过无实体的actor实现。actor的绘制和动画效果都是在图形包里处理的,包括加载OAD格式的网格和动画例如PMD、PSA。

每个实体有一个属性层级树和一系列用js写的的事件处理器。实体类型(例如不同的士兵类型)是用XML定义的。XML模版可以相互继承,因此,举个例子,所有持矛士兵可以继承template_infantry_spearman.xml的一些属性,但是 塞尔特and波斯 国家的持矛士兵可以通过定义celt_infantry_spearman.xml and pers_infantry_spearman.xml来实现不同。类似最大健康的属性可能在XML文件中可能这样实现:100并且将如traits.health.max一般可用js和C++访问。XML文件也会定义可以处理各个实体事件的脚本函数。例如,一个实体可能会选择选择性响应什么时候实体被毁灭。大多数需要实体做一些事情的指令用事件来实现。例如:如果一个单元有一个攻击速率为1次/2s的攻击,然后只要它试图攻击一个目标,它将会每2S得到一个"handle generic order"事件和一个attack动作,然后一个js函数将决定对这个目标造成了多少伤害。C++代码

你可能感兴趣的:(开源游戏)