zhigu 发表于 2006-12-4 18:16:00

DOS游戏编程二十一条

<!--Element not supported - Type: 8 Name: #comment--><table cellspacing="0" cellpadding="0" width="760" align="center" border="0"><tbody><tr><td align="center" background="/Skin/chinadv/top_Path_mid.gif" colspan="2" height="21"><script language="JavaScript1.2" src="/yxzz/JS/ShowClass_Menu.js" type="text/JavaScript"></script></td></tr></tbody></table><table cellspacing="0" cellpadding="0" width="760" align="center" border="0"><tbody><tr><!--Element not supported - Type: 8 Name: #comment--><td align="center"></td></tr></tbody></table><!--Element not supported - Type: 8 Name: #comment--><!--Element not supported - Type: 8 Name: #comment--><!--Element not supported - Type: 8 Name: #comment--><!--Element not supported - Type: 8 Name: #comment--><!--Element not supported - Type: 8 Name: #comment--><table class="center_tdbgall" cellspacing="0" cellpadding="0" width="760" align="center" border="0"><tbody><tr><td valign="top" width="6"><img height="4" width="6" alt=""/></td><td class="main_tdbgall" valign="top" width="748"><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td width="10"><img height="8" src="http://www.game798.com/bbs/" width="10" alt=""/></td><td width="728"><img height="8" src="http://www.game798.com/bbs/" alt=""/>&nbsp;<table class="main_box1" cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr valign="middle" align="center"><td class="main_ArticleTitle" colspan="2" style="WORD-BREAK: break-all;">DOS游戏编程二十一条</td></tr><tr valign="middle" align="center"><td class="main_ArticleSubheading" colspan="2" style="WORD-BREAK: break-all;"></td></tr><tr align="center"><td colspan="2"></td></tr><tr><td class="main_tdcon_760" id="fontzoom" valign="top" colspan="2" height="300" style="WORD-BREAK: break-all;"><span id="lblContent">我在一家游戏公司多年,现就自己的编程经验谈一点体会,希望能对大家有点帮助,本文中所有例子均在WATCOM C/C++ 10.6下调试通过。<br/><br/>1、找一种好的编程语言:<br/>当然,游戏可以用任何语言编写,这是可以肯定的,我就使用过Turbo Basic编写过跑马机游戏,还用VB写过一个半成品的网络拱猪游戏,但是,一个好的编程语言能够达到好的效果,这是毋庸置疑的。一个游戏程序员,梦寐以求的就是一个方便、完美、高速的语言。<br/>汇编是一种高速语言,但不够方便,如果要方便,就必须大量使用宏,笔者就曾经在6502汇编语言中大量使用FOR,NEXT,PRINT等语句,全部是宏,但是相应的内存开销,时间开销都加大了,不划算。<br/>WATCOM C/C++是一种好语言,可以访问大内存,速度快,也够方便,但是调试不够方便,只能用自己写的调试函数解决问题。还有每次运行必须调用DOS/4GW这个32位环境程序,既累赘又不方便,还占地方。<br/>MSC7.0也不错,通过它的虚拟内存机制也可以访问大内存,但可惜是16位仿真的,速度太慢。<br/>DJGPP也是很不错,关键它是共享的,同时还带有一个Alleg的共享游戏库,非常好用,推荐使用,但它生成的程序代码太大,不够优化。<br/>作为游戏程序员,我们追求的就是快一点、快一点、再快一点,如果还有更快的语言,希望大家介绍给我。<br/><br/>2、要写专有程序,不要写通用的,通用,意味着慢,哪怕下次重新来过,也不能为了下次耽误这次。同理,凡是系统给你的函数,调用,要有坚决不用的思想准备,要自己写一套。<br/><br/>3、写出来的程序,每秒钟必须刷屏70次以上,再通过时钟限制在30次(不抖),剩下的时间,就是运行你的游戏程序内容的时间,算一算,不多。<br/><br/>4、要有引擎的概念,引擎包含系统底层的程序,数据结构,调用方法等,这些直接限制你以后的游戏好不好编,一般说来,我们做一个游戏半年时间,其中两个月编引擎,两个月编游戏,剩下两个月调试,可见引擎的重要。永远记着,你写的程序,就计算机而言,就是在搬数,把一堆数据提出来,处理一下搬到另外一块地方,就这么简单,那么,搬数的方法有多重要,你知道了吧。 5、尽量少用乘除法、浮点数,必要时使用移位乘法。这里给一个移位乘法的例子,大家可以参考:<br/>/*-------------------------------------------------------------------------------*/<br/>//XiaoGe Made under WATCOM C/C++ 10.6<br/>/*-------------------------------------------------------------------------------*/<br/>int count_offest(int _width,int x,int y) //移位乘法计算显示偏移值<br/>{<br/>int mode={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536};<br/>int i,offest=0;<br/>for (i=16;i&gt;=0;i--)<br/>{<br/>if (_width&gt;=mode)<br/>{<br/>offest+=(y&lt;&lt;i);<br/>_width-=mode;<br/>if (_width&lt;1) break;<br/>}<br/>}<br/>return(offest+x);<br/>}<br/>/*-------------------------------------------------------------------------------*/<br/>结果=屏幕宽度*y+x。(这仅仅是一个移位乘法的例子,真正用时,要根据具体情况选择使用)<br/><br/>6、没人会用数学描述去写一幅游戏图形,所有的图形都来自于美工画的PCX,BMP图形,去找一个美工,或者偷一批图形吧。读写PCX,BMP的函数是必须的。<br/><br/>7、游戏程序员语录:给我一个画点函数吧,我能描绘出整个世界。任何时候下,一个最高速的画点程序都是必要的,这里给出一个例子(没有乘法的):<br/>/*-------------------------------------------------------------------------------*/<br/>//XiaoGe Made under WATCOM C/C++ 10.6<br/>/*-------------------------------------------------------------------------------*/<br/>void point(int x,int y,unsigned char color) //高速画点<br/>{<br/>if ((color!=NO_COLOR)&amp;&amp;<br/>(x&gt;=0)&amp;&amp;(x&lt;SCR_H)&amp;&amp;<br/>(y&gt;=0)&amp;&amp;(y&lt;SCR_V))<br/>{<br/>#ifdef VESA_320_200<br/>*(buffer+(y&lt;&lt;8)+(y&lt;&lt;6)+x)=color;<br/>#endif<br/>#ifdef VESA_640_480<br/>*(buffer+(y&lt;&lt;9)+(y&lt;&lt;7)+x)=color;<br/>#endif<br/>#ifdef VESA_800_600<br/>*(buffer+(y&lt;&lt;9)+(y&lt;&lt;8)+(y&lt;&lt;5)+x)=color;<br/>#endif<br/>#ifdef VESA_1024_768<br/>*(buffer+(y&lt;&lt;10)+x)=color;<br/>#endif<br/>#ifdef VESA_1280_1024<br/>*(buffer+(y&lt;&lt;10)+(y&lt;&lt;8)+x)=color;<br/>#endif<br/>}<br/>}<br/>/*-------------------------------------------------------------------------------*/<br/><br/>8、镂空算法很多,用的都是AND MASK+OR方式,不要去理它,每一个点要处理两遍,包含三次读内存,两次逻辑运算,一次写内存,太慢了,在你的颜色中规定一种透明色,画点时不去管它就行了(上例)。记住,每个点上少处理一次,你至少可以多跳一圈舞。<br/><br/>9、双缓冲是必要的,但也不全是,很多教课书上把双缓冲作为消除屏幕闪烁的唯一方法,这不对,因为只要跟踪了屏幕刷新周期,就不会闪,双缓冲直接带来的就是你的程序画点必须画两次,一次向buffer,另一次重buffer搬到屏幕。我在做优化时,往往首先把双缓冲优化掉。没必要浪费时间,就算有点闪,游戏是可以牺牲效果,换取时间的。这里给一个跟踪屏幕刷新周期的函数,只要在你的刷屏程序前加上,效果基本上就可以了。<br/>/*-------------------------------------------------------------------------------*/<br/>//XiaoGe Made under WATCOM C/C++ 10.6<br/>/*-------------------------------------------------------------------------------*/<br/>void wait (void) //VGA屏幕刷新周期的测试<br/>{<br/>while (inp(0x3DA)&amp;0x08);<br/>while (!(inp(0x3DA)&amp;0x08));<br/>}<br/>/*-------------------------------------------------------------------------------*/<br/><br/>10、刷屏程序应该包含:背景屏幕刷新、精灵动画刷新、鼠标处理、键盘处理等,并且,每秒钟必须能运行70次以上,如果做不到,优化你的程序。<br/><br/>11、优化是必须的,一个游戏引擎,至少应该优化7-10次,我的一个引擎,就优化了14次,速度从每秒钟12.1屏到70屏。还有,不要使用编译器的优化,除非你想你的用户无法使用你的程序。 12、计算你的每一步使用了几步操作,这一点在C中尤其重要,因为C太方便了,隐瞒了很多细节,如下例:<br/>从 *(Video+k)=*(p+j);<br/>k++;<br/>到 *(Video+(k++))=*(p+j); //减少了一次k读内存操作<br/>到 *(Video+(k++))=*(*(p+1)+j); //减少了把p转化成数组操作<br/><br/>13、减少循环,循环中多开销了一次累加(读写内存),一次比较(读内存+1次逻辑),如下例:<br/>从 for (i=0;i&lt;10000;i++)<br/>{<br/>*(p+i)=0;<br/>}<br/>到 for (i=0;i&lt;10000;i+=10) //循环次数减少9000次<br/>{<br/>*(p+i+0)=0;<br/>*(p+i+1)=0;<br/>*(p+i+2)=0;<br/>*(p+i+3)=0;<br/>*(p+i+4)=0;<br/>*(p+i+5)=0;<br/>*(p+i+6)=0;<br/>*(p+i+7)=0;<br/>*(p+i+8)=0;<br/>*(p+i+9)=0;<br/>}<br/>到 for (i=0;i&lt;10000;i+=10) //20次读变量内存减少为12次读,1次写<br/>{<br/>j=p+i;<br/>*(j+0)=0;<br/>*(j+1)=0;<br/>*(j+2)=0;<br/>*(j+3)=0;<br/>*(j+4)=0;<br/>*(j+5)=0;<br/>*(j+6)=0;<br/>*(j+7)=0;<br/>*(j+8)=0;<br/>*(j+9)=0;<br/>}<br/>到 for (i=0;i&lt;10000;i+=10) //10次读值内存减少为1次,其余为寄存器变量<br/>{<br/>j=p+i;<br/>*(j+0)=*(j+1)=*(j+2)=*(j+3)=*(j+4)=*(j+5)=*(j+6)=*(j+7)=*(j+8)=*(j+9)=0;<br/>}<br/>当然,如果允许,可以写10000个,不过也没必要,减掉一多半就行了。关键在速度和程序容量上达成平衡。另外,DO...WHILE比FOR和WHILE要少一次逻辑比较。<br/><br/>14、具体的说,处理一个图块时,很多人采用x,y两重循环,这是很值得研究的,根据屏幕特点,应该只保留y循环,x方向直接线性累加处理即可。<br/><br/>15、不要节约判断语句,它可能给你带来多一条语句的开销,但是却可能减少几百条语句的开销,1赔100,赌了。<br/><br/>16、别给自己找病,养成良好的书写习惯,让编译程序为你检查错误,如下例:<br/>if (i==1) <br/>写成 if (i=1) 编译不出错,但意思错了<br/>写成 if (1=i) 编译就出错,可以检查出来<br/><br/>17、游戏程序没有主循环,主循环往往只是包含刷屏的一个死循环,更多的东东放在时钟里头,要熟练拦截时钟,改变它的频率,你的画面就会动得流畅、自然。下面是一个拦截时钟的例子,因为采用时钟循环,所以必须大量使用switch/case结构,要有思想准备。<br/><br/>/*-------------------------------------------------------------------------------*/<br/>//XiaoGe Made under WATCOM C/C++ 10.6<br/>/*-------------------------------------------------------------------------------*/<br/>#define TIME_KEEPER_INT 0x1c<br/>long timer_counter;<br/>void (_interrupt far *Old_Time_Isr)();<br/>void timer_program(void);<br/>////////////////////////////////////////////////////////////////<br/>//注意:中断函数中不能调用系统输入输出函数,应尽量使用自己的程序<br/>void _interrupt Timer(void)<br/>{<br/>timer_program(); //调用用户程序<br/>timer_counter++;<br/>Old_Time_Isr();<br/>}<br/>////////////////////////////////////////////////////////////////<br/>#define CTRL_8253 0x43<br/>#define CTRL_WORD 0x3c<br/>#define COUNTER_0 0x40<br/>#define COUNTER_1 0x41<br/>#define COUNTER_2 0x42<br/>#define LOW_BYTE(n) (n&amp;0x00ff)<br/>#define HI_BYTE(n) ((n&gt;&gt;8)&amp;0x00ff)<br/><br/>#define TIME_18HZ 0xFFFF<br/>//改变定时器频率函数<br/>//注意:超过1000Hz,与Windows将发生冲突<br/>void Change_Timer(unsigned short new_count)<br/>{<br/>outp(CTRL_8253,CTRL_WORD);<br/>outp(COUNTER_0,LOW_BYTE(new_count));<br/>outp(COUNTER_0,HI_BYTE(new_count));<br/>}<br/>////////////////////////////////////////////////////////////////<br/>//安装时钟<br/>void install_timer(int Hz)<br/>{<br/>short time_hz;<br/>time_hz=short(1193180/Hz);<br/>timer_counter=0;<br/>Change_Timer(time_hz);<br/>Old_Time_Isr=_dos_getvect(TIME_KEEPER_INT);<br/>_dos_setvect(TIME_KEEPER_INT,Timer);<br/>}<br/>////////////////////////////////////////////////////////////////<br/>//卸载时钟<br/>void uninstall_timer()<br/>{<br/>Change_Timer(TIME_18HZ);<br/>_dos_setvect(TIME_KEEPER_INT,Old_Time_Isr);<br/>}<br/>////////////////////////////////////////////////////////////////<br/>/*-------------------------------------------------------------------------------*/<br/><br/>18、不要去相信mouse程序会为你做到一切,去读0x33的状态,光标由自己显示,否则,哼哼......<br/>例子:<br/>/*-------------------------------------------------------------------------------*/<br/>//XiaoGe Made under WATCOM C/C++ 10.6<br/>/*-------------------------------------------------------------------------------*/<br/>unsigned short cursor[] =<br/>{<br/>0x0000, /*0000000000000000*/ /* 16 words of cursor mask */<br/>0x4000, /*0100000000000000*/<br/>0x6000, /*0110000000000000*/<br/>0x7000, /*0111000000000000*/<br/>0x7800, /*0111100000000000*/<br/>0x7c00, /*0111110000000000*/<br/>0x7e00, /*0111111000000000*/<br/>0x7f00, /*0111111100000000*/<br/>0x7c00, /*0111110000000000*/<br/>0x4600, /*0100011000000000*/<br/>0x0600, /*0000011000000000*/<br/>0x0300, /*0000001100000000*/<br/>0x0300, /*0000001100000000*/<br/>0x0180, /*0000000110000000*/<br/>0x0180, /*0000000110000000*/<br/>0x00c0, /*0000000011000000*/<br/>};<br/>struct Mouse<br/>{<br/>char show; //mouse 光标显示/不显示<br/>char left; //mouse左键<br/>char right //mouse右键<br/>char middle; //mouse中键<br/>int x; //mouseX坐标<br/>int y; //mouseY坐标<br/>unsigned char color; //mouse光标颜色<br/>}mouse;<br/>int mouse_page;<br/>/*-------------------------------------------------------------------------------*/<br/>void set_mouse_xy(int x_min,int x_max,int y_min,int y_max)<br/>{<br/>REGS regs;<br/>if (x_min&lt;0) x_min=0;<br/>if (x_max&gt;SCR_H) x_max=SCR_H;<br/>if (y_min&lt;0) y_min=0;<br/>if (y_max&gt;SCR_V) y_max=SCR_V;<br/>//Define H min-max<br/>regs.w.ax=0x07;<br/>regs.w.cx=x_min;<br/>regs.w.dx=x_max;<br/>int386(0x33,&amp;regs,&amp;regs);<br/>//Define V min-max<br/>regs.w.ax=0x08;<br/>regs.w.cx=y_min;<br/>regs.w.dx=y_max;<br/>int386(0x33,&amp;regs,&amp;regs);<br/>//POSITION MOUSE CURSOR<br/>regs.w.ax=0x04;<br/>regs.w.cx=(x_max-x_min)&gt;&gt;1;<br/>regs.w.dx=(y_max-y_min)&gt;&gt;1;<br/>int386(0x33,&amp;regs,&amp;regs);<br/>}<br/>/*-------------------------------------------------------------------------------*/<br/>void init_mouse(void)<br/>{<br/>REGS regs;<br/>mouse.x=SCR_H/2;<br/>mouse.y=SCR_V/2;<br/>mouse.left=0;<br/>mouse.right=0;<br/>mouse.middle=0;<br/>mouse.color=255;<br/>mouse.show=0;<br/>//mouse reset<br/>regs.w.ax=0x00;<br/>int386(0x33,&amp;regs,&amp;regs);<br/>//old mouse hidden<br/>regs.w.ax=0x01;<br/>int386(0x33,&amp;regs,&amp;regs);<br/>set_mouse_xy(0,SCR_H,0,SCR_V);<br/>//Define Mic/Piexl<br/>regs.w.ax=0x0F;<br/>regs.w.cx=4;<br/>regs.w.dx=4;<br/>int386(0x33,&amp;regs,&amp;regs);<br/>}<br/>/*-------------------------------------------------------------------------------*/<br/>void hard_disp_mouse(void)<br/>{<br/>int i,j,x,y;<br/>long addr,addr1,page;<br/>unsigned short temp;<br/>unsigned char color;<br/>unsigned int b[]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};<br/>unsigned char *video=(unsigned char *)0xA0000;<br/><br/>color=mouse.color;<br/>y=mouse.y-1;<br/>addr=count_offest(SCR_H,mouse.x,mouse.y);<br/>mouse_page=addr&gt;&gt;16;<br/>set_page(mouse_page);<br/>for(i=0;i&lt;16;i++)<br/>{<br/>x=mouse.x-1;<br/>temp=cursor;<br/>addr=count_offest(SCR_H,x,y);<br/>for(j=16;j&gt;=0;j--)<br/>{<br/>if((b&amp;temp)&amp;&amp;(x&gt;0)&amp;&amp;(x&lt;SCR_H)&amp;&amp;(y&gt;0)&amp;&amp;(y&lt;SCR_V))<br/>{<br/>page=addr&gt;&gt;16;<br/>addr1=addr-(page&lt;&lt;16);<br/>if (mouse_page!=page)<br/>{<br/>mouse_page=page;<br/>set_page(mouse_page);<br/>}<br/>*(video+addr1)=color;<br/>*(buffer+addr)=color;<br/>}<br/>x++;<br/>addr++;<br/>}<br/>y++;<br/>}<br/>}<br/>/*-------------------------------------------------------------------------------*/<br/>void read_mouse(void)<br/>{<br/><br/>REGS in,out;<br/>mouse.color=255;<br/>in.w.ax=0x03;<br/>int386(0x33,&amp;in,&amp;out);<br/>mouse.left=(out.w.bx&amp;0x01);<br/>mouse.right=(out.w.bx&amp;0x02);<br/>mouse.middle=(out.w.bx&amp;0x04);<br/><br/>mouse.x=out.w.cx;<br/>if (0&gt;mouse.x) mouse.x=0;<br/>if (SCR_H&lt;mouse.x) mouse.x=SCR_H;<br/>mouse.y=out.w.dx;<br/>if (0&gt;mouse.y) mouse.y=0;<br/>if (SCR_V&lt;mouse.y) mouse.y=SCR_V;<br/>if (mouse.show) hard_disp_mouse();<br/>}<br/>/*-------------------------------------------------------------------------------*/<br/><br/>19、键盘操作要拦截键盘中断,可不能用系统给的函数,游戏程序员戒条:凡是系统给的,必然是不合用的。下面是例子。使用时,在你的循环中直接监测key_ascii就行了。<br/>/*-------------------------------------------------------------------------------*/<br/>#define SCAN_ALT 56<br/>#define SCAN_CTRL 29<br/>#define SCAN_caps 58<br/>#define SCAN_LEFTSHIFT 42<br/>#define SCAN_RIGHTSHIFT 54<br/>#define SCAN_SHIFT (keyflag||keyflag)<br/>#define KEY_END 255<br/>#define KEY_LEFT 254<br/>#define KEY_RIGHT 253<br/>#define KEY_PAGEUP 252<br/>#define KEY_UP 251<br/>#define KEY_DOWN 250<br/>#define KEY_HOME 249<br/>#define KEY_CTRLBREAK 248<br/>#define KEY_F1 247<br/>#define KEY_F2 246<br/>#define KEY_F3 245<br/>#define KEY_F4 244<br/>#define KEY_F5 243<br/>#define KEY_F6 242<br/>#define KEY_F7 241<br/>#define KEY_F8 240<br/>#define KEY_F9 239<br/>#define KEY_F10 238<br/>#define KEY_PAGEDOWN 237<br/>#define KEY_INSERT 236<br/>#define KEY_DELETE 235<br/>#define KEY_LEFTALT 234<br/>#define KEY_RIGHTALT 233<br/>#define KEY_RIGHTCTRL 232<br/>#define KEY_LEFTCTRL 231<br/>#define KEY_caps 230<br/>#define KEY_F11 229<br/>#define KEY_F12 228<br/>#define KEY_PRINTSCREEN 228<br/>#define KEY_NUMLOCK 227<br/>#define KEY_SCROLLLOCK 226<br/>#define KEY_LEFTSHIFT 225<br/>#define KEY_RIGHTSHIFT 224<br/>#define KEY_WINDOWS 223<br/>/*-------------------------------------------------------------------------------*/<br/>static unsigned char asciinames[]={<br/>0,27,1,2,3,4,5,6,7,8,9,0,-,=,8,9,<br/>q,w,e,r,t,y,u,i,o,p,[,],13,KEY_LEFTCTRL,a,s,<br/>d,f,g,h,j,k,l,;,39,`,0,92,z,x,c,v,<br/>b,n,m,,,.,/,0,*,KEY_LEFTALT, ,KEY_caps,KEY_F1,KEY_F2,KEY_F3,KEY_F4,KEY_F5,<br/>KEY_F6,KEY_F7,KEY_F8,KEY_F9,KEY_F10,KEY_NUMLOCK,KEY_SCROLLLOCK,7,8,9,-,4,5,6,+,1,<br/>2,3,0,127,0,0,\\,KEY_F11,KEY_F12,0,0,0,0,0,0,0,<br/>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,<br/>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0<br/>};<br/>/*-------------------------------------------------------------------------------*/<br/>static unsigned char shiftnames[]={<br/>0,27,!,@,#,$,%,^,&amp;,*,(,),_,+,8,9,<br/>Q,W,E,R,T,Y,U,I,O,P,{,},13,1,A,S,<br/>D,F,G,H,J,K,L,:,34,~,KEY_LEFTSHIFT,|,Z,X,C,V,<br/>B,N,M,&lt;,&gt;,?,KEY_RIGHTSHIFT,*,1, ,0,0,0,0,0,0,<br/>0,0,0,0,0,0,0,7,8,9,-,4,5,6,+,1,<br/>2,3,0,127,0,0,|,0,0,0,0,0,0,0,0,0,<br/>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,<br/>0,0,0,0,<br/>0,0,0,0,0,0,0,0,0,0,0,0<br/>};<br/>/*-------------------------------------------------------------------------------*/<br/>static char specialnames[]={<br/>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,<br/>0,0,0,0,0,0,0,0,0,0,0,0,13,KEY_RIGHTCTRL,0,0,<br/>0,0,0,0,0,0,0,0,0,0,KEY_WINDOWS,0,0,0,0,0,<br/>0,0,0,0,0,/,0,KEY_PRINTSCREEN,KEY_RIGHTALT,0,0,0,0,0,0,0,<br/>0,0,0,0,0,0,KEY_CTRLBREAK,KEY_HOME,KEY_UP,KEY_PAGEUP,0,KEY_LEFT,0,KEY_RIGHT,0,KEY_END,<br/>KEY_DOWN,KEY_PAGEDOWN,KEY_INSERT,KEY_DELETE,0,0,0,0,0,0,0,0,0,0,0,0,<br/>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,<br/>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0<br/>};<br/>/*-------------------------------------------------------------------------------*/<br/>unsigned char pause_key;<br/>unsigned char key_ascii;<br/>unsigned char key_scan;<br/>unsigned char keyflag;<br/>static unsigned char caps;<br/>static unsigned char cur_code,key_code;<br/>static void (_interrupt far *_old_key_interrupt)(void);<br/>/*-------------------------------------------------------------------------------*/<br/>void setkeyspeed()<br/>{<br/>REGS regs;<br/>regs.w.bx=0x0;<br/>regs.w.ax=0x0A05;<br/>int386 (0x16,&amp;regs,&amp;regs);<br/>}<br/>/*-------------------------------------------------------------------------------*/<br/>void clearkey()<br/>{<br/>int i;<br/>key_scan=0;<br/>key_ascii=0;<br/>memset(keyflag,0,sizeof(keyflag));<br/>}<br/>/*-------------------------------------------------------------------------------*/<br/>static void interrupt key_interrupt(void)<br/>{<br/>static unsigned char specialflag;<br/>unsigned char k,c,temp;<br/>int i;<br/>k=inp(0x60);<br/>outp(0x61,(temp=inp(0x61))|0x80);<br/>outp(0x61,temp);<br/>if(k==0xe0)specialflag=1;<br/>else if(k==0xe1)pause_key=1;<br/>else<br/>{<br/>if(k&amp;0x80)<br/>{<br/>k&amp;=0x7f;<br/>keyflag=0;<br/>}<br/>else<br/>{<br/>key_code=cur_code;<br/>cur_code=key_scan=k;<br/>keyflag=1;<br/>if(specialflag)c=specialnames;<br/>else<br/>{<br/>if(k==SCAN_caps)<br/>{<br/>caps=(~caps)&amp;1;<br/>}<br/>if(SCAN_SHIFT)<br/>{<br/>c=shiftnames;<br/>if((c&gt;=A)&amp;&amp;(c&lt;=Z)&amp;&amp;caps)<br/>c+=a-A;<br/>}<br/>else<br/>{<br/>c=asciinames;<br/>if((c&gt;=a)&amp;&amp;(c&lt;=z)&amp;&amp;caps)<br/>c-=a-A;<br/>}<br/>}<br/>if(c)key_ascii=c;<br/>}<br/>specialflag=0;<br/>}<br/>outp(0x20,0x20);<br/>}<br/>/*-------------------------------------------------------------------------------*/<br/>static void initkey(void)<br/>{<br/>clearkey();<br/>setkeyspeed();<br/>_old_key_interrupt=_dos_getvect(9);<br/>_dos_setvect(9,key_interrupt);<br/>}<br/>/*-------------------------------------------------------------------------------*/<br/>static void closekey(void)<br/>{<br/>_dos_setvect(9,_old_key_interrupt);<br/>}<br/>/*-------------------------------------------------------------------------------*/<br/>unsigned char getscan(void)<br/>{<br/>unsigned char result;<br/>while((result=key_scan)!=0);<br/>key_scan=0;<br/>return(result);<br/>}<br/>/*-------------------------------------------------------------------------------*/<br/>unsigned char getkey(void)<br/>{<br/>unsigned char result;<br/>while((result=key_ascii)==0);<br/>key_ascii=0;<br/>return(result);<br/>}<br/>/*-------------------------------------------------------------------------------*/<br/><br/>20、任何情况下要注意调试,WATCOM C/C++程序员可以用以下几条函数调试:<br/>调用:<br/>debug("test.dbg","i=%d\n",i);<br/>debug_print();<br/><br/>int debug_count=0;<br/>struct debug_type<br/>{<br/>char *fname;<br/>char *fcoment;<br/>int value;<br/>}debug_i;<br/><br/>//除错程序<br/>void debug(char *file_name,char *coment,int debug_v)<br/>{<br/>if (debug_count&lt;255)<br/>{<br/>debug_i.fname=file_name;<br/>debug_i.fcoment=coment;<br/>debug_i.value=debug_v;<br/>debug_count++;<br/>}<br/>}<br/><br/>//除错写盘程序<br/>void debug_print(void)<br/>{<br/>FILE *debug_file;<br/>int i;<br/>if (debug_count!=0)<br/>{<br/>for (i=0;i&lt;=debug_count;i++)<br/>{<br/>debug_file=fopen(debug_i.fname,"a");<br/>fprintf(debug_file,"debug[%3d] ",i);<br/>fprintf(debug_file,debug_i.fcoment,debug_i.value);<br/>fclose(debug_file);<br/>}<br/>}<br/>init_debug();<br/>}<br/><br/>21、最后一条,写不下去了,就不要写了,游戏开发是一个漫长的过程,没有一天能写成的游戏,至少我没见过,写得太累了,就玩去吧,千万不要把自己的热情消耗没了,那样的话,再简单的游戏也写不出来。</span></td></tr></tbody></table></td></tr></tbody></table></td></tr></tbody></table>
页: [1]
查看完整版本: DOS游戏编程二十一条