RPG游戏引擎的原理

游戏的具体制作

1.地图编辑器的制作

    RPG游戏往往要有大量的场景,场景中根据需要可以有草地,湖泊,树木,房屋,家具等道俱,由于一个游戏需要很多场景且地图越来越大,为了节省空间,提高图象文件的可重用性,RPG游戏的画面采用很多重复的单元(可以叫做“图块”)所构成的,这就要用到地图编辑器了。我们在制作游戏引擎前,要完成地图编辑器的制作。在 RPG游戏里,场景的构成,是图块排列顺序的记录。首先制定一个场景构成文件的格式,在这个文件里记录构成场景所需要的图块的排列顺序,因为我们已经为每个图块建立了索引,所以只需要记录这些索引就可以了。一个场景的构成,是分成几层来完成的:地面,建筑和植物,家具摆设,和在场景中活动的人物或者物体(比如飘扬的旗帜),按照一定的顺序把它们依次显示到屏幕上,就形成了一个丰富多采的场景。我们可以用数组来表示地图场景的生成过程。

MapData[X][Y]; //地图数据,X表示地图宽度,Y表示地图高度

Picture[num]; //道具的图片,num表示道具的总数

void MakeBackGround() //生成场景函数

{

int n;

for( int i=0; i<Y; i++) //共Y行

for( int j=0; j<X; j++) //共X列

{

n=MapData[ i ][ j ]; //取得该位置的道具编号

Draw( j*32, i*32, Picture[n]); //在此位置(j*32,i*32)画道具

}

}

2.游戏的模块的划分

    游戏按功能分为:消息处理系统、场景显示及行走系统、打斗系统三大主要部分。其中又以消息处理系统为核心模块,其余部分紧紧围绕它运行。

一:消息处理系统

    消息处理系统是游戏的核心部分。游戏用到的消息处理系统先等待消息,然后根据收到的消息转到相应的函数进行处理。比如:主角碰到敌人后,我们就让程序产生‘打斗消息',消息处理系统收到这个消息后就会马上转到打斗模块中去。消息处理的大体框架如下:

//定义程序中要用到的变量

DWORD Message; //消息变量

WinMain() //进入程序

{ 初始化主窗口;

初始化DirectDraw环境,并调入程序需要的图形、地图数据;

while( 1 ) //消息循环

{ switch( Message )

{ case 行走消息: 行走模块();

case 打斗消息: 打斗模块();

case 事件消息: 事件模块();

}

}

}
场景显示及行走系统

    作为RPG游戏,其所有事件的发生几乎都是和场景有关,例如:不同的地方会碰到不同的敌人、与不同的人对话得知不同的事情等。鉴于这部分的重要性,我们可再将它划分为:背景显示、行走 和 事件发生 三个子模块,分别处理各自的功能。下面进行具体分析。

(一)背景显示

    程序运行后,先读取前面地图编辑器制作的场景所需要的图块的排列顺序,按照排列顺序将图象拼成一个完整的场景,一般做法是:在内存中开辟一到两个屏幕缓存区,事先把即将显示的图象数据准备在缓存区内,然后一次性搬家:把它们传送到真正的屏幕缓冲区内。

    游戏用到的图片则事先制作好并存于另外的图形文件中。地图编辑器制作的场景文件仅仅是对应的数据,而不是真正的图片。在游戏中生成场景就是地图编辑的逆过程,一个是根据场景生成数据,而另一个是根据数据生成场景。

(二)行走

     要让主角在场景中行走,至少要有上、下、左、右四个行走方向,每个方向4幅图(站立、迈左腿、迈右腿、迈左腿),如图:游戏中一定要将图片的背景设为透明,这样在画人物的时候就不会覆盖上背景色了(这一技术DirectDraw中只要用SetColorKey()函数将原图片背景色过滤掉就行了)。我们让主角位置不动,而使场景移动,即采用滚屏技术来实现角色在场景上移动。这样角色一直保持在屏幕的正中间,需要做的工作只是根据行走方向和步伐不停变换图片而已。行走时的障碍物判断也是每一个场景中必定要有的,有一些道具如树木、房屋等是不可跨越的。对此我主要用一个二维数组来对应一个场景,每一个数组值代表场景的一小格(见图3)。有障碍的地方,该数组的对应值为1,可通过的地方的值为0。

(三)事件发生

     事件发生原理就是把相应事件的序号存储在地图的某些格子中,当主角一踏入这个格子就会触发对应事件。例如:在游戏开始时,主角是在他的家里。他要是想出去的话,就需要执行场景切换这个处理函数。我们假定该事件的编号为001,那么在地图上把家门外路口处的格子值设为001。这样主角走到路口时,编号为 001的场景切换函数就会被触发,于是主角便到了下一个场景中。程序具体如下:

void MessageLoop( int Msg ) //消息循环

{switch( Msg )

{char AddressName[16]; //数组AddressName[16]用来存储主角所在地点的名称

case ADDRESS == 001: // 由ADDRESS的值决定场景值(出门)

ScreenX=12; ScreenY=0; //初始化游戏背景位置

Hero.x=360; Hero.y=80;//主角坐标

Move();//主角移动函数

//以下程序用来显示主角所在地点

sprintf(AddressName,"下一幅游戏场景的名称");

PrintText(lpDDSPrimary, 280, 330,AddressName , RGB(255,255,255));//在屏幕上显示出场景的名称

break;}

}

三:打斗系统

    绝大多数的RPG都是有战斗存在的,因此,打斗系统就成为RPG系统中很重要的一环。有不少RPG游戏采用回合制打斗方式,因为实现起来较为简单。和打斗紧密相关的是升级,通常在一场战斗结束后,主角的经验值都会增加。而当经验值到达一定程度时,角色就升级了。