《如何编制RPG游戏上下 .doc》由会员分享,可在线阅读,更多相关《如何编制RPG游戏上下 .doc(10页珍藏版)》请在三一办公上搜索。
1、一套游戏,其中包含的内容很多,涉及了编程技巧的方方面面。本文力求从简便的角度出发介绍类游戏的制作,只要你有一点语言的基础,就可以按部就班编出一个游戏来,若对没有一点概念,那么正好趁此机会学习一下,体会体会当代最实用的编程语言。考虑到现在及各种版本的普及情况,在此拟采用Turbo C 2.0为例,逐一介绍这方面的具体知识。 一浅说: 在正式进入游戏编程前,我们先来谈谈有关屏幕管理的几个有趣的问题。计算机显示器的工作方式有两种:正文方式和图形方式,在每种显示方式下还可分为不同的显示模式。对于我们的来说,她的处理对象主要是图形,所以我们需要采用后一种显示方式。 在Turbo C中initgraph是
2、一个初始化图形系统的有用函数,它从磁盘装入一个图形驱动程序,且把系统置成图形方式。除了这种动态装入机制外,也可以将一个或几个图形驱动程序文件直接同可执行程序文件连接起来。游戏中通常采用的是640480或320200的分辨率。让我们来看看一个子程序: setupgraph() /* 图形初始化 */ int driver=VGA,mode=VGAHI; /* VGA卡的VGAHI图形模式,640*480同显16色 */ initgraph(&driver,&mode,); /* 使用空字符串 表示设备驱动程序在当前目录中 */ 这个程序装入的图形驱动程序文件为EGAVGA.BGI,在例程中我们也
3、将采用这种640480的模式进行编程。若想选用其他分辩率,只需改变driver和mode的值便可。 下面我们来谈谈有关调色板的应用。 对于VGA显示器,图形模式12H(640480,16色)共设置了16个颜色寄存器,所以显示器上能同时最多显示16种颜色。系统初始化时,也将颜色寄存器予以初始化,若这种默认颜色值不满足要求的话,只需修改相应颜色寄存器的数据,就可实现从64种颜色中任意选取,使显示的图形更加美观。 setpalette(调色板号,颜色号)函数可将指定的颜色填入指定的调色板中,从而改变调色板上的默认颜色。例如: setpalette (1,4); 用该函数重新设置后,以后使用1号调色板
4、时,则显示4号颜色红色。 【注】有效的颜色依赖于当前的图形驱动程序和当前的图形模式,该函数不可用于IBM-8514图形驱动程序,应使用setrgbpalette函数。 VGA的13H模式是320200点阵的彩色图形模式,同显256色。在图形初始化完成后,我们就可以进入富有挑战的游戏编程了。 二制作精灵:在游戏中,有很多能根据不同规则和目的而在背景场地跑来跑去的小目标:象城镇里的居民,野地上的小动物,或者再加上几株会动的小树,当然了,还有最重要的主角游戏中的英雄或淘气鬼。这些小角色我们通常称之为“精灵”。 这些精灵要在各自的场地上迅速移动,当它们在草地上跑动时,经过的地方要遮住背景,而当它们经过
5、后,背景的草地又要迅速恢复回来,若是遇到房屋、小河、岩石,就要停下来。那么,这些是如何实现的呢? 在程序中实现精灵的移动,我们通常采用这样的方法:在屏幕上擦除精灵当前的位置,然后在下一个位置进行重显依次循环,你就会感到精灵跑动起来。这个原理是很简单的,但重要的是:擦掉并重显的速度必须足够快,才能有活生生的效果。 构成图形的最基本要素是点,无论背景也好,精灵也好,都是由许许多多的点组成的,所以精灵的重显问题其实也就是擦点画点的问题。在屏幕上画点有两种方法,一种是使用ROM BIOS调用,另一种是直接写显示RAM。这两种方法比较而言,前一种是相当慢的,而后一种极快。正因为如此,我们不能通过ROM
6、BIOS去画点,而必须采用直接写显示RAM的办法画点。精灵在背景画面上保持动态最好的办法是通过XOR(“逻辑异或”)运算,借助XOR操作,动态精灵在同一显示位置上连续进行两次XOR运算,使画面出现和消失,而不会导致背景画面的任何损坏,我们来看例程:void putpoint (int x,int y,int color) union REGS r; color=color|128; /* 参数color 和 128相逻辑或,置位最高位 */ r.h.bh=0; r.h.ah=12; r.h.al=color; r.x.dx=y; r.x.cx=x; int86(0x10,&r,&r); 这个画
7、点程序采取直接写显示RAM的办法,在画每一个点时, 先让彩色值与值128进行逻辑“或”,使彩色值的位7为1,(这就告诉了函数不是以新彩色值替换原彩色值,而是与原彩色值进行逻辑“异或”)。所以这个点总是可见的. 因为它总是与周围其它点颜色不一样,而连续两次XOR运算又很容易使周围曾经被它占据的点恢复成被占据前的颜色。 在解决了画点问题后,只要把组成精灵的点归入一个集合,使这些点同时进行运动,那么,精灵的问题也就解决了。 精灵的造型设计是丰富多彩的, 你尽可以凭你的想象创造出要在游戏中出现的形态各异的人和其它各种角色。我们可以借助Animator pro来完成角色设计,如果精灵不是很复杂的话,我们
8、甚至可以直接“点”出她们:打开Spt或Windows的画笔,我们在“逐点修改”的方格阵上点绘出精灵的造型,反复修改至满意,给精灵定个外框,在四角任取一个点作为参照坐标(X,Y),以(X,Y)为参数组成精灵集合man(int x,int y): void man(int x,int y) putpoint(x+dx1,y+dy1,color); . putpoint(x+dxn,y+dyn,color); 一般来说,精灵应比较小,以便加快重显速度,使移动看起来比较平滑。若精灵太大,移动起来就比较慢。在例程中,我们用一个912的框代替精灵: void man(int x,int y,int col
9、or) int i; for (i=0;i9;i+) putpoint(x+i,y,color); putpoint(x+i,y+12,color); for (i=0;i12;i+) putpoint(x,y+i,color); putpoint(x+9,y+i,color); 返回页首 三键盘控制: 在游戏中,主角的移动一般是由上、下、左、右键或HOME、END、PGUP、PGDN四键控制的,此处还有几个问题:若键入空格、回车等,计算机如何识别?在游戏的中文菜单中如何用上下键移动选择光条?这些都是在游戏编程中会碰到的典型问题。 在Turbo C中,我们用bioskey (int cs)函数
10、来获取键盘字符。这个函数使用BIOS中断0x14完成各种键盘操作,参数cs确定实际的操作:cs=0,返回从键盘输入的下一键码;cs=1,测试输入键是否有效;cs=2,请求当前移位键(SHIFT)的状态。 bioskey(0)获得所击键的扩展的扫描码。扩展的扫描码分两部分,即扫描码和ASC码。当按键是一般ASC码时,如回车、空格、ESC键,从扩展扫描码的低字节中可以得到它的ASC码值;当按键是特殊键时,如上、下、END、HOME键,其ASC码部分为0,所以要将组成扩展扫描码的两部分分开: do key.i=bioskey(0); if(key.ch0) switch(tolower(key.ch
11、0) case : 程序一 /* 空格键 */ case r: 程序二 /* 回车键 */ else switch(key.ch1) case 72: 程序三 /* 上键 */ case 80: 程序四 /* 下键 */ case 75: 程序五 /* 左键 */ case 77: 程序六 /* 右键 */ while(tolower(key.ch0!=27); /* ESC键 */ key.ch0中为ASC码部分,key.ch1为扫描码部分。ESC键为ASC字符键,键值为27,所以上面程序最后一行表示当按键不是ESC时,就一直循环。而由于上、下、左、右键为特殊键,所以判别是否按了这些键用sw
12、itch(key.ch1)。 【注】常用键码 HOME: 71 F1-F10: 59-68 END: 79 ALT+(F1-F10): 104-113 PAGE UP: 73 SHIFT+(F1-F10): 84-93 PAGE DOWN: 81 返回页首 四边界识别:让我们再回到第二节所讨论的问题:游戏中精灵的跑动是有限制的,它不能越过墙壁、树林、山脉、河流等,同样也不能超越背景的最大最小边界(这时往往会切换到另一幅背景中去),这些都是属于边界问题或者说障碍识别。 对后一类问题,有时我们可以凭借屏幕的(X,Y)边界值来识别;但一旦遇到前一种目标较多的情况时,这种算法无疑是极繁琐的,可能会使速
13、度明显下降,最糟糕的是它要对动态装入的每一块新的动画场地都要重新设置。 很明显,我们经常要采用的是另一类算法,只有对特定的少数目标,如宝藏隐藏点,或旅店、武器店的门,可以用(X,Y)定值来判别。在游戏中,颜色是具有不同含义的。我们可以定义树林的绿色、河流的蓝色、墙壁的土黄色为不可逾越的边界,那么只要检查一下精灵周围各点的颜色有没有这些颜色就可以了。 我们要用到一个很有用的函数getpixel(x,y),它能取得位于(X,Y)处像素点的颜色。在游戏中,主角移动的每一步叫步长,每走一步前,检查下一步步长范围内的像素点中有没有预先定义的颜色,若有,则原地踏步。在实际编程中,其实无需比较全部像素点,只
14、要检查一下下一步长边缘的、三点就可以了。在例程中仍检查了全部点: case 72: /* 上 */ for(j=0;j=9;j+) for(jj=0;jjwinys) /* winys 屏幕 y轴起始点,通常为 0 */ if(colorbz1!=1) y-=increment; colorbz1=0; /* 标志清零 */ break; 五背景处理: 现在,我们的精灵已能自由运动,且能识别障碍了,它活动的动画环境可以取自一些图形数据文件。这些文件是事先用各种编辑软件编辑好,之后保存于硬盘上,以便随时调入。在卡上可设多个有效图形页,程序可直接将图形输出到一个关闭屏幕页,然后通过调用setvis
15、ualpage改变为可见页,可快速显示关闭屏幕图形。但如果你的背景画面不是很复杂的话,一个更简便的方法便是即时画图。 在RPG游戏中,有很多东西是重复的,象树、山脉、房子、草地,这些我们可以称为图形单元,将每个图形单元编制出来放在一个函数中,那么绘一幅背景场地无非是反复调用这些函数。例如树木单元可以是由椭圆和长条组成: void tree (int x,int y) setcolor(2); setfillstyle(1,10); fillellipse(x,y,10,15); /* 椭圆 */ setfillstyle(1,6); bar(x-2,y+10,x+2,y+18); /* 长条
16、*/ 比较而言,房屋单元就稍微复杂些,整幅背景图形可用一个二维数组标识,存放图形序号和特征点(如门、宝箱)地址。在主程序调用这些背景函数时一定要小心谨慎,这里往往是游戏产生的地方(象侠客英雄传中有时就会碰到进入特征点(门)后背景混乱的现象),要注意特征点和序号,序号和序号之间的对应。 六.中文环境: 在编制中文RPG及其它类型的中文游戏时,无可避免地会碰到与中文环境有关的一些问题。例如:在游戏编程中能否直接用现成的中文系统(UCDOS、中国龙等)支撑? 如果你的游戏是建立在文本模式下的话,这个问题不大,象现在有些商业化的应用软件的确是自己不带中文环境的。但这种情况对我们的图形模式游戏来说是不适
17、合的。 使用外挂的中文支撑系统,占用内存很大,而且会与图形模式的部分功能冲突(如屏幕色彩与西文状态下的色彩不一致),使得游戏程序根本无法运行或运行中经常死机。我们通常采用的是西文下显示汉字的技术。 一种通用的方法是为开发的软件编制小字库。若要更简单的话,直接调用现成字库也是可以的。例:UCDOS或213汉字系统中1616点阵的字库文件是HZK16;2424点阵字库分别为HZK24S(宋体)、HZK24K(楷体)、HZK24H(黑体)。在24点阵字库中我向大家推荐楷体,这种字形非常美观,接近商业化的要求。 有关西文下显示汉字的例子鉴于各类书刊上极多,这里不再重复,只想对其作出一些勘误: 1616
18、点阵: c1=(i-0xal)&0x07f; : c2=(i-0xal)&0x07f; : rec=(c1-23)*94+c2-23; 2424点阵: c1=(i-0xa0)&0x07f; : c2=(i-0xa0)&0x07f; : rec=(c1-16)*94+c2-1; 七.游戏菜单: 游戏中中文菜单是必不可少的,简单一点的有对话框、信息框,稍复杂的有弹出式指令菜单及其子菜单(物品栏、状态栏等)。 这些菜单分别可以由第三节所介绍的热键激活。例如用空格键激活对话框,用回车键激活指令菜单,上下键选择子菜单,ESC退回游戏。 指令菜单往往被设计成一个弹出并显示的窗口,选择项在窗口中垂直排列,而
19、被选中的项为高亮,反显中文,后开的窗口常要覆盖屏幕上原来的部分内容,窗口消失后,又要将覆盖的内容再现出来。要实现这一点,就必须在覆盖之前将要覆盖区域的内容保护起来,称为保存屏幕;窗口消失后,再将保护的那块屏幕拿出来补上,称为恢复屏幕。在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
20、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拷贝
21、,XOR_PUT异或, OR_PUT或,AND_PUT与,NOT_PUT取反拷贝。 了解以上函数后,我们用一个详细的例程来说明如何实现西文状态下菜单系统的编制: /* 状态栏 */ setcolor(14); /* 设置当前绘图色为黄颜色 */ setlinestyle(0,0xff00,3); /* 设置线型为粗实线 */ rectangle(10,125,100,255); /* 画一个左上角为(10,125)右下角为(100,255)的矩形 */ setlinestyle(0,0xff00,1); /* 设置线型为细实线 */ rectangle(14,129,96,251); setf
22、illstyle(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
23、); 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:ky28; /* 将组成扩展扫描码的两部分分开 *
24、/ 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); /* 将所定义的矩形区
25、域(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所指向的内存空间 */ 至于对话
26、框、信息框等因为是单一菜单,就相对简单些了,运用图形函数可设计出具有专业效果的窗口,具体见所附例程。 八.精灵动画: 也许大家已注意到了我们在上面所说的动画程序产生的精灵本身形状是不变的,还达不到动画片的效果。因为一个精灵无论外形多么逼真,但如果在跑动时既不提手也不抬腿,那么效果便会大打折扣。解决这个问题最好的办法是再建立一个或更多的精灵组,让它们在精灵运动时轮流显示,由于人的视觉暂留现象,就给人一种连续运动的感觉。 由于精灵在四个方向上移动形状各不相同,所以至少要建立个精灵组。用一个二维数组bjij标识,i表示方向序号,表示运动序号,显示时对进行循环累加,产生精灵的动画效果。 九.战斗系统:
27、 RPG游戏中战斗系统的地位至关重要,它的好坏直接影响游戏的可操作性和可玩性。现在市面上的游戏,有些战斗系统极其复杂,特别象一些S-RPG类游戏,有些则很简单,象日式传统RPG。战斗系统是游戏的灵魂,它留给设计者的自由度是很大的,但它的好与坏并不取决于简与繁,而取决于另外许多东西:象参数设计合理性、键盘鼠标操作的易上手性、战斗手段多样化等等,甚至包括敌人出现的频繁程度。至于简繁问题,繁是专门为发烧级玩友准备,简则留予入门级朋友消谴,这是由设计者的出发点决定。 从传统RPG的角度来说,主角通常由手无缚鸡之力的级成长为顶级英雄。在各个活动区域注意敌人的强弱分布,不妨将强弱档次拉开,增加游戏的难度及
28、在同一区域活动的适应性。 在攻防方面,为了避免出现敌人打不死的情况,注意要设置较低的敌人防御值。敌人的攻击力应跟着自己的防御值调整,使主角等级提升到一定程度不惧怕一类敌人的进攻,增加玩者的成就感。损血可以这样计算: Hp损K(己方攻击力对方攻击力) K值根据设计者采用的Hp总值来定,通常所说的会心一击或致命一击即将K值调为三至五倍。在损血计算之前,还应加入闪避、常态及致命一击的随机频率计算。 十.DEMO及过场动画: 很多朋友可能都被PC游戏中优秀的片头动画震惊过。其实,这些动画几乎都是由各种各样的应用软件包制作、调整,再联接到主程序,而并非由编程直接完成。同样我们也可以借3DS、ANIMAT
29、OR、CORELDRAW的威力制作出满意的、甚至超越市面中很多游戏水准的动画、图片来融入我们自己编制的游戏之中。 我们有幸拥有这样一个函数system(),system可启动MS-DOS COMMAND.COM文件去执行 command字符串中给出的命令,即使命令输入在DOS提示行。如system(C: GAME TITLE.EXE); 表示调用C盘GAME目录下的TITLE.EXE片头动画可执行文件。 在上例引号中也可是一个批命令或带参数命令。又如system (C:GAMEPLAYMVY TITLE.FLI); 即一个常见的调用FLI、FLC格式动画文件的方法。 【注】在引用system命
30、令之前,一定要先关闭不相容的图形模式,以免冲突死机。 十一.SLG类游戏引申及总体制作: 以上我们介绍了一个RPG类中文游戏简便的制作方法,对引擎作稍许修改,我们也可以制作中文战棋SLG类游戏。在战棋类GAME中主角不是RPG中的一个(RPG中三四个其实也仅相当于一个),而是变成敌我双方的若干个。每一个主角都会在各自的时间段中独立思考运动。运动时除了受阻障碍外,还有影响障碍,即地表性质影响速度。行动原则(敌方自由运动的主角):2)魔法师检查攻击范围内有无敌人,若有使用魔法;僧侣检查医疗范围内有无己方损血人员,若有进行治疗;战士检查攻击范围内有无敌兵,若有转入攻击等级最低者或Hp值最小者。2)各
31、自攻击范围内无敌人,检查搜索范围内有无敌人,若有,向等级最低或Hp值最小方向移动。3)检查地面,改变运动步长(攻击时检查地面,改变攻防参数)。将主角编入数组循环,可制作出魔法世纪式的战棋游戏。 纵观目前众多的游戏,大家不难看出一个成功的游戏不光要有优秀的画面和流畅的界面,更要有一个引人入胜的剧情,九五年大宇的仙剑奇侠传便是一个典型的例子。挑选一个合适的主题,编写理想的情节在游戏制作中无疑极其重要。自从声卡面市以来,音乐音效所占的份量也日趋受到瞩目(限于篇幅,有关声卡、声霸卡编程方面的问题我们以后有机会再谈),而在RPG类游戏中,尤以音乐为重。正因为一个完整游戏涉及的面很多且很杂,所以游戏BUG是在所难免的(笔者在新出的新蜀山剑侠传中同样发现了若干个臭虫),制作公司对成功的游戏一般都会接着推出除BUG版。 那么我们按以上方法制作出的RPG游戏效果如何呢?我可以告诉大家,比勇者斗恶龙强,和侠客英雄传差不多。我们何不动手试一试,编出你的第一个中文RPG游戏!