编程高手之路代码集萃C语言编写的俄罗斯方块文档格式.docx
《编程高手之路代码集萃C语言编写的俄罗斯方块文档格式.docx》由会员分享,可在线阅读,更多相关《编程高手之路代码集萃C语言编写的俄罗斯方块文档格式.docx(17页珍藏版)》请在冰点文库上搜索。
![编程高手之路代码集萃C语言编写的俄罗斯方块文档格式.docx](https://file1.bingdoc.com/fileroot1/2023-5/9/6d0a525e-8d08-4a00-a116-5526f0638fc8/6d0a525e-8d08-4a00-a116-5526f0638fc81.gif)
{
printf(Graphicserror:
%sn,grapherrormsg(errorcode));
printf(Pressanykeytohalt:
);
getch();
exit
(1);
/*returnwitherrorcode*/
}
/*returntotextmode*/
closegraph();
Tc2.0中常用图形函数的用法?
在这里讲几个游戏中用到的绘图用的图形函数:
setcolor();
line();
rectangle();
settextjustify();
outtextxy();
setfillstyle();
bar();
voidfarsetcolor(intcolor);
设置画线、画框和在图形模式下显示文字的当前颜色。
这个函数将影响line()、rectangle()和outtextxy()函数绘图的颜色。
color可以取常的颜色常量:
BLACK?
0
BLUE?
1
GREEN?
2
CYAN?
3
RED?
4
MAGENTA?
5
BROWN?
6
LIGHTGRAY?
7
DARKGRAY?
8
LIGHTBLUE?
9
LIGHTGREEN?
10
LIGHTCYAN?
11
LIGHTRED?
12
LIGHTMAGENTA?
13
YELLOW?
14
WHITE?
15
voidfarline(intx1,inty1,intx2,inty2);
用当前颜色从(x1,y1)画一条到(x2,y2)的线段。
voidfarrectangle(intleft,inttop,intright,intbottom);
用当前颜色画一个左上角为(left,top)、右下角为(right,bottom)的矩形框。
voidfarsettextjustify(inthorz,intvert);
设置图形模式下文字输出的对齐方式。
主要影响outtextxy()函数。
horiz和vert可取如下枚举常量:
horiz?
LEFT_TEXT?
0?
Left-justifytext
?
CENTER_TEXT?
1?
Centertext
RIGHT_TEXT?
2?
Right-justifytext
vert?
BOTTOM_TEXT?
Justifyfrombottom
TOP_TEXT?
Justifyfromtop
voidfarouttextxy(intx,inty,char*textstring);
在(x,y)处用当前字体(缺省的字体是DEFAULT_FONT)显示字符串textstring,字符串的对齐方式由settextjustify()指定。
voidfarsetfillstyle(intpattern,intcolor);
设置图形的填充模式和填充颜色,主要影响bar()等函数。
pattern一般取枚举常量值SOLID_FILL,color的取值与setcolor(intcolor)中color的取值范围相同。
介绍完了前面两个问题,现在来写一个程序。
这个程序演示前了面所介绍的几个图形函数。
程序prog1.c
怎样获取鍵盘输入?
在Tc2.0中有一个处理键盘输入的函数bioskey();
intbioskey(intcmd);
当cmd为1时,bioskey()检测是否有键按下。
没有键按下时返回0;
有键按下时返回按键码(任何按键码都不为0),但此时并不将检测到的按
键码从键盘缓冲队列中清除。
当cmd为0时,bioskey()返回键盘缓冲队列中的按键码,并将此按键码从键盘缓冲队列中清除。
如果键盘缓冲队列为空,则一直等到有键按
下,才将得到的按键码返回。
Escape键的按键码为0x11b,下面的小程序可以获取按键的按键码。
for(;
;
)
key=bioskey(0);
/*waitforakeystroke*/
printf(0x%xn,key);
if(key==0x11b)break;
/*Escape*/
常用按键的按键码如下:
#defineVK_LEFT0x4b00
#defineVK_RIGHT0x4d00
#defineVK_DOWN0x5000
#defineVK_UP0x4800
#defineVK_HOME0x4700
#defineVK_END0x4f00
#defineVK_SPACE0x3920
#defineVK_ESC0x011b
#defineVK_ENTER0x1c0d
完整的程序请参见prog2.c、prog3.c。
prog2.c获取按键的按键码,按Escape键退出程序。
prog3.c根据不同的按键进行不同的操作,按Escape键退出程序。
怎样控制方块的移动?
方块移动的实现很简单,将方块原来的位置用背景色画一个同样大小的方块,将原来的方块涂去。
然后在新的位置上重新绘制方块就可以
了。
这样就实现了方块的移动。
完整的程序请参见prog4.c。
这个用方向键控制一个黄色的小方块在屏幕上上、下、左、右移动。
这个程序用到了前面几个问题讲的内容,如果你有点忘了,还要回头看看哦。
:
怎样控制时间间隔(用于游戏中控制形状的下落)?
解决这个问题要用到时钟中断。
时钟中断大约每秒钟发生18.2次。
截获正常的时钟中断后,在处理完正常的时钟中断后,将一个计时变量
加1。
这样,每秒钟计时变量约增加18。
需要控控制时间的时候,只需要看这个计时变量就行了。
截获时钟中断要用到函数getvect()和setvect()。
两个函数的声明如下:
voidinterrupt(*getvect(intinterruptno))();
voidsetvect(intinterruptno,voidinterrupt(*isr)());
保留字interrupt指示函数是一个中断处理函数。
在调用中断处理函数的时候,所有的寄存器将会被保存。
中断处理函数的返回时的指令是iret,而不是一般函数用到的ret指令。
getvect()根据中断号interruptno获取中断号为interruptno的中断处理函数的入口地址。
setvect()将中断号为interruptno的中断处理函数的入口地址改为isr()函数的入口地址。
即中断发生时,将调用isr()函数。
在程序开始的时候截获时钟中断,并设置新的中断处理。
在程序结束的时候,一定要记着恢复时钟中断哦,不然系统的计时功能会出问题
的。
具体演示程序请参见prog5.c。
由于中断处理大家可能用的不多,所以我把prog5.c这个程序完整地贴在下面,并加上详细的解释。
/*prog5.c*/
Thisisaninterruptserviceroutine.YoucanNOTcompilethis
programwithTestStackOverflowturnedonandgetanexecutable
filewhichwilloperatecorrectly.*/
/*这个程序每隔1秒钟输出一个整数,10秒钟后结束程序。
按escape键提前退出程序。
*/
#include
/*Escapekey*/
#defineVK_ESC0x11b
#defineTIMER0x1c/*时钟中断的中断号*/
/*中断处理函数在C和C++中的表示略有不同。
如果定义了_cplusplus则表示在C++环境下,否则是在C环境下。
*/
#ifdef__cplusplus
#define__CPPARGS...
#else
#define__CPPARGS
#endif
intTimerCounter=0;
/*计时变量,每秒钟增加18。
/*指向原来时钟中断处理过程入口的中断处理函数指针(句柄)*/
voidinterrupt(*oldhandler)(__CPPARGS);
/*新的时钟中断处理函数*/
voidinterruptnewhandler(__CPPARGS)
/*increasetheglobalcounter*/
TimerCounter++;
/*calltheoldroutine*/
oldhandler();
/*设置新的时钟中断处理过程*/
voidSetTimer(voidinterrupt(*IntProc)(__CPPARGS))
oldhandler=getvect(TIMER);
disable();
/*设置新的时钟中断处理过程时,禁止所有中断*/
setvect(TIMER,IntProc);
enable();
/*开启中断*/
/*恢复原有的时钟中断处理过程*/
voidKillTimer()
setvect(TIMER,oldhandler);
voidmain(void)
intkey,time=0;
SetTimer(newhandler);
/*修改时钟中断*/
if(bioskey
(1))
if(key==VK_ESC)/*按escape键提前退出程序*/
printf(Usercancel!
n);
break;
if(TimerCounter>
18)/*1秒钟处理一次*/
/*恢复计时变量*/
TimerCounter=0;
time++;
printf(%dn,time);
if(time==10)/*10秒钟后结束程序*/
printf(Programterminatednormally!
KillTimer();
/*恢复时钟中断*/
游戏中的各种形状及整个游戏空间怎么用数据表示?
以后我提到的形状都是指下面七种形之一及它们旋转后的变形体。
□□□□□□□□□□□□□□□□
□■□□□■■□□□□□□□□□
□■□□□■□□□■□□□■■□
□■■□□■□□■■■□■■□□
□□□□□■□□□□□□
■■□□□■□□□■■□
□■■□□■□□□■■□
我定义了一个结构来表示形状。
structshape
intxy[8];
intcolor;
intnext;
-1012
-3□□□□
-2□□□□
-1□□□□
0□■□□
所有的各种形状都可以放在4x4的格子里。
假定第二列,第四行的格子坐标为(0,0)(如上图中黑块所示),则每个形状的四个方块都可以用4
个数对来表示。
坐标x从左向右依次增加,y从上到下依次增加。
表示的时候,组成该形状的四个方块从左到右,从上到下(不一定非要按这个顺
序)。
如上面七种形状的第一个用数对来表示就是(-2,0)、(-1,0)、(0,0)、(1,0)。
结构shape中的xy就是用来表示这4个数对的。
为了简化程序,用一维数组xy[8]来表示。
xy[0]、xy[1]表示第一个数对,xy[2]、xy[3]表示第二个数对,依次类推。
shape中的color表示形状的颜色,不同的形状有不同的颜色。
七种形状及它们旋转后的变形体一共有19种形状,用一个全局数组表示。
假定旋转的方向是逆时针方向(顺时针方向道理一样)。
shape中的next就表示当前形状逆时针旋转后的下一个形状的序号。
例如:
第一种形状及其旋
转变形的形状用结构表示如下。
□■□□□□□□□■■□□□□□
□■□□□□■□□□■□■■■□
□■■□■■■□□□■□■□□□
structshapeshapes[19]=
/*{x1,y1,x2,y2,x3,y3,x4,y4,color,next}*/
{0,-2,0,-1,0,0,1,0,CYAN,1},/**/
{-1,0,0,0,1,-1,1,0,CYAN,2},/*#*/
{0,-2,1,-2,1,-1,1,0,CYAN,3},/*#*/
{-1,-1,-1,0,0,-1,1,-1,CYAN,0},/*##*/
……
游戏空间指的是整个游戏主要的界面(呵呵,这个定义我实在想不出更准确的,还请哪位大虾指点)。
实际上是一个宽10格子、高20格子的
游戏板。
用一个全局数组board[12][22]表示。
表示的时候:
board[x][y]为1时表示游戏板上(x,y)这个位置上已经有方块占着了,board[x][y]
为0表示游戏板上这位置还空着。
为了便于判断形状的移动是否到边、到底,初始的时候在游戏板的两边各加一列,在游戏板的下面加一行,全
部填上1,表示不能移出界。
即board[0][y],board[11][y](其中y从0到21)初始都为1,board[x][21](其中x从1到10)初始都为1。
12345678910
1□□□□□□□□□□
2□□□□□□□□□□
3□□□□□□□□□□
4□□□□□□□□□□
5□□□□□□□□□□
6□□□□□□□□□□
7□□□□□□□□□□
8□□□□□□□□□□
9□□□□□□□□□□
10□□□□□□□□□□
11□□□□□□□□□□
12□□□□□□□□□□
13□□□□□□□□□□
14□□□□□□□□□□
15□□□□□□□□□□
16□□□□□□□□□□
17□□□□□□□□□□
18□□□□□□□□□□
19□□□□□□□□□□
20□□□□□□□□□□
prog6.c演示了用结构表示各种形状的方法。
虽然程序稍长一些,但并不是特别复杂。
其中游戏板初始化部分并没有真正用到,但是后面的程
序会用到的。
其中SIZE定义为16,这样将整个屏幕的坐标系由原来的640×
480转换成40×
30(640/16=40,480/16=30)。
游戏中所有的坐标都是基于40×
30的坐标系的,这样有助于简化程序。
坐标的转换在程序中由DrawBlock(intx,inty)来体现。
新的坐标系如下图所示:
-8-7-6-5-4-3-2-1012345678
-4□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
-3□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
-2□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
-1□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
0□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
1□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
2□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
3□□□□□□□□□■■■■■■■■■■□□□■■■■□□□□□□□□□□□□□□
4□□□□□□□□□■■■■■■■■■■□□□■■■■□□□□□□□□□□□□□□
5□□□□□□□□□■■■■■■■■■■□□□■■■■□□□□□□□□□□□□□□
6□□□□□□□□□■■■■■■■■■■□□□■■■■□□□□□□□□□□□□□□
7□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
8□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
9□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
10□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
11□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
12□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
13□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
14□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
15□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
16□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
17□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
18□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
19□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
20□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
21□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
22□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
23□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
24□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
25□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
26□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
新坐标中最主要的是就是上面两块黑色的部分。
左边那块大的就是游戏板(横坐标从1到10,纵坐标从1到20),右边那块小的就是显示“下一个”形状的部分(横坐标从14到17,纵坐标从3到6)。
这个新的坐标系是整个游戏的基础,后面所有的移动、变形等的计算都是基于这个坐标系的。
游戏中怎么判断左右及向下移动的可能性?
看懂了前面的各种形状和游戏板等的表示,接下来的东西就都好办多了。
先来看一下某个形状如何显示在游戏板当中。
假设要在游戏板中
显示第一个形状。
第一个形状在结构中的表示如下:
{0,-2,0,-1,0,0,1,0,CYAN,1},
那么这个组成形状四个方块的坐标表示为(0,-2)、(0,-1)、(0,0)和(1,0)。
这实际上是相对坐标。
假形状的实际坐标指的是4x4方块中的第
二列、第三行的方块的位置,设这个位置为(x,y)。
那么组成这个形状的四个小方块的实际坐标(以第一个形状为例)就是(x+0,y-2)、(x+0,y-1)、(x+0,y+0)和(x+1,y+0)。
由于所有的形状都可以在4x4的方块阵列中表示,这样就找到了一种统一的方法来表示所有的形状了。
-3□□□□相对坐标
-2□■□□
-1□■□□组成第一种形状的四个方块的相对坐标为(0,-2)、(0,-1)、(0,0)和(1,0)。
0□■■□
让我们看看形状是如何显示在游戏板中的(以第一个形状为例)。
1□■□□□□□□□□形状的坐标为(2,3)。
组成形状的四个方块的坐标由形状的
2□■□□□□□□□□坐标加上这四个小方块各自的相对坐标得出。
它们分别是:
3□■■□□□□□□□(2+0,3-2)、(2+0,3-1)、(2+0,3-0)和(2+1,3-0)。
即:
4□□□□□□□□□□(2,1)、(2,2)、(2,3)和(3,3)。
如左图所示。
7■□□□□□□□□