如何编制RPG游戏(下)
现在,我们的精灵已能自由运动,且能识别障碍了,它活动的动画环境可以取自一些图形数据文件。这些文件是事先用各种编辑软件编辑好,之后保存于硬盘上,以便随时调入。在VGA卡上可设多个有效图形页,程序可直接将图形输出到一个关闭屏幕页,然后通过调用setvisualpage改变为可见页,可快速显示关闭屏幕图形。
但如果你的背景画面不是很复杂的话,一个更简便的方法便是即时画图。
在RPG游戏中,有很多东西是重复的,象树、山脉、房子、草地,这些我们可以称为图形单元,将每个图形单元编制出来放在一个函数中,那么绘一幅背景场地无非是反复调用这些函数。例如树木单元可以是由椭圆和长条组成:
void tree (int x,int y)
setColor(2);
fillellipse(x,y,10,15); /* 椭圆 */
setfillstyle(1,6);
bar(x-2,y+10,x+2,y+18); /* 长条 */
比较而言,房屋单元就稍微复杂些,整幅背景图形可用一个二维数组标识,存放图形序号和特征点(如门、宝箱)地址。在主程序调用这些背景函数时一定要小心谨慎,这里往往是游戏BUG产生的地方(象《侠客英雄传》中有时就会碰到进入特征点(门)后背景混乱的现象),要注意特征点和序号,序号和序号之间的对应。
六.中文环境:
在编制中文RPG及其它类型的中文游戏时,无可避免地会碰到与中文环境有关的一些问题。例如:在游戏编程中能否直接用现成的中文系统(UCDOS、中国龙等)支撑?
如果你的游戏是建立在文本模式下的话,这个问题不大,象现在有些商业化的应用软件的确是自己不带中文环境的。但这种情况对我们的图形模式游戏来说是不适合的。
使用外挂的中文支撑系统,占用内存很大,而且会与图形模式的部分功能冲突(如屏幕色彩与西文状态下的色彩 不一致),使得游戏程序根本无法运行或运行中经常死机。我们通常采用的是西文下显示汉字的技术。
一种通用的方法是为开发的软件编制小字库。若要更简单的话,直接调用现成字库也是可以的。例:UCDOS或213汉字系统中16×16点阵的字库文件是HZK16;24×24点阵字库分别为HZK24S(宋体)、HZK24K(楷体)、HZK24H(黑体)。在24点阵字库中我向大家推荐楷体,这种字形非常美观,接近商业化的要求。
有关西文下显示汉字的例子鉴于各类书刊上极多,这里不再重复,只想对其作出一些勘误:
16×16点阵:
c1=(i-0xal)&0x07f;
c2=(i-0xal)&0x07f;
rec=(c1-23)*94+c2-23;
24×24点阵:
c1=(i-0xa0)&0x07f;
c2=(i-0xa0)&0x07f;
rec=(c1-16)*94+c2-1;
七.游戏菜单:
游戏中中文菜单是必不可少的,简单一点的有对话框、信息框,稍复杂的有弹出式指令菜单及其子菜单(物品栏、状态栏等)。
这些菜单分别可以由第三花?所介绍的热键激活。例如用空格键激活对话框,用回车键激活指令菜单,上下键选择子菜单,ESC退回游戏。
指令菜单往往被设计成一个弹出并显示的窗口,选择项在窗口中垂直排列,而被选中的项为高亮,反显中文,后开的窗口常要覆盖屏幕上原来的部分内容,窗口消失后,又要将覆盖的内容再现出来。要实现这一点,就必须在覆盖之前将要覆盖区域的内容保护起来,称为保存屏幕;窗口消失后,再将保护的那块屏幕拿出来补上,称为恢复屏幕。在TURBO C中要用到这样一组函数:
void far getimage (int left,int top,int right,int bottom,void far *bitmap);
unsigned far imagesize (int left,int top,int right, int bottor, voidfar *bitmap);
void far putimage (int left,int top,void far *bitmap,int op);
imagesize 决定getimage用于保存指定矩形所需的字节数,它返回的图象大小包括用于记录矩形宽和高的空间。
getimage将屏幕上一个矩形区域的位图像存到内存中,(left,top)和(right,bottom) 四个参数用于定义屏幕上的矩形,bitmap指向内存中存放位图像的区域。
putimage将以前用getimage保存的位图像重新送回屏幕,图像的左上角位于(left,right),bitmap 指向保存源图像的内存区域,参数op指明了一个组合:COPY_PUT拷贝,XOR_PUT异或, OR_PUT或,AND_PUT与,NOT_PUT取反拷贝。
了解以上函数后,我们用一个详细的例程来说明如何实现西文状态下菜单系统的编制:
/* 状态栏 */
setcolor(14); /* 设置当前绘图色为黄颜色 */
setlinestyle(0,0xff00,3); /* 设置线型为粗实线 */
/* 画一个左上角为(10,125)右下角为(100,255)的矩形 */
setlinestyle(0,0xff00,1); /* 设置线型为细实线 */
rectangle(14,129,96,251);
setfillstyle(8,2); /* 设置绿色斜网格的填充模式 */
bar(17,132,93,249);
/* 画一个左上角为(17,132)右下角为(93,249) 的矩形并填充 */
p24(25,137,0,14,"状态");
/* 在点(25,137)处输出楷体汉字,字间距为0,颜色为白色 */
p24(25,163,0,14,"法力");
p24(25,189,0,14,"物品");
p24(25,215,0,14,"系统");
size2=imagesize(17,137,93,163);
/* 保存屏幕上矩形(17,137)(93,163)所需的字节数 */
buf2=malloc(size2);
getimage(17,137,93,163,buf2);
/* 将所定义的矩形区域(17,137)(93,163)的位图像保存至内存 */
putimage(17,137,buf2,NOT_PUT);
/* 将getimage保存的位图像反显送回屏幕,达到当前选项高亮效果 */
cdy=137;ky1=0;
while(ky1!=27) /* 检查是否按下ESC键 */
while(bioskey(1)==0); /* 等待操作者击键 */
ky1=ky2=bioskey(0);
ky1=ky1&0xff;
ky2=ky2&0xff?0:ky2>>8; /* 将组成扩展扫描码的两部分分开 */
if(ky2==72||ky2==80) /* 判断是否为上下键 */
putimage(17,cdy,buf2,COPY_PUT);
/* 将getimage保存的位图像反显送回屏幕,取消当前选项高亮效果 */
if(ky2==72) cdy=cdy==137?215:cdy-26;
/* 键入上键,若cdy=137则取215,反之cdy值减26,26为选项所占高度 */
if(ky2==80) cdy=cdy==215?137:cdy+26;
/* 键入下键,若cdy=215则取137,反之cdy值加26 */
getimage(17,cdy,93,cdy+26,buf2);
/* 将所定义的矩形区域(17,cdy)(93,cdy+26)的位图像保存至内存 */
putimage(17,cdy,buf2,NOT_PUT);
/* 将getimage保存的位图像反显送回屏幕,达到当前选项高亮效果 */
test1=(cdy-137)/26+1; /* test1 菜单行号代码 */
if(ky1==13) /* 检查是否按下回车键 */
switch(test1)
case 1: /* 此处插入状态栏子程序 */
break;
case 2:
break;
case 3:
break;
case 4:
break;
free (buf2); /* 释放buf2所指向的内存空间 */
至于对话框、信息框等因为是单一菜单,就相对简单些了,运用图形函数可设计出具有专业效果的窗口,具体见所附例程。
八.精灵动画:
也许大家已注意到了我们在上面所说的动画程序产生的精灵本身形状是不变的,还达不到动画片的效果。因为一个精灵无论外形多么逼真,但如果在跑动时既不提手也不抬腿,那么效果便会大打折扣。解决这个问题最好的办法是再建立一个或更多的精灵组,让它们在精灵运动时轮流显示,由于人的视觉暂留现象,就给人一种连续运动的感觉。
由于精灵在四个方向上移动形状各不相同,所以至少要建立8个精灵组。用一个二维数组bj[i][j]标识,i表示方向序号,j表示运动序号,显示时对j进行循环累加,产生精灵的动画效果。
九.战斗系统:
RPG游戏中战斗系统的地位至关重要,它的好坏直接影响游戏的可操作性和可玩性。现在市面上的游戏,有些战斗系统极其复杂,特别象一些S-RPG类游戏,有些则很简单,象日式传统RPG。战斗系统是游戏的灵魂,它留给设计者的自由度是很大的,但它的好与坏并不取决于简与繁,而取决于另外许多东西:象参数设计合理性、键盘鼠标操作的易上手性、战斗手段多样化等等,甚至包括敌人出现的频繁程度。至于简繁问题,繁是专门为发烧级玩友准备,简则留予入门级朋友消谴,这是由设计者的出发点决定。
从传统RPG的角度来说,主角通常由手无缚鸡之力的0级成长为顶级英雄。在各个活动区域注意敌人的强弱分布,不妨将强弱档次拉开,增加游戏的难度及在同一区域活动的适应性。
在攻防方面,为了避免出现敌人打不死的情况,注意要设置较低的敌人防御值。敌人的攻击力应跟着自己的防御值调整,使主角等级提升到一定程度不惧怕一类敌人的进攻,增加玩者的成就感。损血可以这样计算:
Hp损=K(己方攻击力-对方攻击力)
K值根据设计者采用的Hp总值来定,通常所说的会心一击或致命一击即将K值调为三至五倍。在损血计算之前,还应加入闪避、常态及致命一击的随机频率计算。
十.DEMO及过场动画:
很多朋友可能都被PC游戏中优秀的片头动画震惊过。其实,这些动画几乎都是由各种各样的应用软件包制作、调整,再联接到主程序,而并非由编程直接完成。同样我们也可以借3DS、ANIMATOR、CORELDRAW的威力制作出满意的、甚至超越市面中很多游戏水准的动画、图片来融入我们自己编制的游戏之中。
我们有幸拥有这样一个函数system(),system可启动MS-DOS comMAND.COM文件去执行 command字符串中给出的命令,即使命令输入在DOS提示行。如system("C: \ GAME\ TITLE.EXE"); 表示调用C盘GAME目录下的TITLE.EXE片头动画可执行文件。 在上例引号中也可是一个批命令或带参数命令。又如system ("C:\GAME\PLAYMVY TITLE.FLI"); 即一个常见的调用FLI、FLC格式动画文件的方法。
【注】在引用system命令之前,一定要先关闭不相容的图形模式,以免冲突死机。
十一.SLG类游戏引申及总体制作:
以上我们介绍了一个RPG类中文游戏简便的制作方法,对引擎作稍许修改,我们也可以制作中文战棋SLG类游戏。在战棋类GAME中主角不是RPG中的一个(RPG中三四个其实也仅相当于一个),而是变成敌我双方的若干个。每一个主角都会在各自的时间段中独立思考运动。运动时除了受阻障碍外,还有影响障碍,即地表性质影响速度。行动原则(敌方自由运动的主角):2)魔法师检查攻击范围内有无敌人,若有使用魔法;僧侣检查医疗范围内有无己方损血人员,若有进行治疗;战士检查攻击范围内有无敌兵,若有转入攻击等级最低者或Hp值最小者。2)各自攻击范围内无敌人,检查搜索范围内有无敌人,若有,向等级最低或Hp值最小方向移动。3)检查地面,改变运动步长(攻击时检查地面,改变攻防参数)。将主角编入数组循环,可制作出《魔法世纪》式的战棋游戏。
纵观目前众多的游戏,大家不难看出一个成功的游戏不光要有优秀的画面和流畅的界面,更要有一个引人入胜的剧情,九五年大宇的《仙剑奇侠传》便是一个典型的例子。挑选一个合适的主题,编写理想的情节在游戏制作中无疑极其重要。自从声卡面市以来,音乐音效所占的份量也日趋受到瞩目(限于篇幅,有关声卡、声霸卡编程方面的问题我们以后有机会再谈),而在RPG类游戏中,尤以音乐为重。正因为一个完整游戏涉及的面很多且很杂,所以游戏BUG是在所难免的(笔者在新出的《新蜀山剑侠传》中同样发现了若干个臭虫),制作公司对成功的游戏一般都会接着推出除BUG版。
那么我们按以上方法制作出的RPG游戏效果如何呢?我可以告诉大家,比《勇者斗恶龙》强,和《侠客英雄传》差不多。我们何不动手试一试,编出你的第一个中文RPG游戏!
想了解更多?