当前位置:文档之家› 一个RPG的游戏架构设计

一个RPG的游戏架构设计

一个RPG的游戏架构设计
本文将要展示一个RPG的游戏架构设计,这个架构是根据我的经验所设计出来的,目前还是一个雏形,由于我的经验不足,所以还有很多考虑不周的地方,现在还不具备实用价值。

本文所要讲述的框架包括一下几个模块:
1.游戏状态机管理模块。

2.世界管理模块。

3.资源管理模块。

4.渲染模块。

5.脚本模块。

6.输入处理模块。

(最后更新时间:05-2-24)
游戏状态机管理模块
整个游戏架构是基于状态机来运行的,游戏运行时的各种不同形式(比如用户自由控制时,脚本控制时,战斗时,对话时等)被划分为一个个的状态,任何时候都只有一个状态会被执行。

采用状态机的形式便于对游戏进行处理及扩展,新状态的加入以及状态之间的转换都很容易。

考虑到状态嵌套的情况(就是指当前状态未结束就暂时转入另一个状态,等新状态结束之后会返回来),所有的活动状态用一个栈来管理,任何时刻都只处理栈顶的状态。

状态机管理器的结构如下所示(只写出主要接口):
class CGSMManager{
void Update();
void Render();
void ClearStateStack();
void AddState(CGameState*);
};
说明:
void Update()
更新当前的GameState。

void Render()
渲染当前的GameState。

以上两个操作会在游戏每一帧被调用一次。

void ClearStateStack()
清除状态栈中的所有状态。

因为某些状态(比如游戏结束)须要将原先所有未结束的状态中止。

void AddState(CGameState*)
增加一个状态,将新状态压栈。

注意:新状态的对象必须是动态构建的,虽然是在外部建立的,但是此后该对象会完全交由状态机管理器管理(包括其销毁)。

游戏状态结构(只写出主要接口):
class CGameState{
CGameState(CGameState* pContextState);
bool Update();
void Render();
};
说明:
CGameState(CGameState* pContextState);
构造函数。

为了处理状态组合时的渲染问题,故需要得到相关的状态pContextState。

比如说在角色对话时就会这样,能够接收输入并作出处理的是角色对话框,但是当前的场景还是需要渲染的,所以在渲染时会先调用原状态的渲染操作来渲染场景。

bool Update();
更新本GameState。

void Render();
渲染此GameState。

资源管理模块
游戏资源,主要包括图片、音频、游戏相关的数据等,为了便于修改,所以将其独立出来,专门设立一个模块进行管理。

这里的主要思想是建立一个游戏实体与资源的对应关系的数据库。

在游戏中所有的对象都会被分配一个全局唯一的ID,该ID中包含了对象的类型信息。

根据ID 可以找到与该对象相对应的所有资源,再根据对象的相关信息即可找到具体要使用的资源。

(目前这个模块还没想到一个通用的设计,所以暂时不写)
∙渲染模块
渲染模块,负责游戏的渲染,包括视频和音频。

渲染器是跟游戏状态机的子状态相关联的,每一个游戏状态都有一个渲染器,负责该状态的渲染。

渲染器会读取关联的游戏状态所拥有的游戏对象的信息,根据这些信息从资源模块中获取相关的渲染资源,进行渲染。

注意资源的关联性,比如一个角色的某个动作,除了包括一组动画序列之外,还有相关的音效,渲染器除了会把动画渲染之外,还会将音效播放出来。

不同的游戏状态是可以共用同一个渲染器的,只要它们拥有的游戏实体是一样的。

(待续)
∙脚本运行机制
关于脚本解析器,叫黑马来写更合适一些,我这里只讲讲在我们的游戏里是怎么处理脚本的。

为了将游戏的剧情做得更加灵活,易于修改和调试,所以剧情需要用脚本来描写。

在我们这里的脚本是事件驱动的,框架会内置一些事件,同时允许用户自定义事件。

当某个事件被触发的时候,游戏就会转入脚本状态,执行跟该事件相关的一段脚本。

游戏脚本只是用于描述游戏剧情(这个是线性的),所以并没有多少复杂的语法,所有操作都基于框架所提供的库函数。

由于游戏是实时的,基于帧的,而脚本是非实时的,基于函数的,任何时候执行脚本,都是处于游戏的某一帧里的,而脚本里的一个语句(比如从A点走到B点)就可能需要游戏执行数帧才可完成。

为了解决这个矛盾,我们的脚本里只是一些描述性的语句,描述要做什么事情,但是并不会在这个函数调用里做,同时为了完成该指令的请求,需要先暂时将脚本解析器挂起,等待游戏运行N帧结束该动作之后,再接着解析下面的脚本。

整个执行过程如下所示:
while(脚本未结束) //每一帧会循环一次
{
if(当前没有脚本语句在执行)
解析一条语句(也可能是解析多条需要同时执行的语句);
执行当前的语句,完成一帧内的状态更新;
渲染当前帧的状态。

}
注意我们的脚本并不像一般的基于函数的设计的一样,一个函数内的语句会无间断的执行直到结束并且将所有的操作完成,正如上面所说,这种做法在基于帧的设计里是不现实的,因为大多数的脚本语句都是帧同步的操作。

相关主题