初学者怎样看懂代码怎么制作俄罗斯方块(如何用代码制作俄罗斯方

http://www.itjxue.com  2023-04-02 20:48  来源:未知  点击次数: 

如何用C语言编一个俄罗斯方块

游戏界面预览:

菜单预览:

自定义每个小方块颜色功能界面:

游戏主要有四部分组成:Square类,Block类,gameField类,游戏引擎

Square类:

这个类描述的对象是组成大方块中的每个小正方形实体。

类设计:

class Square

{

public Point location; //小方块的坐标

public Size size; //小方块大小

public Color foreColor; //小方块前景色

public Color backColor; //小方块背景色

public Square(Size initSize,Color initForeColor,Color initBackColor) //构造函数

{ ……}

public void Draw(System.IntPtr winHandle) //在指定设备上画方块

{ …… }

public void Erase(System.IntPtr winHandle)//擦除方块

{ …… }

}

Block类:

这个类描述的对象是某一个大方块的实体。每个大方块由四个小正方形组成,一共有7种组合方式。这个类需要实现一个大方块实体所有的属性和动作。包括:方块的形状,位置,方块左移,右移,下移,旋转等。

类设计:

class Block

{

public Square square1; //组成block的四个小方块

public Square square2;

public Square square3;

public Square square4; private const int squareSize = GameField.SquareSize; //小方块的边长

public enum BlockTypes

{

undefined = 0,

square = 1,

line = 2,

J = 3,

L = 4,

T = 5,

Z = 6,

S = 7

};//一共有7种形状

public BlockTypes blockType; //方块的形状

//七个小方块的颜色数组

private Color foreColor;

private Color backColor;

//方块的方向

public enum RotateDirections

{

North = 1,

East = 2,

South = 3,

West = 4

};

public RotateDirections myRotation = RotateDirections.North;

public Block(Point thisLocation,BlockTypes bType)

{ ……}

//含有自定义颜色的重载

public Block(Point thisLocation, BlockTypes bType,Color fc,Color bc)

{ ……} /*画方块*/

public void Draw(System.IntPtr winHandle)

{…… }

/*擦方块*/

public void Erase(System.IntPtr winHandle)

{…… } /*移动*/

public bool down()

{……}

public bool left()

{……}

public bool right()

{……}

/*旋转block*/

public void Rotate()

{……}

/*检测是否到顶*/

public int Top()

{……}

}

GameField类:

这个类描述的对象是游戏场景实体,包括场景的背景色,大小,方块是否还可以移动,以及场景中填满一行的检测等。

类设计:

class GameField

{

public const int width = 20; //场景的宽,以方块个数为单位

public const int height = 30;

public const int SquareSize = 15; //每个四分之一小方块的边长

public static Color BackColor; //场景的背景色

public static System.IntPtr winHandle; //场景的handle

public static Color[] BlockForeColor ={ Color.Blue, Color.Beige, Color.DarkKhaki, Color.DarkMagenta, Color.DarkOliveGreen, Color.DarkOrange, Color.DarkRed };

public static Color[] BlockBackColor ={ Color.LightCyan, Color.DarkSeaGreen, Color.Beige, Color.Beige, Color.Beige, Color.Beige, Color.Beige };

public static bool isChanged=false; //设置是否被更改的标志位

public static SoundPlayer sound = new SoundPlayer(); //播放声音 public static Square[,] arriveBlock = new Square[width, height]; //保存已经不能再下落了的方块

public static int[] arrBitBlock=new int[height]; //位数组:当某个位置有方块时,该行的该位为1

private const int bitEmpty = 0x0; //0000 0000 0000 0000 0000

private const int bitFull = 0xFFFFF; //1111 1111 1111 1111 1111 /*检测某个位置是否为空*/

public static bool isEmpty(int x, int y)

{……}

/*将方块停住*/

public static void stopSquare(Square sq, int x, int y)

{……}

/*检测行是否满

* 返回:成功消除的行数和 (方便统计分数)

*/

public static int CheckLines()

{ ……}

/*播放声音*/

public static void PlaySound(string soundstr)

{……}

/*重画*/

public static void Redraw()

{ …… }

//结束

}

游戏引擎:

游戏引擎正如其名,就像一个发动机一样让游戏不间断运行。本游戏中就是让方块以一定的速度下落。并响应键盘事件,实行左右移动,和向下加速功能。(代码见源码)

声音播放:

音效是游戏不可缺少的一部分。在.Net2.0中已经提供了一个类来播放声音。在using System.Media;命名空间。

本游戏中播放声音的代码如下:(在 GameField类中)

using System.Media;

public static SoundPlayer sound = new SoundPlayer();

/*播放声音*/

public static void PlaySound(string soundstr)

{

switch (soundstr)

{

case "FinishOneLine": //消除一行的声音

if (!File.Exists("FinishOneLine.wav")) return;

sound.SoundLocation = "FinishOneLine.wav";

break;

case "CanNotDo": //当无法操作时

if (!File.Exists("CanNotDo.wav")) return;

sound.SoundLocation = "CanNotDo.wav";

break;

}

sound.Play();

}

要播放的时候调用PlaySound()方法即可。

其实步骤很简单,先引用System.Media空间,然后创建一个SoundPlayer 对象,用SoundLocation 属性设置声音文件的地址,然后调用Play()方法即可播放。不过注意,这个类可以播放的声音格式只有Wav文件。

保存游戏设置:

在游戏中经常要保存用户自定义的设置。本游戏通过写进ini文件来保存。

主要代码如:

/*加载窗体时从配置文件Setting.ini中读取游戏设置*/

private void getSettings()

{

if (!File.Exists("Setting.ini"))

return;

FileStream fs = new FileStream("Setting.ini", FileMode.OpenOrCreate, FileAccess.ReadWrite);

StreamReader sr = new StreamReader(fs);

string line1=sr.ReadLine();

string line2=sr.ReadLine();

string line3=sr.ReadLine();

if (line1 != null line1.Split('=').Length 1)

{

GameField.BackColor = Color.FromArgb(int.Parse(line1.Split('=')[1]));

picBackGround.BackColor = GameField.BackColor;

}

if (line2 != null line2.Split('=').Length 1)

GameField.BlockForeColor = strToColor(line2.Split('=')[1]);

if (line3 != null line3.Split('=').Length 1)

GameField.BlockBackColor = strToColor(line3.Split('=')[1]);

sr.Close();

fs.Close();

}

/*如果游戏设置被更改,将新的设置保存到Setting.ini*/

private void saveSettings()

{

FileStream fs = new FileStream("Setting.ini", FileMode.Create, FileAccess.ReadWrite);

StreamWriter sw = new StreamWriter(fs);

sw.WriteLine("GameFieldColor="+GameField.BackColor.ToArgb());

sw.WriteLine("BlockFroeColor=" + colorToStr(GameField.BlockForeColor));

sw.WriteLine("BlockBackColor=" + colorToStr(GameField.BlockBackColor));

sw.Flush();

sw.Close();

fs.Close();

}

要源码+QQ348199903

俄罗斯方块C语言代码

俄罗斯方块C源代码

#include?stdio.h

#include?windows.h

#include?conio.h

#include?time.h

#define??ZL??4 ? ? //坐标增量,?不使游戏窗口靠边

#define?WID??36 ?? //游戏窗口的宽度

#define?HEI??20 ?? //游戏窗口的高度

int?i,j,Ta,Tb,Tc; ? ?? //?Ta,Tb,Tc用于记住和转换方块变量的值

int?a[60][60]={0}; ?? //标记游戏屏幕各坐标点:0,1,2分别为空、方块、边框

int?b[4]; ? ? ?? //标记4个"口"方块:1有,0无,类似开关

int?x,y,?level,score,speed; ?? //方块中心位置的x,y坐标,游戏等级、得分和游戏速度

int?flag,next; ? //当前要操作的方块类型序号,下一个方块类型序号

void?gtxy(int?m,?int?n); ? //以下声明要用到的自编函数

void?gflag(?);? //获得下一方块序号

void?csh(?);? //初始化界面

void?start(?);? //开始部分

void?prfk?(?);? //打印方块

void?clfk(?);? //清除方块

void?mkfk(?);? //制作方块

void?keyD(?);? //按键操作

int??ifmov(?);? //判断方块能否移动或变体

void clHA(?);? //清除满行的方块

void?clNEXT(?);? //清除边框外的NEXT方块

int?main(?)

{?csh(?); ??

?? while(1)

? ?? {start(?);??//开始部分

? ? ?? while(1)

? ? ?? {?prfk(?);??

? ? ? ?? Sleep(speed);? //延时

? ? ? ? ? clfk(?);

? ? ? ? ? Tb=x;Tc=flag;??//临存当前x坐标和序号,以备撤销操作

? ? ? ? ? keyD(?); ?

? ? ? ? ? y++;?????//方块向下移动

? ? ? ?? if?(ifmov(?)==0)?{?y--;?prfk(?);?dlHA(?);?break;}?//不可动放下,删行,跨出循环

? ? ?? }

? ? ? for(i=y-2;iy+2;i++){?if?(i==ZL)?{?j=0;?}?}? //方块触到框顶

? ?? if?(j==0)?{?system("cls");gtxy(10,10);printf("游戏结束!");?getch();?break;?}?

? ?? clNEXT(?); ? //清除框外的NEXT方块

? ? }

? return?0;

}

void?gtxy(int?m,?int?n)??//控制光标移动

{COORD?pos;??//定义变量

pos.X?=?m;??//横坐标

pos.Y?=?n;???//纵坐标

SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),?pos);

}

void?csh(?)????//初始化界面

{gtxy(ZL+WID/2-5,ZL-2);?printf("俄罗斯方块");??????//打印游戏名称

gtxy(ZL+WID+3,ZL+7);?printf("*******?NEXT:");??//打印菜单信息

gtxy(ZL+WID+3,ZL+13);?printf("**********");

gtxy(ZL+WID+3,ZL+15);?printf("Esc?:退出游戏");

gtxy(ZL+WID+3,ZL+17);?printf("↑键:变体");

gtxy(ZL+WID+3,ZL+19);?printf("空格:暂停游戏");

gtxy(ZL,ZL);??printf("╔");??gtxy(ZL+WID-2,ZL);??printf("╗");??//打印框角

gtxy(ZL,ZL+HEI);??printf("╚");??gtxy(ZL+WID-2,ZL+HEI);??printf("╝");

a[ZL][ZL+HEI]=2;??a[ZL+WID-2][ZL+HEI]=2;??//记住有图案

for(i=2;iWID-2;i+=2)?{gtxy(ZL+i,ZL);??printf("═");?}??//打印上横框

for(i=2;iWID-2;i+=2)?{gtxy(ZL+i,ZL+HEI);?printf("═");?a[ZL+i][ZL+HEI]=2;?}?//下框

for(i=1;iHEI;i++)?{?gtxy(ZL,ZL+i);??printf("║");?a[ZL][ZL+i]=2;?}??//左竖框记住有图案

for(i=1;iHEI;i++)?{gtxy(ZL+WID-2,ZL+i);?printf("║");?a[ZL+WID-2][ZL+i]=2;?}?//右框

CONSOLE_CURSOR_INFO?cursor_info={1,0};???//以下是隐藏光标的设置

SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),cursor_info);

level=1;?score=0;?speed=400;

gflag(?);??flag=next;??//获得一个当前方块序号

}

void?gflag(?) ? //获得下一个方块的序号

{?srand((unsigned)time(NULL));?next?=?rand()%19+1; }

void?start(?)??//开始部分

{?gflag(?);?Ta=flag;?flag=next;??//保存当前方块序号,将下一方块序号临时操作

x=ZL+WID+6;?y=ZL+10;?prfk(?);??//给x,y赋值,在框外打印出下一方块

flag=Ta;?x=ZL+WID/2;?y=ZL-1;??//取回当前方块序号,并给x,y赋值

}

void?prfk?(?)??//打印俄罗斯方块

{?for(i=0;i4;i++)?{b[i]=1;?}??//数组b[4]每个元素的值都为1

mkfk?(?);??//制作俄罗斯方块

for(?i=?x-2;?i=x+4;?i+=2?)??//打印方块

{?for(j=y-2;j=?y+1;j++)?{?if(?a[i][j]==1??jZL?){?gtxy(i,j);?printf("□");?}?}?}

gtxy(ZL+WID+3,ZL+1); ? printf("level?:?%d",level); ?//以下打印菜单信息

gtxy(ZL+WID+3,ZL+3);? printf("score?:?%d",score);

gtxy(ZL+WID+3,ZL+5);? printf("speed?:?%d",speed);

}

void?clfk(?)??//清除俄罗斯方块

{?for(i=0;i4;i++)?{?b[i]=0;?}??//数组b[4]每个元素的值都为0

mkfk?(?);??//制作俄罗斯方块

for(?i=x-2;?i=x+4;?i+=2?)??//清除方块

{?for(j=y-2;j=y+1;j++){?if(?a[i][j]==0??jZL?){?gtxy(i,j);?printf("??");?}?}?}

}

void?mkfk(?)??//制作俄罗斯方块

{?a[x][?y]=b[0];??//方块中心位置状态:?1-有,0-无

switch(flag)???//共6大类,19种小类型

{?case?1:?{?a[x][y-1]=b[1];?a[x+2][y-1]=b[2];?a[x+2][y]=b[3];?break;?}??//田字方块

case?2:?{?a[x-2][y]=b[1];?a[x+2][y]=b[2];?a[x+4][y]=b[3];?break;?}??//直线方块:----

case?3:?{?a[x][y-1]=b[1];?a[x][y-2]=b[2];?a[x][y+1]=b[3];?break;?}??//直线方块:?|

case?4:?{?a[x-2][y]=b[1];?a[x+2][y]=b[2];?a[x][y+1]=b[3];?break;?}??//T字方块

case?5:?{?a[x][y-1]=b[1];?a[x][y+1]=b[2];?a[x-2][y]=b[3];?break;?}??//T字顺时针转90度

case?6:?{?a[x][y-1]=b[1];?a[x-2][y]=b[2];?a[x+2][y]=b[3];?break;?}??//T字顺转180度

case?7:?{?a[x][y-1]=b[1];?a[x][y+1]=b[2];?a[x+2][y]=b[3];?break;?}??//T字顺转270度

case?8:?{?a[x][y+1]=b[1];?a[x-2][y]=b[2];?a[x+2][y+1]=b[3];?break;?}?//Z字方块

case?9:?{?a[x][y-1]=b[1];?a[x-2][y]=b[2];?a[x-2][y+1]=b[3];?break;?}??//Z字顺转90度

case?10:?{?a[x][y-1]=b[1];?a[x-2][y-1]=b[2];?a[x+2][y]=b[3];?break;?}??//Z字顺转180度

case?11:?{?a[x][y+1]=b[1];?a[x+2][y-1]=b[2];?a[x+2][?y]=b[3];?break;?}?//Z字顺转270度

case?12:?{?a[x][y-1]=b[1];?a[x][y+1]=b[2];?a[x-2][y-1]=b[3];?break;?}??//7字方块

case?13:?{a[x-2][y]=b[1];?a[x+2][y-1]=b[2];?a[x+2][y]=b[3];?break;?}??//7字顺转90度

case?14:?{?a[x][y-1]=b[1];?a[x][y+1]=b[2];?a[x+2][y+1]=b[3];?break;?}??//7字顺转180度

case?15:?{?a[x-2][y]=b[1];?a[x-2][y+1]=b[2];?a[x+2][y]=b[3];?break;?}??//7字顺转270度

case?16:?{?a[x][y+1]=b[1];?a[x][y-1]=b[2];?a[x+2][y-1]=b[3];?break;?}??//倒7字方块

case?17:?{?a[x-2][y]=b[1];?a[x+2][y+1]=b[2];?a[x+2][y]=b[3];?break;?}??//倒7字顺转90度

case?18:?{?a[x][y-1]=b[1];?a[x][y+1]=b[2];?a[x-2][y+1]=b[3];?break;?}??//倒7字顺转180度

case?19:?{?a[x-2][y]=b[1];?a[x-2][y-1]=b[2];?a[x+2][y]=b[3];?break;?}??//倒7字顺转270度

}

}

void?keyD(?)??//按键操作

{?if?(kbhit(?))

{?int?key;

?? key=getch();

if?(key==224)

{?key=getch();

? ? ?? if?(key==75)?{?x-=2;?}??//按下左方向键,中心横坐标减2

if?(key==77)?{?x+=2;?}??//按下右方向键,中心横坐标加2

? ? ? if?(key==72)?????//按下向上方向键,方块变体

{?if?(flag=2??flag=3?)?{?flag++;?flag%=2;?flag+=2;?}

if?(?flag=4??flag=7?)?{?flag++;?flag%=4;?flag+=4;?}

if?(flag=8??flag=11?)?{?flag++;?flag%=4;?flag+=8;?}

if?(flag=12??flag=15?)?{?flag++;?flag%=4;?flag+=12;?}

if?(?flag=16??flag=19?)?{?flag++;?flag%=4;?flag+=16;?}?}

? ? ?? }

? ? if?(key==32)?????//按空格键,暂停

{?prfk(?);?while(1)?{?if?(getch(?)==32)?{?clfk(?);break;}?}?}? //再按空格键,继续游戏

? ? if?(ifmov(?)==0)?{?x=Tb;?flag=Tc;?}? //如果不可动,撤销上面操作

? ? else?{?prfk(?);?Sleep(speed);?clfk(?);?Tb=x;Tc=flag;} ? //如果可动,执行操作

}

}

int?ifmov(?)???//判断能否移动

{?if?(a[x][y]!=0)?{?return?0;?}??//方块中心处有图案返回0,不可移动

else{?if?(?(flag==1??(?a[x][?y-1]==0??a[x+2][y-1]==0??a[x+2][y]==0?)?)?||

? ? ?? (flag==2??(?a[x-2][y]==0??a[x+2][y]==0??a[x+4][y]==0?)?)?||

? ? ?? (flag==3??(?a[x][y-1]==0??a[x][y-2]==0??a[x][y+1]==0?)?)?||

? ? ?? (flag==4??(?a[x-2][y]==0??a[x+2][y]==0??a[x][y+1]==0?)?)?||

? ? ?? (flag==5??(?a[x][y-1]==0??a[x][y+1]==0??a[x-2][y]==0?)?)?||

? ? ?? (flag==6??(?a[x][?y-1]==0??a[x-2][y]==0??a[x+2][y]==0?)?)?||

? ? ?? (flag==7??(?a[x][y-1]==0??a[x][y+1]==0??a[x+2][y]==0?)?)?||

? ? ?? (flag==8??(?a[x][y+1]==0??a[x-2][y]==0??a[x+2][y+1]==0?)?)?||

? ? ?? (flag==9??(?a[x][y-1]==0??a[x-2][y]==0??a[x-2][y+1]==0?)?)?||

? ? ?? (flag==10??(?a[x][y-1]==0??a[x-2][y-1]==0??a[x+2][y]==0?)?)?||

? ? ?? (flag==11??(?a[x][y+1]==0??a[x+2][y-1]==0??a[x+2][y]==0?)?)?||

? ? ?? (flag==12??(?a[x][y-1]==0??a[x][y+1]==0??a[x-2][y-1]==0?)?)?||

? ? ? ( flag==13 ( a[x-2][y]==0 a[x+2][y-1]==0 a[x+2][y]==0 ) ) ||

????( flag==14 ( a[x][y-1]==0 a[x][y+1]==0 a[x+2][y+1]==0 ) ) ||

? ?? (flag==15 ( a[x-2][y]==0 a[x-2][y+1]==0 a[x+2][y]==0 ) ) ||

? ?? (flag==16 ( a[x][y+1]==0 a[x][y-1]==0 a[x+2][y-1]==0 ) ) ||

? ?? ( flag==17 ( a[x-2][y]==0 a[x+2][y+1]==0 a[x+2][y]==0 ) ) ||

????(flag==18 ( a[x][y-1]==0 a[x][y+1]==0 a[x-2][y+1]==0 ) ) ||

? ?? (flag==19 ( a[x-2][y]==0 a[x-2][y-1]==0

? ? ? ? ? ? ?a[x+2][y]==0?)?)?)?{?return?1;?}

}

return?0; ? //其它情况返回0

}

void?clNEXT(?) ? //清除框外的NEXT方块

{?flag?=?next;??x=ZL+WID+6;??y=ZL+10;??clfk(?);?}

void clHA(?) ? //清除满行的方块

{?int?k,?Hang=0; ?? //k是某行方块个数,?Hang是删除的方块行数

for(j=ZL+HEI-1;j=ZL+1;j--)??//当某行有WID/2-2个方块时,则为满行

{?k=0;?for(i=ZL+2;iZL+WID-2;i+=2)

{?if?(a[i][j]==1)???//竖坐标从下往上,横坐标由左至右依次判断是否满行

{?k++; ? //下面将操作删除行

? ?? if?(k==WID/2-2)? { ? for(k=ZL+2;kZL+WID-2;k+=2)

? ? ? ?? {?a[k][j]=0;?gtxy(k,j);?printf("??");?Sleep(1);?}

? ? ? ? for(k=j-1;kZL;k--)

? ? ? ? {?for(i=ZL+2;iZL+WID-2;i+=2)??//已删行数上面有方块,先清除再全部下移一行

? ? ? ? ? {?if(a[i][k]==1)?{?a[i][k]=0;?gtxy(i,k);?printf("??");a[i][k+1]=1;

? ? ? ? ? ? gtxy(i,k+1);?printf("□");?}?}

? ? ? ? ? }

? ? ? ? j++;?????//方块下移后,重新判断删除行是否满行

? ? ? ? Hang++;??//记录删除方块的行数

? ? ?? }

? ? }

?? }

}

score+=100*Hang; ? //每删除一行,得100分

if?(?Hang0??(score%500==0?||?score/500?level-1?)?) ?//得分满500速度加快升一级

? {?speed-=20;?level++;?if(speed200)speed+=20; }

}

一个简单的c语言写的俄罗斯方块程序?

1、考虑怎么存储俄罗斯方块

俄罗斯方块的形状一共有19种类型,如果拿数组来表示的话,可能会比较会浪费空间(网上有很多实现代码)

考虑到每种方块形状的范围是4 *4的小方块,用 字模点阵的方式来存储,即设置一个4行4列的数组,元素置1即代表这个位置有小?

方块,元素置0即代表这个位置无小方块,这个整个的4*4的数组组成俄罗斯方块的形状。?

1000?

1000?

1100?

0000?

上述4*4来表示L形状的方块。?

4*4 =16 bit 正好为short类型,所以每一个方块可以用一个short类型的数据来表示。

我们把俄罗斯方块点阵的数位存在rockArray中,我们可以事先把这19种方块的字模点阵自己转化成十六进制,然后在rockArray数组的初始化时赋值进去。?

但是这种方式扩展性不好,每当有一种新方块时需要改动,?

所以可以写一个配置文件来表示19种方块。(RockShape.ini)

@###@###@@######1234

从配置文件中读取方块的类型的代码在(Init.h的ReadRock函数中)在下面3中解释下代码如何实现

2如何画出方块

可以使用EasyX库来画出简单的图形,?

EasyX库是在VC下实现TC的简单绘图功能的一个库,这个库很容易学会(直接 百度EasyX库,里面有详细的教程)

那么如何画出方块,方块已经存储到一个short类型中了?

从short中读取出,可以用一个掩码mask = 1来与short的每个bit位相与,结果为1,则画出一个小方块;?

函数声明:

void DisplayRock(int rockIdx, ?RockLocation_t* ?LocatePtr, bool displayed)1

参数1:表示在数组中的下标,取出short类型的方块表示数据?

参数2:表示当前坐标,即画出方块的左上角的坐标x,y?

参数3:true表示画出该方块,false 表示擦除该方块。

//方块在图形窗口中的位置(即定位4*4大块的左上角坐标) ?typedef struct LOCATE

{ ? ?int left; ? ?int top;

} RockLocation_t;123456

3如何实现同一种类型方块的翻转,

在按‘↑’时应该翻转同一种类型的方块,?

比如下面的横杆和竖杆

@###@###@###@###@@@@############****1234567891011

可以假想成静态循环链表来实现这种方式?

使同一种类型的方块循环起来,

用一个struct结构来表示一种方块

typedef struct ROCK

{ ? ?//用来表示方块的形状(每一个字节是8位,用每4位表示方块中的一行)

unsigned short rockShapeBits; ? ?int ? ? ? ? ?nextRockIndex; ?//下一个方块,在数组中的下标 ?} RockType;123456

定义一个RockType类型的数组来存储19种方块?

RockType RockArray[19] = { (0, 0) };

当我们按“↑”时,把传入画方块函数DrawRock中的rockIndex变为当前方块结构体中的nextRockIndex即可。

简单解释下ReadRock函数的实现:当读取到空行的时候表示 一种方块已经读取完毕,当读取到****?行时 表示同一种类型的方块读取完毕,具体看代码实现,代码中具体的注释

4、主要游戏实现的逻辑

贴一个预览图吧?

注:上述预览图的游戏控制区和游戏显示区在Draw.h的DrawGameWindow()函数实现的

(1)在初始位置画出方块,在预览区画出下一次的方块?

(2)方块有两种行为:响应键盘命令UserHitKeyBoard(),自由下落?

如果敲击键盘了(w ,a ,s ,d, )空格表示暂停,如果在规定时间内没有敲击键盘的话,方块自由下落一个单位

if (kbhit()) //如果敲击键盘了 就处理按键

{

userHit = getch();

UserHitKeyBoard(userHit, curRockIndex, curRockLocation);

} ? ? ? ?//没有 就自动下移一个单位 :不能用else,因为可能按键不是上下左右

DWORD newtime = GetTickCount(); ? ? ? ?if (newtime - oldtime = (unsigned int)(300) moveAbled == TRUE)

{

oldtime = newtime;

DisplayRock(curRockIndex, curRockLocation, false);

curRockLocation.top += ROCK_SQUARE_WIDTH; //下落一格

}1234567891011121314

(3)当方块落地(即不能下移了)时,判断是否满行,如果满行则消除,然后再判断游戏是否结束,游戏结束的话,直接退出游戏

判断满行:FullLine()函数,从最底下的一行开始判断,直到遇到一行空行,

while (count != xROCK_SQUARE_NUM ) //遇到空行 14

{

linefull = true; ? ? ? ?count = 0; ? ? ? ?for (int i = 1; i = xROCK_SQUARE_NUM; ++i)

{ ? ? ? ? ? ?if (game_board[idx][i] == 0)

{

linefull = false; ? ? ? ? ? ? ? ?count++;

}

} ? ? ? ?if (linefull) //满行,消除当前行,更新分数

{

DelCurLine(idx);//消除满行

game_socres += 3;

UpdateSocres(game_socres);

idx++;//因为下面要减1

}

idx--;

}123456789101112131415161718192021

(4)消除满行?

将要删除的满行擦除:即将方块化成与背景色相同的,该代码为黑色?

然后将上面的一行向下移,移一行删除一行,直到遇到空行?

具体看代码的具体实现 game.h?

void DelCurLine(int rowIdx)

(4)判断方块是否能移动?

在game.h中实现

bool MoveAble(int rockIndex, RockLocation_t* currentLocatePtr, int f_direction)1

**比较当前位置的坐标(左上角)开始,能否放下rockIndex的方块。?

注:f_direction为”↑”的话,则传入的rockIndex为下一个方块**

如果不能移动的话,给游戏game_board设置标记表示该位置被占有

//全局变量-游戏板的状态描述(即表示当前界面哪些位置有方块) ?//0表示没有,1表示有(多加了两行和两列,形成一个围墙,便于判断方块是否能够移动) ?int game_board[yROCK_SQUARE_NUM + 2][xROCK_SQUARE_NUM + 2] = { 0 };123

实现过程遇到的一些问题

(1)在快速下落的时候,可能方块会掉出围墙的范围内,?

快速下落是使方块每次下落2个单位距离。?

在判断不能下落时,使当前坐标的top即y减去一个单位的距离

(2)遇到多行满行时消除不了,?

在判断满行时,循环找出满行,找出一个满行,就消除一行,然后继续判断是否满行,直到遇到空行

怎样制作俄罗斯方块

以下代码粘贴在主场经第一祯,测试影片就看到了:

N = 20;//行数

WIDTH = 20;//方块边长

level = 0;//开始等级(下落速度)

ret = new Array();//当前出现的方块

nextret = new Array();//下一个出现的方块

bg = new Array();//背景数组

createEmptyMovieClip("panel", 1048575);//所有方块都在此mc里

for (i = 0; i 5; i++) {

//初始化方块数组,2*5格式,前四行代表每个方块的4个小块的位置坐标,最后一行第一列是方块形状,第二列是方块旋转方向

ret.push(new Array(2));

nextret.push(new Array(2));

}

for (i = 0; i 20; i++) {//初始化背景数组,10*20格式

bg.push(new Array(10));

}

X = Y = panel._x = panel._y = 0;//换为X、Y表示

function reach(x:Number, y:Number, ret:Object) {

//x、y为方块位置,ret为方块形状,若方块ret下落一格碰到边界或者方块返回1

var i:Number, j:Number, k:Number;

for (i = 0; i N; i++) {

for (j = 0; j 10; j++) {

if (bg[i][j] == 219) {

for (k = 0; k 4; k++) {

if (x + ret[k][0] == j y + ret[k][1] + 1 == i) {

return 1;

}

}

}

}

}

return 0;

}

function lrnotout(lorr:Number, a:Object) {

//lorr==-1代表a往左边一格可行性的判断,lorr==1代表右边一格可行性的判断,lorr==0代表a的位置合理性的判断,出现不合理则返回0

var i:Number;

if (lorr == -1) {

for (i = 0; i 4; i++) {

if (x + a[i][0] - 1 0 || reach(x - 1, y - 1, a)) {

return 0;

}

}

}

if (lorr == 1) {

for (i = 0; i 4; i++) {

if (x + a[i][0] + 1 9 || reach(x - 1, y + 1, a)) {

return 0;

}

}

}

if (lorr == 0) {

for (i = 0; i 4; i++) {

if (x + a[i][0] 0 || x + a[i][0] 9) {

return 0;

}

}

}

return 1;

}

function rv(a:Object, ret:Object) {

//方块赋值,将a方块赋值到ret方块

var i:Number;

for (i = 0; i 5; i++) {

ret[i][0] = a[i][0], ret[i][1] = a[i][1];

}

}

function rotate(ret:Object) {

//根据方块ret最后一行(分别是形状指示变量和旋转方向变量)为ret的前四行赋以具体形状值

switch (ret[4][0]) {

case 0 ://方形

a = [[1, 0], [2, 0], [1, 1], [2, 1], [0, 0]];

rv(a, ret);

return;

case 1 ://长形

switch (ret[4][1]) {

case 1 :

a = [[0, 0], [1, 0], [2, 0], [3, 0], [1, 0]];

if (lrnotout(0, a) !reach(x, y - 1, a)) {

rv(a, ret);

}

return;

case 0 :

a = [[1, 0], [1, 1], [1, 2], [1, 3], [1, 1]];

if (lrnotout(0, a) !reach(x, y - 1, a)) {

rv(a, ret);

}

return;

}

case 2 ://Z形

switch (ret[4][1]) {

case 1 :

a = [[0, 1], [1, 1], [1, 2], [2, 2], [2, 0]];

if (lrnotout(0, a) !reach(x, y - 1, a)) {

rv(a, ret);

}

return;

case 0 :

a = [[2, 0], [1, 1], [2, 1], [1, 2], [2, 1]];

if (lrnotout(0, a) !reach(x, y - 1, a)) {

rv(a, ret);

}

return;

}

case 3 ://反Z形

switch (ret[4][1]) {

case 1 :

a = [[1, 1], [2, 1], [0, 2], [1, 2], [3, 0]];

if (lrnotout(0, a) !reach(x, y - 1, a)) {

rv(a, ret);

}

return;

case 0 :

a = [[1, 0], [1, 1], [2, 1], [2, 2], [3, 1]];

if (lrnotout(0, a) !reach(x, y - 1, a)) {

rv(a, ret);

}

return;

}

case 4 ://T形

switch (ret[4][1]) {

case 3 :

a = [[1, 0], [0, 1], [1, 1], [2, 1], [4, 0]];

if (lrnotout(0, a) !reach(x, y - 1, a)) {

rv(a, ret);

}

return;

case 0 :

a = [[1, 0], [0, 1], [1, 1], [1, 2], [4, 1]];

if (lrnotout(0, a) !reach(x, y - 1, a)) {

rv(a, ret);

}

return;

case 1 :

a = [[0, 1], [1, 1], [2, 1], [1, 2], [4, 2]];

if (lrnotout(0, a) !reach(x, y - 1, a)) {

rv(a, ret);

}

return;

case 2 :

a = [[1, 0], [1, 1], [2, 1], [1, 2], [4, 3]];

if (lrnotout(0, a) !reach(x, y - 1, a)) {

rv(a, ret);

}

return;

}

case 5 ://倒L形

switch (ret[4][1]) {

case 3 :

a = [[1, 0], [2, 0], [1, 1], [1, 2], [5, 0]];

if (lrnotout(0, a) !reach(x, y - 1, a)) {

rv(a, ret);

}

return;

case 0 :

a = [[0, 1], [0, 2], [1, 2], [2, 2], [5, 1]];

if (lrnotout(0, a) !reach(x, y - 1, a)) {

rv(a, ret);

}

return;

case 1 :

a = [[2, 0], [2, 1], [1, 2], [2, 2], [5, 2]];

if (lrnotout(0, a) !reach(x, y - 1, a)) {

rv(a, ret);

}

return;

case 2 :

a = [[0, 1], [1, 1], [2, 1], [2, 2], [5, 3]];

if (lrnotout(0, a) !reach(x, y - 1, a)) {

rv(a, ret);

}

return;

}

case 6 ://L形

switch (ret[4][1]) {

case 3 :

a = [[1, 0], [2, 0], [2, 1], [2, 2], [5, 0]];

if (lrnotout(0, a) !reach(x, y - 1, a)) {

rv(a, ret);

}

return;

case 0 :

a = [[0, 1], [1, 1], [2, 1], [0, 2], [5, 1]];

if (lrnotout(0, a) !reach(x, y - 1, a)) {

rv(a, ret);

}

return;

case 1 :

a = [[1, 0], [1, 1], [1, 2], [2, 2], [5, 2]];

if (lrnotout(0, a) !reach(x, y - 1, a)) {

rv(a, ret);

}

return;

case 2 :

a = [[2, 1], [0, 2], [1, 2], [2, 2], [5, 3]];

if (lrnotout(0, a) !reach(x, y - 1, a)) {

rv(a, ret);

}

return;

}

}

}

function generate(ret:Object) {//随机产生方块函数(可进一步修正)

ret[4][0] = Math.floor(Math.random() * 7);

ret[4][1] = Math.floor(Math.random() * 4);

rotate(ret);//完成方块ret的具体形状的赋值

}

function init() {//初始化背景、方块、运动函数

var i:Number, j:Number;

for (i = 0; i N; i++) {//初始化背景,边界为219,其余为' '

for (j = 0; j 10; j++) {

if (i == N - 1) {

bg[i][j] = 219;

} else {

bg[i][j] = ' ';

}

}

}

for (i = 0; i 5; i++) {//为当前方块赋初值0

ret[i][0] = ret[i][1] = 0;

}

generate(ret);//产生当前方块

generate(nextret);//产生下一个方块

y = 0, x = 3, score = lines = 0, level=0;//当前位置坐标和计分系统初始化

_tetris.removeTextField();//如果从结束过的游戏恢复,删除结束标志

display();//显示画面

frameflag = 0;//标示下落时间间隔

onEnterFrame = function () {

frameflag++;

if (10 - frameflag level) {//根据等级level确定下落时间间隔

frameflag = 0;

go();//下落及判断

}

};

}

function drawblock(a, b, c, d) {//绘制方块的小块

with (panel) {

beginFill(0x000FFF, 100);

lineStyle(1, 0xFF00FF);

moveTo(panel._x + a, panel._y + b);

lineTo(panel._x + c, panel._y + b);

lineTo(panel._x + c, panel._y + d);

lineTo(panel._x + a, panel._y + d);

lineTo(panel._x + a, panel._y + b);

endFill();

}

}

function erase() {//删除一行方块

var n:Number = 0, i:Number, j:Number, k:Number, l:Number;

for (i = 0; i N - 1; i++) {

for (j = 0; j 10; j++) {

if (bg[i][j] == ' ') {//如果该行有空,则开始判断下一行

i++, j = -1;

if (i == N - 1) {//行N-1为底线,不判断

break;

}

} else if (j == 9) {//判断到该行最后一列都没有空

for (k = i; k = 1; k--) {//上方方块下落

for (l = 0; l 10; l++) {

bg[k][l] = bg[k - 1][l];

}

}

for (l = 0; l 10; l++) {//删除该行

bg[0][l] = ' ';

}

n++;//此次删除行数变量增一

if ((lines + n) % 30 == 0) {//删除行数总数到30的倍数则等级上升

level = (level + 1) % 10;

}

}

}

}

lines += n, score += (n * n + n) * 50;//总行数增n,计算得分

}

function display() {

//显示函数,采用全部清除再重绘制的方法(因为这个程序本来是在Turbo C 2.0的文本环境下完成的)

var i:Number, j:Number;

panel.clear();

with (panel) {//画边界

lineStyle(1, 0x0000FF);

moveTo(panel._x, panel._y);

lineTo(panel._x + WIDTH * 10, panel._y);

lineTo(panel._x + WIDTH * 10, panel._y + WIDTH * (N - 1));

lineTo(panel._x, panel._y + WIDTH * (N - 1));

lineTo(panel._x, panel._y);

}

for (i = 0; i 4; i++) {//当前方块占据的地方赋值为边界类型219

bg[y + ret[i][1]][x + ret[i][0]] = 219;

}

for (i = 0; i N - 1; i++) {//绘制背景方块

for (j = 0; j 10; j++) {

if (bg[i][j] == 219) {

drawblock(j * WIDTH + X, i * WIDTH + Y, j * WIDTH + WIDTH + X, i * WIDTH + WIDTH + Y);

}

}

}

for (i = 0; i 4; i++) {//绘制当前方块

drawblock(nextret[i][0] * WIDTH + 14 * WIDTH + X, nextret[i][1] * WIDTH + 12 * WIDTH + Y, nextret[i][0] * WIDTH + WIDTH + 14 * WIDTH + X, nextret[i][1] * WIDTH + WIDTH + 12 * WIDTH + Y);

}

for (i = 0; i 4; i++) {//当前方块绘制完毕,重新将当前位置改为' '

bg[y + ret[i][1]][x + ret[i][0]] = ' ';

}

createTextField("_lvltxt", 1, 270, 100, 100, 20);//绘制计分系统

createTextField("_scrtxt", 2, 270, 130, 100, 20);

createTextField("_lnstxt", 3, 270, 160, 100, 20);

_lvltxt.text = "Level: " + level;

_scrtxt.text = "Score: " + score;

_lnstxt.text = "Lines: " + lines;

}

function go() {//下落函数

var sss:Number = reach(x, y, ret);//当前方块下落一格是否碰到边界或方块

var ii:Number;

if (!sss) {

y++;//如果当前方块下落一格没有碰到边界或方块则下落一格

}

display();//重新绘制

if (sss) {//碰到边界或方块

score += 10;//得10分

display();//重新绘制

for (ii = 0; ii 4; ii++) {//修改背景数组,将当前方块的位置改为边界类型

bg[y + ret[ii][1]][x + ret[ii][0]] = 219;

}

erase();//删除行判断及执行

rv(nextret, ret);//将下一个方块赋值为当前方块

y = 0, x = 3;//重置方块位置

generate(nextret);//生成下一个方块

display();//重新绘制

if (reach(x, y, ret)) {//如果下一格碰到方块则游戏结束

createTextField("_tetris", 100000, WIDTH * 3.3, WIDTH * N / 3, 70, 20);

_tetris._x += 200;

_tetris._y += 50;

_tetris._xscale = 300;

_tetris._yscale = 300;

_tetris.background = true;

_tetris.text = "Game Over!";

onEnterFrame = function () {//停止下落

};

}

}

}

function key() {

if (Key.isDown(Key.UP)) {

rotate(ret);

display();

}

if (Key.isDown(Key.LEFT)) {

if (lrnotout(-1, ret)) {//左移可行性判断

x--;

display();

}

}

if (Key.isDown(Key.RIGHT)) {

if (lrnotout(1, ret)) {//右移可行性判断

x++;

display();

}

}

if (Key.isDown(Key.DOWN)) {//键盘控制下落

go();

}

if (Key.isDown(Key.SPACE)) {//一键下落到底

while (!reach(x, y, ret)) {

y++;

}

go();

}

if (Key.isDown(82)) { //重新开始游戏

init();

}

}

init();//初始化

setInterval(key, 80);//每个80毫秒执行一次键盘事件函数

createTextField("hinttxt",33324,200,20,300,50);

hinttxt.text="键盘键:上,下,左,右,R(reset),空格";

(责任编辑:IT教学网)

更多

推荐鼠标代码文章