不知大家有没有注意到这一点:喜欢电脑的大都喜欢游戏。为什么呢?因为不管对男女老少来说,游戏都具有一种特殊的魅力,休闲的魅力、回味的魅力,或是竞争的魅力。但有时我也常常这样想,比如由于内存或者硬件的什么原因,游戏玩不起来,请来朋友帮忙调整,问题解决了,兴高采烈地继续玩,那么你什么也没学到。若是据此深入,刨根问底,从头到尾搞明白了,相信不久你就会成为电脑高手。何谓高手也都是平常磨练出来的。大家由爱游戏而尝试编游戏,也许有一天你会发觉虽然编程水平增长有限,但却不知不觉中精通了3DS或者COREL DRAW等软件,并能以另一个高度看待以前曾经模棱两可的操作系统概念,这就叫潜移默化。
那我们能编些什么游戏呢?QUAKE还是《AH-64D长弓阿帕奇》?这些恐怕许多专业编程人员也难以搞清楚其中的关键细节。我们不妨定得稍低一些,先从对速度、技巧要求较低的RPG、SLG开始,如果你有耐力、肯下苦功,再加上少许天赋与灵感,相信我们中间也能出一个Tom Hall,编出比QUAKE更酷的引擎程序。
(一)开篇
在高配置和软件极其丰富的今天,我想当年的《勇者斗恶龙》恐怕已很难再使玩家入迷了,从4色向16M真彩,从320×200转向1024×768的发展是大势所趋,那我们要如何来定位呢?以前介绍的16色只是给大家一个入门的简单练习,要想达到《炎龙骑士团Ⅱ》、《仙剑奇侠传》这样的养眼程度,256色是比较恰当的,有很多朋友会问:那么真彩呢?真彩固然好,但我们不妨作个比较,将一幅16M真彩图片经图象转换工具转换成256色后,两者相比除了光泽略减外,图像失真并不严重。只有动态的动画,如《银河飞将Ⅳ》的过场动画只有真彩(其实是64K色)才会显出真正的威力。不过,请大家有一点要记在心里,一个游戏的真正吸引力还在于内涵和创意,空有一副外壳是没有用的,象战斗画面绝不逊于《仙剑奇侠传》的《冥界幻姬》遭受失败即是一个例子。光就美工水平而论,同样是256色,制作的水准也有相当大的差异,有的甚至还不如16色。而16色中,做得好的也绝不逊于256色,象光荣的《三国志英杰传》在画面上就看不出哪点比智冠的《三国演义Ⅱ》差,好像还强些。游戏今后肯定向真彩发展,大家即使有了真彩的编程环境,美工仍是需要细致对待。
(二)色彩
颜色是物体的一个表面特征,对我们大多数人来说,并不能直接与光线打交道,我们看到的是色彩效果。当我们坐在屏幕前,使用一种工具产生、控制各种颜色,必须明白眼睛看到的颜色实际上是由颜料反射的光线。这在一开始可能会不太习惯,但在深入学习包括光线效果在内的美工技巧时,有必要首先理解颜料的色彩。
画家通过混合颜料来取得新的颜色,这种混合后能产生多种色彩变化效果的基色称为原色,它们是红、绿、蓝,譬如我们需要洋红,那就混合红和蓝,需要白色,就要混合等量的红、绿、蓝。现在我们来看看另外一种配色方案:即由RGB三基色互补而成的洋红色(MAGENTA)、雪青色(CYAN)、黄色(YELLOW)三色CYM模式。CYM模式的一个重要区别在于三基色混合在一起得到黑色而不是棕色,象通常我们接触的LCD液晶显示用的就是CYM方案。
色彩(HUE)就是通常所说的颜色。很多人可能会感到惊讶白、黑和灰也是无色彩的颜色,平常说的彩色即有色彩的颜色,而灰色则是彩色和黑的混合物,明白它们对理解电脑图像创作是很重要的。不同的颜色在视觉上会产生不同的效果,有些容易让人放松,有些使人惴惴不安,另有一些暗示着危险或安全,所有这些在编游戏时都要考虑进去。一件作品的好坏,也许和谐比华丽更重要,你不必一定要以一个艺术家的角度去绘制那些游戏画面,但在游戏出品前,先听听其他人的意见是个不错的主意,如果这些色彩使他们厌烦,那我想在你的作品正式推出前会是件好事。
在PC机中,以标准VGA来说,R、G、B的亮度(即色彩深浅)各分为2^6(64)等分,一共需要18个位来表示,白色即(63,63,63),这种方法共能显示2^6×2^6×2^6(256K)种颜色。对于SVGA真彩,由于每种颜色用8位来表示,所以共可显示出2^8×2^8×2^8(16M)种颜色。
VGA/SVGA卡中负责颜色输出的是RAM DAC(DIGTALTO ANALOG CONVERTOR)。VGA卡将8位的输入数字信号经一个颜色对照表和DAC的转换后,由模拟信号线输出到屏幕上。虽然颜色对照表中每个字段可有256K种颜色变化,但因输入信号只有256种,所以屏幕上最多只能同时显示256色,也就是说每次从256K种颜色中选出256种来显示。SVGA卡中DAC芯片必须使用16位(32K、64K)的或24位(16M)的输入接口,对这些芯片来说,输入的信号就是真实的色值,所以只要按RGB格式转换即可。由于采用的数据传输接口位数增加,所以在速度上可以提高不少,当然SVGA卡上的集成化和一些加速设置也功不可没。在绘图模式下,这类卡提供硬件光标功能,减轻了CPU负担。
(三)显示模式
VGA的绘图模式中,最重要的是模式12和模式13(我想大部分玩家手上已经没有CGA、EGA显示卡了吧)。模式12H采用平面式对应的方法,支持640×480,视频内存起始地址为A0000H,和其它D、E、10H三种模式一样同为16色,只是分辨率有所不同。视频内存地址上,每一个字节代表8个像素,每一位又可对应到颜色平面中同样位置的4位上。当我们要在屏幕上绘出一个点时,就必须将数据分别存放到四个颜色平面中对应的位上。VGA提供了许多存取颜色平面数据的方法,如一次存取4个颜色平面数据或每次只对单一平面操作,哪种方法比较快呢?如果是图像方面的处理,选择第二种较理想;而对于画点方式的作图,第一种更快速一些。
模式13H是VGA卡中唯一可同显256的模式,支持分辨率320×200,视频内存起始地址A0000H,它采用的是线性对应的方法(SVGA的所有256色和真彩都是用这种方法)。线性对应将屏幕上每一点与视频内存地址按顺序一一对应起来,一个点对应一个字节,这样做的好处是:这种对应方式比颜色平面对应方式简单多了,因为我们只需直接对视频内存地址做存取即可,而不必理会颜色平面与内存地址的对应关系。大家不难看出,其实线性对应就是将四个颜色平面的内存串联在一起,而成为一种直线的排列。
13H的初始化编码,《大众软件》今年第一期中黄明朋友已经给出,如果大家用的是TURBOC,也可以这样写:
[NO.1]
setup-graph() /* VGA 13h 模式初始化 */
{
union REGS r;
r.h.ah=0;
r.h.al=0×13;
int86(0x10,&r,&r);
}
close-graph() /* 关闭 VGA 13h 图形系统 */
{
union REGS r;
r.h.ah=0x00;
r.h.al=0x03;
int86(0x10,&r,&r);
}
SVGA由于要存取更高分辨率或更多颜色的数据,一般都至少拥有512K以上的内存,但其所占用视频内存的地址仍大都是64K。在内存地址发生不够用的情况下,SVGA的区域切换功能将整个内存划分为许多内存页,然后利用切换功能把不同的内存页对应到A0000H或其它的视频内存地址上。但目前各个厂家的SVGA卡规格都不一样,切换内存页的方法也不尽相同,而且有些显示卡上还设有两个切换开关,这是我们需要注意的。
下面我们来看看SVGA的图形初始化例程:
[NO.2]
#include
int huge Return-SVGA256(void)
{
return(0); /* 返回各种分辨率的对应编号 0~6
0) Standard VGA/MCGA 320×200×256
1) 256K Svga/VESA 640×400×256
2) 512K Svga/VESA 640×480×256
3) 512K Svga/VESA 800×600×256
4) 1024K Svga/VESA 1024×768×256
5) 256K Svga 640×350×256
6) 1280K以上 VESA 1280×1024×256 */
}
void setup-svga256(void) /* SVGA 256色模式初始化 */
{
int gm,driver = DETECT;
installuserdriver(“svga256”,Return-SVGA256);
initgraph(&driver,&gm?);
}
void main()
{
setup-svga256();
setcolor(2);
circle(100,100,50);
getch();
closegraph();
}
大家只要把SVGA的图形接口程序 SVGA256.BGI拷入C的系统程序目录中编译即可,为什么呢?因为这个驱动程序当然不会是BORLAND公司的产品。这样做的一个好处是:让还没有图形库子函数编程经验的朋友可以直接利用TURBO C图形库(GRAPHICS.LIB)嵌入文件GRAPHICS.H中定义的各种绘图函数。
这个SVGA图形驱动程序效果不错,也能支持大多数的SVGA卡,象ATI、Trident、Tseng等,由于SVGA卡兼容规格的局限性,笔者在一些卡上也碰到了一些问题,如9440卡不支持5号模式,5428卡则不支持1号、5号模式,但不管哪种类型的卡,都支持0号和2号模式。
(四)函数和优化
如果大家仔细观看TURBO C下的系统目录,就可以发现很多 *.BGI文件。TURBO C图形系统可分为与机器无关的图形库(GRAPHICS.LIB)和以文件形式存在于磁盘上的字体库(*.CHR)、图形设备驱动程序(*.BGI)。BGI即Borland Graphics Interface的缩写,是美国BORLAND公司编出的一套通用图形接口,如EGAVGA.BGI为 EGA/VGA卡的驱动程序。这是个通过建立功能函数库而使编程者能在图形处理上独立于各类显示系统的办法,但出于兼容性的考虑是以牺牲速度作为补偿的,而且它也不支持SVGA卡关键的256色或真彩显示,虽然早期的许多游戏(甚至包括一些射击游戏)确实都是在这些驱动程序上编写的,但对于现今速度上要求极高的、特别是三维游戏无疑是不现实的。一个最好的办法就是自行编写高效的图形原码,从画点做起,进而扩充需要的整个图形库。有的朋友可能会说:“象RPG中画几条菜单框框慢不了多少时间吧。”但如果卷轴平移呢?640×480×256是个什么样的量级概念!就算慢不了多少,你为什么不能使它更快呢?
画点是很重要的一步,几乎所有的图形函数都是以它为基础,下面我为大家提供一个适合于各种分辨率下的高效画点原编码:
[NO.3]
#include
void point(int x,int y,char color)
{
unsigned put;
put=y*320+x; /* 分辨率为320*200,若为其他分辨率请换算相应的系数 */
*((char far *)(0×A0000000L)+put)=color;
}
大家在创建自己的功能函数库的同时,必须注意一些速度上的编程技巧:1.避免乘法和除法,这是相当浪费CPU时间的一种运算,求余数也应该尽可能避免。2.多使用整数,少用浮点数,双精度那就更慢了。3.减少读取磁盘文件的操作,一次读取多量的方式比少量数据的多次读取要快很多。4.使用Register定义变量,寄存器的速度甚至比内存还快。5.这会是经常犯的毛病,尽量将费时的运算移到循环外进行。
另外,画图子函数在算法上有些需要区别考虑,象斜线的Bresenham算法、填充的优化算法等,这些请大家翻阅相关的数学算法程序书籍。还有呢?那当然是汇编了,汇编是种较难维护的语言,有汇编程序经验的朋友可以尝试一些嵌入汇编码的方法,需要注意的是对汇编语言不同的C编译程序规定了不同的调用规则。在TURBO C中用修饰符cdecl说明的函数或不加说明的函数按照从右向左的顺序将参数压入堆栈,即给定调用函数(a,b,c)后,a最先进栈,然后是b和c。进入汇编编码过程后,寄存器BP内容必须存在堆栈中,当前栈指针SP的值存入BP,如果子程序用SI和DI,唯一必存的寄存器为SI和DI,从汇编语言子程序返回之前,必须恢复BP、SI和DI,并重新设置堆栈指针。
最后一种办法,实在缺少函数编程经验的朋友可以通过Internet下载一些支持VGA/SVGA的高效图形函数库,这些可是现成可以用的,翻阅README可找到详尽的函数定义说明。“我一定要用Borland的驱动程序作画!”那我也不反对,也许明年786就要出来了(笑话)。