俄罗斯方块 16p.docx

上传人:b****1 文档编号:10659851 上传时间:2023-05-27 格式:DOCX 页数:22 大小:24.76KB
下载 相关 举报
俄罗斯方块 16p.docx_第1页
第1页 / 共22页
俄罗斯方块 16p.docx_第2页
第2页 / 共22页
俄罗斯方块 16p.docx_第3页
第3页 / 共22页
俄罗斯方块 16p.docx_第4页
第4页 / 共22页
俄罗斯方块 16p.docx_第5页
第5页 / 共22页
俄罗斯方块 16p.docx_第6页
第6页 / 共22页
俄罗斯方块 16p.docx_第7页
第7页 / 共22页
俄罗斯方块 16p.docx_第8页
第8页 / 共22页
俄罗斯方块 16p.docx_第9页
第9页 / 共22页
俄罗斯方块 16p.docx_第10页
第10页 / 共22页
俄罗斯方块 16p.docx_第11页
第11页 / 共22页
俄罗斯方块 16p.docx_第12页
第12页 / 共22页
俄罗斯方块 16p.docx_第13页
第13页 / 共22页
俄罗斯方块 16p.docx_第14页
第14页 / 共22页
俄罗斯方块 16p.docx_第15页
第15页 / 共22页
俄罗斯方块 16p.docx_第16页
第16页 / 共22页
俄罗斯方块 16p.docx_第17页
第17页 / 共22页
俄罗斯方块 16p.docx_第18页
第18页 / 共22页
俄罗斯方块 16p.docx_第19页
第19页 / 共22页
俄罗斯方块 16p.docx_第20页
第20页 / 共22页
亲,该文档总共22页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

俄罗斯方块 16p.docx

《俄罗斯方块 16p.docx》由会员分享,可在线阅读,更多相关《俄罗斯方块 16p.docx(22页珍藏版)》请在冰点文库上搜索。

俄罗斯方块 16p.docx

俄罗斯方块16p

Tc2.0编写俄罗斯方块游戏

  很多编程爱好者都编写过俄罗斯方块的游戏程序。

很久以前,我用Tc2.0也做过一个;最近有好些朋友看见我以前的俄罗斯方块的程序后,

问我是怎么做的。

我一直想把这个程序的整个过程写一份详细的东西,与各位编程爱好者分享,一直没空。

正好现在放假了,而且离回家还有几天。

于是我就把这个程序重新写了一遍,尽量使程序的结构比较清晰好懂一些。

同时写了下面的这份东西。

  俄罗斯方块游戏的程序中用到了一些方法。

为了比较容易理解这些方法,我在讲述的同时写了些专门针对这些方法的示例程序。

这些示例程序力求短小,目的是用最小的代码能够清楚的示例所用的方法。

这些示例程序都经过tc2.0测试。

最后还附了完整的俄罗斯方块游戏的源代码,和最终的可执行程序。

如果你看了这份东东,有什么意见和想法,请发电子邮件告诉我。

我将会继续更新这分东东,最新的版本可以在我的个人主页上下载。

  下面的问题是有关俄罗斯方块程序的,其中有些是朋友问我的,有些是我认为可能会被问到的。

我尽量按问题从易到难排列这些问题。

关于俄罗斯方块程序的一些问题:

******************************************************

Tc2.0中怎么样设置图形显示?

Tc2.0中常用图形函数的用法?

怎样获取鍵盘输入?

怎样控制方块的移动?

怎样控制时间间隔(用于游戏中控制形状的下落)?

游戏中的各种形状及整个游戏空间怎么用数据表示?

游戏中怎么判断左右及向下移动的可能性?

游戏中怎么判断某一形状旋转的可能性?

按向下方向键时加速某一形状下落速度的处理?

怎么判断某一形状已经到底?

怎么判断某一已经被填满?

怎么消去已经被填满的一行?

怎么消去某一形状落到底后能够消去的所有的行?

(如长条最多可以消去四行)

怎样修改游戏板的状态?

怎样统计分数?

怎样处理升级后的加速问题?

怎样判断游戏结束?

关于计分板设计的问题。

关于“下一个”形状取法的问题。

剩下的问题。

******************************************************

新的问题:

 我想有一个最高记录的显示,应该怎么做呀?

 我想实现一个进度存储功能,应该怎么做呀?

Tc2.0中怎么样设置图形显示?

  Tc2.0中有两种显示模式,一种是我们所熟知的字符模式,另一种是图形模式。

在字符模式下只能显式字符,如ASCII字符。

一般是显示25

行,每行80个字符。

程序缺省的是字符模式。

在字符模式下不能显式图形和进行绘图操作。

要想进行图形显示和绘图操作,必须切换到图形模

式下。

  Tc2.0中用initgraph()函数可以切换到图形模式,用closegraph()可以从图形模式切换回字符模式。

initgraph()和closegraph()都是图形

函数,使用图形函数必须包括头文件"graphics.h"。

  voidfarinitgraph(intfar*graphdriver,intfar*graphmode,charfar*pathtodriver);graphdriver是上涨指向图形驱动序号变量的指针;graphmode是在graphdriver选定后,指向图形显示模式序号变量的指针。

pathtodriver表示存放图形驱动文件的路径。

  Tc2.0中有多种图形驱动,每种图形驱动下又有几种图形显示模式。

在我的程序中图形驱动序号为VGA,图形显示模式序号为VGAHI。

这是一种分辨率为640*480(从左到右坐标依次为0-639,从上到下坐标依次为0-479),能够显示16种颜色的图形模式。

别的图形驱动序号和图形显示模式序号,可以从手册或联机帮助中找到。

  pathtodriver指示存放图形驱动文件的路径。

图形驱动序号不同,图形驱动文件也不同。

序号为VGA图形驱动对应"egavga.bgi"这个图形驱动文件。

"egavga.bgi"一般在Tc目录下。

voidfarclosegraph(void);

  没有参数,从图形模式直接返回字符模式。

initgraph()和closegraph()的常用用法如下:

intgdriver=VGA,gmode=VGAHI,errorcode;

/*initializegraphicsmode*/

initgraph(&gdriver,&gmode,"e:

\\tc2");

/*readresultofinitialization*/

errorcode=graphresult();

if(errorcode!

=grOk)/*anerroroccurred*/

{

printf("Graphicserror:

%s\n",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?

0?

Justifyfrombottom

?

CENTER_TEXT?

1?

Centertext

?

TOP_TEXT?

2?

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%x\n",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

#include

#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()

{

disable();

setvect(TIMER,oldhandler);

enable();

}

voidmain(void)

{

intkey,time=0;

SetTimer(newhandler);/*修改时钟中断*/

for(;;)

{

if(bioskey

(1))

{

key=bioskey(0);

if(key==VK_ESC)/*按escape键提前退出程序*/

{

printf("Usercancel!

\n");

break;

}

}

if(TimerCounter>18)/*1秒钟处理一次*/

{

/*恢复计时变量*/

TimerCounter=0;

time++;

printf("%d\n",time);

if(time==10)/*10秒钟后结束程序*/

{

printf("Programterminatednormally!

\n");

break;

}

}

}

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-1012345678910111213141516171819202122232425262728293031

-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),右边那块小的就是显示“下一个”形状的部分(横坐

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 农林牧渔 > 林学

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2