C语言俄罗斯方块(详解..)
C语言_俄罗斯方块_VS2010
![C语言_俄罗斯方块_VS2010](https://img.taocdn.com/s3/m/7cec368ed4d8d15abe234ef8.png)
}
// 如果有按键,返回按键对应的功能
if (_kbhit())
{
switch(_getch())
{
case 'w':
case 'W': return CTRL_ROTATE;
case 'a':
case ' ': return CTRL_SINK;
case 0:
case 0xE0:
switch(_getch())
{
case 72: return CTRL_ROTATE;
case 75: return CTRL_LEFT;
{
case CTRL_ROTATE: OnRotate(); break;
case CTRL_LEFT: OnLeft(); break;
case CTRL_RIGHT: OnRight(); break;
void OnLeft(); // 左移方块
void OnRight(); // 右移方块
void OnDown(); // 下移方块
void OnSink(); // 沉底方块
/////////////////////////////////////////////
// 函数定义
COLORREF color; // 方块的颜色
} g_Blocks[7] =
{
{0x0F00, 0x4444, 0x0F00, 0x4444, RED}, // I
{0x0660, 0x0660, 0x0660, 0x0660, BLUE}, // 口
教你用c语言写俄罗斯方块
![教你用c语言写俄罗斯方块](https://img.taocdn.com/s3/m/24f75ed476a20029bd642d79.png)
来如鹏挺长时间了,受益很多希望更多的朋学加入进来做俄罗斯方块是因为无意中在杨老师的帖子看到说最少也要能做出俄罗斯方块这样的东西出来,我想这个意思能做出俄罗斯方块就说明水平到了一个层次了吧。
刚才注意到音乐播放器居然下载超过400次!我反醒我上传的代码很少解释而且做的都是没有趣味的东西。
俄罗斯方块如鹏已经有好几个同学做出来了,但是我想还有很多同学做不出来,我抛砖引玉,其实俄罗斯方块并不复杂今天先告诉大家第一步,在屏幕上把方块显示出来cfree 新建一个工程选窗口程序显示helloworld的win32的 api 图形函数都要用到 HDC 这是一个保存窗口图形的数据的句柄比如我要画一个正方形可以用Rectangle (hdc,标X,左上角坐标y,右下角坐标x,右下角坐标y);为了方便我们直接在switch (message){case WM_PAINT:hdc = BeginPaint(hWnd, &ps);// 这个下面添加代码Rectangle (hdc,50,50,100,100);然后编译运行这是效果就是一个正方形没别的东西?别着急哈,慢慢来。
俄罗斯方块每块都是四部分的所以要画4个这里面需要一小点数学知识把这些复制到刚才的位置看一下效果{int x,y;const int size=50;//方块大小x=y=50;//从窗口的左上角位置开始画//第一个方块Rectangle (hdc,x,y,x+size,y+size);x+=size; //向右一块位置画第二个方块Rectangle (hdc,x,y,x+size,y+size);x+=size; //向右一块位置画第三个方块Rectangle (hdc,x,y,x+size,y+size);//最后一个方块//相对于第三个方块左下角的位置x-=50;y-=50;Rectangle (hdc,x,y,x+size,y+size);}这个画好像很麻烦我们可以自定义一个函数huafangkuai专门负责画这个正方形以后所有的其他函数也必须经过他才能画正方形这个类似于win32 api的封装思想void huafangkuai(int x,int y,int color);x y是方块的坐标color 就是color函数原理是x y 是相对于游戏里的坐标而不是屏幕坐标屏幕坐标要经过函数自己转换这样我们就可以把心关注在游戏的事情而不必分心了void huafangkuai(HDC hdc,int x,int y,int color){const int BEGINX= 50;//游戏图形的开始位置const int BEGINY= 50 ;const int FSIZE= 35 ; //方块大小int screenx=BEGINX +x*FSIZE; //方块左上角的坐标是x乘方块大小再加上起始位置int screeny=BEGINY +y*FSIZE;Rectangle (hdc,screenx,screeny,screenx+FSIZE,screeny+FSIZE);}这样我们再画就四个就容易多了 color 先不管int x,y;x=5;y=5;huafangkuai(hdc,x,y,0);huafangkuai(hdc,x+1,y,0);huafangkuai(hdc,x+2,y,0);huafangkuai(hdc,x+1,y+1,0);这样就画出了一个方块形状但是怎么能画出其它的呢?请听下回分解.弄这点东西我费了一个多小时时间 ...我终于理解为什么杨老师问最近没人反馈备课再加录视频一定花了很多心血可是没有几个同学问问题或做作业的心情...leeco 说的是我以前很少写注释这回一写反而乱写一通下次改进下一步有一些麻烦了为了省代码还是再定义一个函数void DrawTetris(HDC hdc, int dir,int shape,int color,int x,int y)dir 是方块的4个方向 shape 是形状比如有L 形 |形和田形 x y 游戏中的坐标我们定义一个全局数组把俄罗斯方块中7种不同的正式形状都保存在里面调用这个函数之后能把要求的方块显示出来void DrawTetris(HDC hdc, int dir,int shape,int color,int x,int y){int nx,ny;for(int i=0;i<4;i++){nx=SQRARRAY[shape][dir].x+x;ny=SQRARRAY[shape][dir].y+y;huafangkuai(hdc,nx,ny,color);}}要求所有的方块的形状都弄好我费了不少时间这个就是全局数组放到代码的最上面每4行是1个形状最后一个全是一样的就是田形const POINT SQRARRAY[7][FOUR][FOUR]={{0,-1,0,0,1,0,2,0,1,0,0,0,0,1,0,2,0,1,0,0,-1,0,-2,0,-1,0,0,0,0,-1,0,-2},{-1,0,0,0,0,1,0,2,-1,0,0,0,-2,0,0,-1,0,-1,0,0,0,-2,1,0,0,1,0,0,1,0,2,0},{ -1,0,0,0,0,-1,1,0,0,-1,0,0,1,0,0,1,-1,0,0,0,0,1,1,0,-1,0,0,0,0,-1,0,1},{ 0,-1,0,0,1,0,1,1,1,0,0,0,0,1,-1,1,0,-1,0,0,1,0,1,1,1,0,0,0,0,1,-1,1,},{ 0,-1,0,0,-1,0,-1,1,-1,0,0,0,0,1,1,1,0,-1,0,0,-1,0,-1,1,-1,0,0,0,0,1,1,1},{-1,0,0,0,1,0,2,0,0,-1,0,0,0,1,0,2,-1,0,0,0,1,0,2,0,0,-1,0,0,0,1,0,2},{-1,0,0,0,-1,1,0,1,-1,0,0,0,-1,1,0,1,-1,0,0,0,-1,1,0,1,-1,0,0,0,-1,1,0,1}} ;先调用试试效果switch (message){case WM_PAINT:hdc = BeginPaint(hWnd, &ps);//在这的加入这些static int shape=0;static int dir=0;++dir%=4;++shape%=7;DrawTetris(hdc,dir,shape,0,3,3);运行之后双击程序的标题栏要求窗口刷新每次图形都会变化下一步是想让图形怎么动起来这个要响应键盘消息在wm_paint 下面找到break;在break;下面的地方加入由于不在wm_paint 里面我们只能自己用getdc得到HDCcase WM_KEYDOWN:switch(wParam){case VK_SPACE:HDC hdc= GetDC(hWnd);static int shape=0;++shape%=7;DrawTetris(hdc,0,shape,0,6,2);ReleaseDC(hWnd,hdc);break;}break;这回VK_SPACE 就是空格还有其它键比如VK_DOWNVK_LEFTVK_RIGHT再运行之后按空格键图形都在一直变化但是变成这样的了因为每显示一次都不清除前面的话就这样这个怎么解决呢?未完待续...谢谢支持我以为没有同学感兴趣呢为了不显示混乱所以一定要先擦除前的用的方法是用背景色的画笔再画一遍定义一个结构体保存现在方块和以前方块的位置struct PosInfo{int x,y,dir,shape;};PosInfo CurrentPos,PrePos;//全局变量HPEN PenArray[10];PosInfo CurrentPos,PrePos;再定义一组画笔在程序开始时用这个函数初初化void Init(HWND hwnd){PenArray [0]=CreatePen(PS_SOLID,0,RGB(255,255,255));//现在是白色背景PenArray [1]=CreatePen(PS_SOLID,0,RGB(120,120,120));CurrentPos.dir=0;CurrentPos.shape=0;CurrentPos.x=2;CurrentPos.y=2;PrePos=CurrentPos;}在键盘击下后用这个函数改变方块位置void KeyDown(int keycode,HWND hwnd){HDC hdc= GetDC(hwnd);switch(keycode){case VK_LEFT:break;case VK_RIGHT:CurrentPos.x++;DrawTetris(hdc,PrePos.dir,PrePos.shape,0,PrePos.x,PrePos.y);DrawTetris(hdc,CurrentPos.dir,CurrentPos.shape,1,CurrentPos.x,CurrentPos.y); PrePos=CurrentPos;break;case VK_DOWN:break;case VK_SPACE:break;}ReleaseDC(hwnd,hdc);}然后就是检查方块是不是出格了用这个函数 MAPX MAPY 是游戏里数组的长和高map [][]是保存方块有没被放置状态有还是没有bool Check(int dir,int pX,int pY,int shape){int x,y;for(int ff=0;ff<4;ff++){x= SQRARRAY[shape][dir][ff].x+pX;y= SQRARRAY[shape][dir][ff].y+pY;if(x<0 || x>=MAPX || y<0 ||y>=MAPY ||map[Pos[ff].x][Pos[ff].y]!=0){return FALSE;}}return TRUE;}1.#include "tetris.h"2.const int BEGINX= 50;//游戏图形的开始位置3.const int BEGINY= 50 ;4.const int FSIZE= 19 ; //方块大小5.const int FOUR =4;6.const int MAPX =10;7.const int MAPY=20;8.struct PosInfo9.{10.int x,y,dir,shape;11.};12.13.PosInfo CurrentPos,PrePos;//全局变量14.int GameMap[MAPX][MAPY]; //游戏方格15.16.HBRUSH PenArray[10];//用画刷可以用fillrect 画实心的图形17.void Init(HWND hwnd)18.{19.20.PenArray [0]=CreateSolidBrush(RGB(255,255,255));//现在是白色背景21.PenArray [1]=CreateSolidBrush(RGB(120,120,120));22.CurrentPos.dir=0;23.CurrentPos.shape=0;24.CurrentPos.x=2;25.CurrentPos.y=2;26.PrePos=CurrentPos;27.}28.29.30.const POINT SQRARRAY[7][FOUR][FOUR]=31.{32.{0,-1,0,0,1,0,2,0,33.1,0,0,0,0,1,0,2,34.0,1,0,0,-1,0,-2,0,35.-1,0,0,0,0,-1,0,-2},36.{-1,0,0,0,0,1,0,2,37.-1,0,0,0,-2,0,0,-1,38.0,-1,0,0,0,-2,1,0,39.0,1,0,0,1,0,2,0},40.41.{ -1,0,0,0,0,-1,1,0,42.0,-1,0,0,1,0,0,1,43.-1,0,0,0,0,1,1,0,44.-1,0,0,0,0,-1,0,1},45.{ 0,-1,0,0,1,0,1,1,46.1,0,0,0,0,1,-1,1,47.0,-1,0,0,1,0,1,1,48.1,0,0,0,0,1,-1,1,49.},50.{ 0,-1,0,0,-1,0,-1,1,51.-1,0,0,0,0,1,1,1,52.0,-1,0,0,-1,0,-1,1,53.-1,0,0,0,0,1,1,1},54.55.{-1,0,0,0,1,0,2,0,56.0,-1,0,0,0,1,0,2,57.-1,0,0,0,1,0,2,0,58.0,-1,0,0,0,1,0,2},59.60.{-1,0,0,0,-1,1,0,1,61.-1,0,0,0,-1,1,0,1,62.-1,0,0,0,-1,1,0,1,63.-1,0,0,0,-1,1,0,1}64.} ;65.66.67.68.69.void huafangkuai(HDC hdc,int x,int y,int color)70.{71.72.int screenx=BEGINX +x*FSIZE; //方块左上角的坐标是x乘方块大小再加上起始位置73.int screeny=BEGINY +y*FSIZE;74.RECT rt;75.rt.left=screenx;76.rt.top=screeny;77.rt.right=screenx+FSIZE;78.rt.bottom=screeny+FSIZE;79.FillRect(hdc,&rt ,PenArray[color]);80.81.82.}83.84.//画所有7种俄罗斯方块 dir方块的方向 shape 方块的形状85.void DrawTetris(HDC hdc, int dir,int shape,int color,int x,int y)86.{87.88.89.90.int nx,ny;91.for(int i=0;i<4;i++)92.{93.94.nx=SQRARRAY[shape][dir].x+x;ny=SQRARRAY[shape][dir].y+y;95.huafangkuai(hdc,nx,ny,color);96.}97.}98.99.100.void KeyDown(int keycode,HWND hwnd)101.{102.HDC hdc= GetDC(hwnd);103.104.switch(keycode)105.{106.case VK_LEFT:107.if(!Check(CurrentPos.dir,CurrentPos.x-1,CurrentPos.y,CurrentPos.shape)) 108.{109.return;110.}111.112.CurrentPos.x--;113.DrawTetris(hdc,PrePos.dir,PrePos.shape,0,PrePos.x,PrePos.y);114.DrawTetris(hdc,CurrentPos.dir,CurrentPos.shape,1,CurrentPos.x,CurrentPos.y); 115.PrePos=CurrentPos;116.break;117.case VK_RIGHT:118.119.if(!Check(CurrentPos.dir,CurrentPos.x+1,CurrentPos.y,CurrentPos.shape)) 120.{121.return;122.}123.CurrentPos.x++;124.DrawTetris(hdc,PrePos.dir,PrePos.shape,0,PrePos.x,PrePos.y);125.DrawTetris(hdc,CurrentPos.dir,CurrentPos.shape,1,CurrentPos.x,CurrentPos.y); 126.PrePos=CurrentPos;127.break;128.case VK_DOWN:129.if(!Check(CurrentPos.dir,CurrentPos.x,CurrentPos.y+1,CurrentPos.shape))130.{131.return;132.}133.CurrentPos.y++;134.DrawTetris(hdc,PrePos.dir,PrePos.shape,0,PrePos.x,PrePos.y);135.DrawTetris(hdc,CurrentPos.dir,CurrentPos.shape,1,CurrentPos.x,CurrentPos.y); 136.PrePos=CurrentPos;137.break;138.case VK_SPACE:139.if(!Check((CurrentPos.dir+1)%4,CurrentPos.x,CurrentPos.y,CurrentPos.shape)) 140.{141.return;142.}143.++CurrentPos.dir%=4;144.DrawTetris(hdc,PrePos.dir,PrePos.shape,0,PrePos.x,PrePos.y);145.DrawTetris(hdc,CurrentPos.dir,CurrentPos.shape,1,CurrentPos.x,CurrentPos.y); 146.PrePos=CurrentPos;147.break;148.}149.ReleaseDC(hwnd,hdc);150.}151.152.153.//check 检查方块移动时是否有数组越界情况有则什么也不执行154.bool Check(int dir,int pX,int pY,int shape)155.156.{157.int x,y;158.for(int ff=0;ff<4;ff++)159.{160.x= SQRARRAY[shape][dir][ff].x+pX;161.y= SQRARRAY[shape][dir][ff].y+pY;162.if(x<0 || x>=MAPX || y<0 ||y>=MAPY ||GameMap[x][y]!=0)163.{164.return FALSE;165.}166.}167.168.return TRUE;169.170.}171.172.//画已经放在下面的方块通过检查数组是否大于0 是则画数数里面的色彩173.//否则画白色擦除174.void DrawMap(HDC hdc )175.{176.177.Rectangle(hdc,BEGINX-10,BEGINY-10,BEGINX+MAPX*FSIZE+10,BEGINY+MAPY*FSIZE+10); 178.//画基本的外框179.for(int x=0;x<MAPX;x++)180.{181.for(int y=0;y<MAPY;y++)182.{183.if(GameMap[x][y]>0)184.{185.huafangkuai(hdc,x,y,GameMap[x][y]);186.}187.else188.{189.huafangkuai(hdc,x,y,0);190.}191.}192.}193.}194.DrawTetris(hdc,PrePos.dir,PrePos.shape,0,PrePos.x,PrePos.y);DrawTetris(hdc,CurrentPos.dir,CurrentPos.shape,1,CurrentPos.x,CurrentPos.y);这个0就是调用和窗口一样的画刷1呢是我定义的方块的颜色PrePos 保存的是方块未移动时的位置DrawTetris(hdc,PrePos.dir,PrePos.shape,0,PrePos.x,PrePos.y);之后因为和之前画的在一个地方而且是白色的所以前面画的就清除掉了195.。
C语言实现俄罗斯方块
![C语言实现俄罗斯方块](https://img.taocdn.com/s3/m/d9f0ca05bceb19e8b8f6baaf.png)
模块1.界面设计
基本符合一般的俄罗斯方块游戏; 我们设计时考虑倒我们屏幕的大小,采用
16X24的方格阵.背景用蓝色,墙用红色, 墙 内用白色. 这部分已设计好,看演示!
模块2.定义所有方块
所有俄罗斯方块都是有四个方格,所有可能情况有二 十种(由于方块所占比率太小,有两!颜色随机!)
具体如下:0. 1.
三.所用知识:
基本的C语言知识。 数据结构。 图形交互技术。 算法分析和设计。 数据库知识. 人工智能
四.模块分析
根据七种功能可得到六个模块. 分别为:1.界面; 2.方块; 3.下落及控制; 4.碰壁停止; 5.消行及玩完; 6.电脑判别最优走法(难) 7.记录.(难) 具体见下:
这一部分比较难,我们正在查找相应的书,学 习相应的知识.
模块7.玩者姓名及成绩排行榜
分数由所消行数及难度确定. 设计时定义好. 在指定时间之内,或失败后都有一个最终分
数.可以选择记录之.这将会被录入对应文件. 用到C语言的文件操作. 能够调出排行榜,及最高纪录.用到数据库方 面知识,及排序. 这一部分不容易,我们还在思考之中!
3.头节点及方块号码数据结构:
typedef struct{ Pos node0; /*int x1;int y1;*/ //方块头节点左上点 int num; //方块号码不同,对应形状不同
}PosType;
4.方块定义:
typedef struct{ Pos node[4]; //0号为头节点,其他三个与之对应 int color; //方块颜色 }Square;
言实现的。 这里我们要用C语言实现之。
二.功能分析:
1具有基本的游戏背景/界面。 2能随机生成所有可能的方块。 3能根据难度确定方块下落速度。 4能用键盘控制方向,变形。 5方块判别停止条件及墙壁。 6能判别消行及游戏结束。 7电脑能自动玩,可以选择人机对抗玩.(难) 8能记录玩者姓名及最佳成绩。
俄罗斯方块 变形 c语言
![俄罗斯方块 变形 c语言](https://img.taocdn.com/s3/m/6e062244bb1aa8114431b90d6c85ec3a86c28b4a.png)
俄罗斯方块变形c语言在C语言中实现俄罗斯方块游戏是一项复杂的任务,涉及到图形界面、游戏逻辑和事件处理等多个方面。
以下是一个简化版的俄罗斯方块游戏示例,使用字符在控制台中显示游戏界面。
c复制代码#include<stdio.h>#include<stdlib.h>#include<unistd.h>#define WIDTH 20#define HEIGHT 10typedef enum {BLOCK_EMPTY,BLOCK_I,BLOCK_J,BLOCK_L,BLOCK_O,BLOCK_S,BLOCK_Z} BlockType;typedef struct {BlockType type;int x;int y;} Block;Block board[WIDTH][HEIGHT];BlockType currentBlock = BLOCK_I;int rotation = 0;int x = WIDTH / 2;int y = HEIGHT - 1;void drawBoard() {for (int i = 0; i < WIDTH; i++) { for (int j = 0; j < HEIGHT; j++) { char ch = ' ';switch (board[i][j].type) {case BLOCK_EMPTY:ch = '.';break;case BLOCK_I:ch = 'I';break;case BLOCK_J:ch = 'J';break;case BLOCK_L:ch = 'L';break;case BLOCK_O:ch = 'O';break;case BLOCK_S:ch = 'S';break;case BLOCK_Z:ch = 'Z';break;}printf("%c", ch);}printf("\n");}}void updateBoard() {for (int i = 0; i < WIDTH; i++) {for (int j = 0; j < HEIGHT; j++) {if (board[i][j].type != BLOCK_EMPTY) {board[i][j].y--; // Move block down one row.} else { // Place new block.switch (currentBlock) { // Place based on current block type.case BLOCK_I: // Place full I-block.board[i][j].type = BLOCK_I; // Column.j y row.i X -- column.j+1 y row.i X -- column.j y row.i+1 X -- column.j+1 y row.i+1 X -- column.j y row.i X -- column.j+1 y row.i X -- column.j y row.i+1 X -- column.j+1 y row.i+1 X -- column.j y row.i X -- column.j+1 y row.i X -- column.j y row.i+1 X -- column.j+1 y row.i+1 X -- column.j y row.i X -- column.j+1 y row.i X -- column.j y row.i+1 X -- column.j+1 y row.i+1 X -- column.j y row.i X -- column.j+1 y row.i X -- column.j y row.i+1 X -- column.j+1 y row.i+1 X -- column.j y row.i X -- column.j+1 y row.i X -- column.j y row.i+1 X -- column.j+1 y row.i+1 X -- column.j y row.i X -- column.j+1 y row.i X -- column.j y row.i+1 X -- column j Y n Row Y j Columns n - j 1 -- i 1 i - i j Row i Row i - 1 i Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column Column n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i - - - - - - - - - - - - - - -。
C语言俄罗斯方块
![C语言俄罗斯方块](https://img.taocdn.com/s3/m/2f1060e29b89680203d8258b.png)
gotoxy(52,2+i);
puts("▓");
}
int t;
FILE *fp=fopen("C:\\els.txt","r");
fscanf (fp,"%d",&t);
fclose(fp);
color(43);
gotoxy(37,12);
{{0, 0,-2,-2},{0,-1,-1,-2}},{{0, 0, 2, 4},{0,-1, 0, 0}},
{{0, 0, 0, 2},{0,-1,-2,-2}},{{0, 0,-2,-4},{0,-1,-1,-1}},
{{0, 2, 2, 2},{0, 0,-1,-2}},{{0, 2, 4, 4},{0, 0, 0,-1}},
{2,{-2,2},{0,0}},
{4,{-2,0,4,-2},{0,0,-1,1}},
{4,{-4,2,-2,4},{0,0,-1,1}},
{4,{-2,2,0,0},{0,0,0,0}},
};
void gotoxy(int x, int y)
{
COORD pos;
pos.X = x;
{
int i;
int x=43,y=6;
color(34);
for(i=0;i<4;i++)
{
gotoxy(x-3,y+i-2);
puts(" ");
}
pri_kind=pkind;
if(pkind==6) pkind=15,x--;
俄罗斯方块代码c语言详解
![俄罗斯方块代码c语言详解](https://img.taocdn.com/s3/m/93efb63058eef8c75fbfc77da26925c52cc591e8.png)
俄罗斯方块代码c语言详解
俄罗斯方块代码c语言详解:。
1、首先在C语言中定义游戏中所使用的数组及变量,这些变量包括游戏方块的位置、颜色、下落时间等。
同时,在这里将建立一个随机数发生器用来随机选择方块的出现类型。
2、然后,在C语言中实现游戏画面的显示,采用双缓冲方式,首先建立游戏画面的背景,然后将方块的形状和颜色绘制到背景上。
3、接着,在C语言中实现游戏方块的操作,实现主要包括按键控制方块的旋转、移动等,并且可以判断方块是否能成功下落,从而实现游戏的控制。
4、最后,在C语言中实现游戏的得分计算功能,通过计算消除一行方块得到积分,具体积分根据游戏难度而设置,以达到让玩家继续游戏的目的。
c语言怎样编写俄罗斯方块
![c语言怎样编写俄罗斯方块](https://img.taocdn.com/s3/m/3eb50b2a4531b90d6c85ec3a87c24028915f85ba.png)
linesCleared++; for (int k = i; k > 0; k--) {
for (int j = 0; j < WIDTH; j++) { board[k][j] = board[k - 1][j];
} } for (int j = 0; j < WIDTH; j++) {
board[0][j] = 0; } } } printf("Lines cleared: %d\n", linesCleared); }
if (kbhit()) { char key = getch(); switch (key) { case 'a': if (!checkCollision(shapeX - 1, shapeY, shape)) { shapeX--; } break; case 'd': if (!checkCollision(shapeX + 1, shapeY, shape)) { shapeX++; } break; case 's': if (!checkCollision(shapeX, shapeY + 1, shape)) { shapeY++; } break; case 'w': int tempShape[4][4]; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { tempShape[i][j] = shape[i][j]; } } rotateShape(tempShape); if (!checkCollision(shapeX, shapeY, tempShape)) { rotateShape(shape); } break; case 'q': exit(0); }
俄罗斯方块C语言代码(计算机类)
![俄罗斯方块C语言代码(计算机类)](https://img.taocdn.com/s3/m/14bdb8c476c66137ef06191c.png)
#include <stdio.h>#include <dos.h>#include <conio.h>#include <graphics.h>#include <stdlib.h>#ifdef__cplusplus#define __CPPARGS ...#else#define __CPPARGS#endif#define MINBOXSIZE 15 /* 最小方块的尺寸*/#define BGCOLOR 7 /* 背景着色*/#define GX 200#define GY 10#define SJNUM 10000 /* 每当玩家打到一万分等级加一级*/ /* 按键码*/#define VK_LEFT 0x4b00#define VK_RIGHT 0x4d00#define VK_DOWN 0x5000#define VK_UP 0x4800#define VK_HOME 0x4700#define VK_END 0x4f00#define VK_SPACE 0x3920#define VK_ESC 0x011b#define VK_ENTER 0x1c0d/* 定义俄罗斯方块的方向(我定义他为4种)*/#define F_DONG 0#define F_NAN 1#define F_XI 2#define F_BEI 3#define NEXTCOL 20 /* 要出的下一个方块的纵坐标*/#define NEXTROW 12 /* 要出的下一个方块的横从标*/#define MAXROW 14 /* 游戏屏幕大小*/#define MAXCOL 20#define SCCOL 100 /*游戏屏幕大显示器上的相对位置*/#define SCROW 60int gril[22][16]; /* 游戏屏幕坐标*/int col=1,row=7; /* 当前方块的横纵坐标*/int boxfx=0,boxgs=0; /* 当前寺块的形壮和方向*/int nextboxfx=0,nextboxgs=0,maxcol=22;/*下一个方块的形壮和方向*/ int minboxcolor=6,nextminboxcolor=6;int num=0; /*游戏分*/int dj=0,gamedj[10]={18,16,14,12,10,8,6,4,2,1};/* 游戏等级*//* 以下我用了一个3维数组来纪录方块的最初形状和方向*/int boxstr[7][4][16]={{{1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0},{0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0},{1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0},{0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0}},{{0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0},{1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0},{0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0},{1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0}},{{1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0},{1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0},{1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0},{0,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0}},{{1,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0},{1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0},{0,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0},{1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0}},{{0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0},{0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0},{0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0},{0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0}},{{1,1,0,0,1,1,0,0,0,0,0,0.0,0,0,0},{1,1,0,0,1,1,0,0,0,0,0,0.0,0,0,0},{1,1,0,0,1,1,0,0,0,0,0,0.0,0,0,0},{1,1,0,0,1,1,0,0,0,0,0,0.0,0,0,0}},{{0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0},{1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0},{0,1,0,0,1,1,1,0,0,0,0,0.0,0,0,0},{0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0}}};/* 随机得到当前方块和下一个方块的形状和方向*/void boxrad(){minboxcolor=nextminboxcolor;boxgs=nextboxgs;boxfx=nextboxfx;nextminboxcolor=random(14)+1;if(nextminboxcolor==4||nextminboxcolor==7||nextminboxcolor==8) nextminboxcolor=9;nextboxfx=F_DONG;nextboxgs=random(7);}/*初始化图形模试*/void init(int gdrive,int gmode){int errorcode;initgraph(&gdrive,&gmode,"e:\\tc");errorcode=graphresult();if(errorcode!=grOk){printf("error of: %s",grapherrormsg(errorcode));exit(1);}}/* 在图形模式下的清屏*/void cls(){setfillstyle(SOLID_FILL,0);setcolor(0);bar(0,0,640,480);}/*在图形模式下的高级清屏*/void clscr(int a,int b,int c,int d,int color){setfillstyle(SOLID_FILL,color);setcolor(color);bar(a,b,c,d);}/*最小方块的绘制*/void minbox(int asc,int bsc,int color,int bdcolor){int a=0,b=0;a=SCCOL+asc;b=SCROW+bsc;clscr(a+1,b+1,a-1+MINBOXSIZE,b-1+MINBOXSIZE,color);if(color!=BGCOLOR){setcolor(bdcolor);line(a+1,b+1,a-1+MINBOXSIZE,b+1);line(a+1,b+1,a+1,b-1+MINBOXSIZE);line(a-1+MINBOXSIZE,b+1,a-1+MINBOXSIZE,b-1+MINBOXSIZE); line(a+1,b-1+MINBOXSIZE,a-1+MINBOXSIZE,b-1+MINBOXSIZE); }}/*游戏中出现的文字*/void txt(int a,int b,char *txt,int font,int color){setcolor(color);settextstyle(0,0,font);outtextxy(a,b,txt);}/*windows 绘制*/void win(int a,int b,int c,int d,int bgcolor,int bordercolor){clscr(a,b,c,d,bgcolor);setcolor(bordercolor);line(a,b,c,b);line(a,b,a,d);line(a,d,c,d);line(c,b,c,d);}/* 当前方块的绘制*/void funbox(int a,int b,int color,int bdcolor){int i,j;int boxz[4][4];for(i=0;i<16;i++)boxz[i/4][i%4]=boxstr[boxgs][boxfx][i];for(i=0;i<4;i++)for(j=0;j<4;j++)if(boxz[i][j]==1)minbox((j+row+a)*MINBOXSIZE,(i+col+b)*MINBOXSIZE,color,bdcolor); }/*下一个方块的绘制*/void nextfunbox(int a,int b,int color,int bdcolor){int i,j;int boxz[4][4];for(i=0;i<16;i++)boxz[i/4][i%4]=boxstr[nextboxgs][nextboxfx][i];for(i=0;i<4;i++)for(j=0;j<4;j++)if(boxz[i][j]==1)minbox((j+a)*MINBOXSIZE,(i+b)*MINBOXSIZE,color,bdcolor);}/*时间中断定义*/#define TIMER 0x1cint TimerCounter=0;void interrupt ( *oldhandler)(__CPPARGS);void interrupt newhandler(__CPPARGS){TimerCounter++;oldhandler();}void SetTimer(void interrupt (*IntProc)(__CPPARGS)){oldhandler=getvect(TIMER);disable();setvect(TIMER,IntProc);enable();}/*由于游戏的规则,消掉都有最小方块的一行*/void delcol(int a){int i,j;for(i=a;i>1;i--)for(j=1;j<15;j++){minbox(j*MINBOXSIZE,i*MINBOXSIZE,BGCOLOR,BGCOLOR); gril[i][j]=gril[i-1][j];if(gril[i][j]==1)minbox(j*MINBOXSIZE,i*MINBOXSIZE,minboxcolor,0);}}/*消掉所有都有最小方块的行*/void delete(){int i,j,zero,delgx=0;char *nm="00000";for(i=1;i<21;i++){zero=0;for(j=1;j<15;j++)if(gril[j]==0)zero=1;if(zero==0){delcol(i);delgx++;}}num=num+delgx*delgx*10;dj=num/10000;sprintf(nm,"%d",num);clscr(456,173,500,200,4);txt(456,173,"Number:",1,15);txt(456,193,nm,1,15);}/*时间中断结束*/void KillTimer(){disable();setvect(TIMER,oldhandler);enable();}/* 测试当前方块是否可以向下落*/int downok(){int i,j,k=1,a[4][4];for(i=0;i<16;i++)a[i/4][i%4]=boxstr[boxgs][boxfx][i]; for(i=0;i<4;i++)for(j=0;j<4;j++)if(a[j] && gril[col+i+1][row+j])k=0;return(k);}/* 测试当前方块是否可以向左行*/ int leftok(){int i,j,k=1,a[4][4];for(i=0;i<16;i++)a[i/4][i%4]=boxstr[boxgs][boxfx][i]; for(i=0;i<4;i++)for(j=0;j<4;j++)if(a[j] && gril[col+i][row+j-1])k=0;return(k);}/* 测试当前方块是否可以向右行*/ int rightok(){int i,j,k=1,a[4][4];for(i=0;i<16;i++)a[i/4][i%4]=boxstr[boxgs][boxfx][i]; for(i=0;i<4;i++)for(j=0;j<4;j++)if(a[j] && gril[col+i][row+j+1])k=0;return(k);}/* 测试当前方块是否可以变形*/int upok(){int i,j,k=1,a[4][4];for(i=0;i<4;i++)for(i=0;i<16;i++)a[i/4][i%4]=boxstr[boxgs][boxfx+1][i]; for(i=3;i>=0;i--)for(j=3;j>=0;j--)if(a[j] && gril[col+i][row+j])k=0;return(k);}/*当前方块落下之后,给屏幕坐标作标记*/void setgril(){int i,j,a[4][4];funbox(0,0,minboxcolor,0);for(i=0;i<16;i++)a[i/4][i%4]=boxstr[boxgs][boxfx][i];for(i=0;i<4;i++)for(j=0;j<4;j++)if(a[j])gril[col+i][row+j]=1;col=1;row=7;}/*游戏结束*/void gameover(){int i,j;for(i=20;i>0;i--)for(j=1;j<15;j++)minbox(j*MINBOXSIZE,i*MINBOXSIZE,2,0);txt(103,203,"Game Over",3,10);}/*按键的设置*/void call_key(int keyx){switch(keyx){case VK_DOWN: { /*下方向键,横坐标加一。
C语言实现俄罗斯方块
![C语言实现俄罗斯方块](https://img.taocdn.com/s3/m/ca6d9f5069dc5022abea0072.png)
电脑自己玩
• 这一部分的算法已编出,但还没找到最优 算法,尚未嵌入程序,可单独演示。
• 游戏中,按回车键暂停,再敲回车开始, 也可按ESC直接退出。
• 记分板开始前为0分,每消1行分数增1,同 时2行得3分,同时3行得7分,同时4行得13 分。
• 当方块出上界,游戏结束,根据提示,按 回车键重新游戏,ESC退出游戏。
• 每次退出前都询问。
• 演示
• 另外还有,自定义操作键,双人游戏,退出 保存等功能,接口都已做好,都有相应的代 码,由于具体操作时存在问题,暂未加入。
总体设计看演示。
二。游戏流程
• 游戏开始前,系统自动初始化图形模式, 装载界面,接着是用户设置速度和难度, 默认情况为速度难度都为0等级。TAB键移 动光标,上下键调整数值,总共有0-9个 速度和难度等级。回车键确认,开始游戏, ESC键直接退出游戏。
• 游戏开始后,有计时器计时,默认情况是 UP键变形,LEFT,RIGHT控制方向。 DOWN加速。
C语言实现俄罗斯方块
演示文稿
ห้องสมุดไป่ตู้
一.界面设计
• Tc2.0中有两种显示模式,一种是字符模式, 另一种是图形模式。
• 本软件在图形模式下运行,图形模式时,整 个全屏是640X480象素。
• 以STEP(16)为步长的话,为40X30的网格。 • 设游戏板为WIDE(10) X HIGH(20)个网格。 • 加上记分板,下一个方块的显示区及设置区。
俄罗斯方块-C语言
![俄罗斯方块-C语言](https://img.taocdn.com/s3/m/5782f07a0029bd64793e2c2d.png)
俄罗斯方块游戏在本章内容中,将介绍使用C语言开发一个简单的俄罗斯方块游戏的方法,并详细介绍其具体的实现流程。
1.1 第一个项目1.1.1 作业2004年7月1日,晴,我的作业在离校前的10分钟,我们最敬仰的程序老师TC给我们布置了一个暑期作业:题目很简单——用C语言实现俄罗斯方块游戏(提示用graphics.h实现),并提醒务必做好前期的分析工作。
1.1.2 准备2004年7月3日,微风阵阵老师的建议:在做项目前一定要好好地构思和规划项目,根据需求规划开发流程。
于是,我在电脑上画了一个简单的项目开发流程图,如图1-1所示。
图1-1 开发流程图❑功能分析:分析整个系统所需要的功能;❑模块结构规划:规划系统中所需要的功能模块;❑总体设计:分析系统处理流程,探索系统核心模块的运作;❑数据结构:设计系统中需要的数据结构;❑规划函数:预先规划系统中需要的功能函数;❑具体编码:编写系统的具体实现代码。
1.2 功能分析2004年7月4日,阳光明媚其基本结构如图1-2所示。
预览界面底部图1-2 俄罗斯方块游戏的基本结构这样,我总结出了俄罗斯方块游戏的基本功能模块,并做了一个简单的项目规划书,整个规划书分为两个部分:❑系统需求分析;❑结构规划。
1.2.1 系统需求分析1) 游戏方块的预览功能当游戏运行后并在底部出现一个游戏方块时,必须在预览界面中出现下一个方块,这样便于玩家提前进行控制处理。
因为在该游戏中共有19种方块,所以在方块预览区内要显示随机生成的游戏方块。
2) 游戏方块的控制功能游戏玩家可以对出现的方块进行移动处理,分别实现左移、右移、快速下移、自由下落和行满自动消除功能的效果。
3) 更新游戏显示当在游戏中移动方块时,需要先消除先前的游戏方块,然后在新坐标位置重新绘制新方块。
4) 游戏速度设置和分数更新通过游戏分数能够实现对行数的划分,例如,可以设置消除完整的一行为10分。
当达到一定数量后,需要给游戏者进行等级上的升级。
C语言源码实现俄罗斯方块
![C语言源码实现俄罗斯方块](https://img.taocdn.com/s3/m/e6f5f4ebfbb069dc5022aaea998fcc22bcd143fd.png)
C语⾔源码实现俄罗斯⽅块介绍俄罗斯⽅块(Tetris,俄⽂:Тетрис)是⼀款电视游戏机和掌上游戏机游戏,它由俄罗斯⼈阿列克谢·帕基特诺夫发明,故得此名。
俄罗斯⽅块的基本规则是移动、旋转和摆放游戏⾃动输出的各种⽅块,使之排列成完整的⼀⾏或多⾏并且消除得分。
由于上⼿简单、⽼少皆宜,从⽽家喻户晓,风靡世界。
源码#include <stdio.h>#include <string.h>#include <stdlib.h>#include <time.h>#include <conio.h>#include <windows.h>#ifdef _MSC_VER // M$的编译器要给予特殊照顾#if _MSC_VER <= 1200 // VC6及以下版本#error 你是不是还在⽤VC6?!#else // VC6以上版本#if _MSC_VER >= 1600 // 据说VC10及以上版本有stdint.h了#include <stdint.h>#else // VC10以下版本,⾃⼰定义int8_t和uint16_ttypedef signed char int8_t;typedef unsigned short uint16_t;#endif#ifndef __cplusplus // 据说VC都没有stdbool.h,不⽤C++编译,⾃⼰定义booltypedef int bool;#define true 1#define false 0#endif#endif#else // 其他的编译器都好说#include <stdint.h>#ifndef __cplusplus // 不⽤C++编译,需要stdbool.h⾥的bool#include <stdbool.h>#endif#endif// =============================================================================// 7种⽅块的4旋转状态(4位为⼀⾏)static const uint16_t gs_uTetrisTable[7][4] ={{ 0x00F0U, 0x2222U, 0x00F0U, 0x2222U }, // I型{ 0x0072U, 0x0262U, 0x0270U, 0x0232U }, // T型{ 0x0223U, 0x0074U, 0x0622U, 0x0170U }, // L型{ 0x0226U, 0x0470U, 0x0322U, 0x0071U }, // J型{ 0x0063U, 0x0264U, 0x0063U, 0x0264U }, // Z型{ 0x006CU, 0x0462U, 0x006CU, 0x0462U }, // S型{ 0x0660U, 0x0660U, 0x0660U, 0x0660U } // O型};// =============================================================================// 初始状态的游戏池// 每个元素表⽰游戏池的⼀⾏,下标⼤的是游戏池底部// 两端各置2个1,底部2全置为1,便于进⾏碰撞检测// 这样⼀来游戏池的宽度为12列// 如果想要传统的10列,只需多填两个1即可(0xE007),当然显⽰相关部分也要随之改动// 当某个元素为0xFFFFU时,说明该⾏已被填满// 顶部4⾏⽤于给⽅块,不显⽰出来// 再除去底部2⾏,显⽰出来的游戏池⾼度为22⾏static const uint16_t gs_uInitialTetrisPool[28] ={0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U,0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U,0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U,0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xFFFFU, 0xFFFFU};#define COL_BEGIN 2#define COL_END 14// ============================================================================= typedef struct TetrisManager // 这个结构体存储游戏相关数据{uint16_t pool[28]; // 游戏池int8_t x; // 当前⽅块x坐标,此处坐标为⽅块左上⾓坐标int8_t y; // 当前⽅块y坐标int8_t type[3]; // 当前、下⼀个和下下⼀个⽅块类型int8_t orientation[3]; // 当前、下⼀个和下下⼀个⽅块旋转状态unsigned score; // 得分unsigned erasedCount[4]; // 消⾏数unsigned erasedTotal; // 消⾏总数unsigned tetrisCount[7]; // 各⽅块数unsigned tetrisTotal; // ⽅块总数bool dead; // 挂} TetrisManager;// ============================================================================= typedef struct TetrisControl // 这个结构体存储控制相关数据{bool pause; // 暂停bool clockwise; // 旋转⽅向:顺时针为trueint8_t direction; // 移动⽅向:0向左移动 1向右移动// 游戏池内每格的颜⾊// 由于此版本是彩⾊的,仅⽤游戏池数据⽆法存储颜⾊信息// 当然,如果只实现单⾊版的,就没必要⽤这个数组了int8_t color[28][16];} TetrisControl;HANDLE g_hConsoleOutput; // 控制台输出句柄// ============================================================================= // 函数声明// 如果使⽤全局变量⽅式实现,就没必要传参了void initGame(TetrisManager *manager, TetrisControl *control); // 初始化游戏void restartGame(TetrisManager *manager, TetrisControl *control); // 重新开始游戏void giveTetris(TetrisManager *manager); // 给⼀个⽅块bool checkCollision(const TetrisManager *manager); // 碰撞检测void insertTetris(TetrisManager *manager); // 插⼊⽅块void removeTetris(TetrisManager *manager); // 移除⽅块void horzMoveTetris(TetrisManager *manager, TetrisControl *control); // ⽔平移动⽅块void moveDownTetris(TetrisManager *manager, TetrisControl *control); // 向下移动⽅块void rotateTetris(TetrisManager *manager, TetrisControl *control); // 旋转⽅块void dropDownTetris(TetrisManager *manager, TetrisControl *control); // ⽅块直接落地bool checkErasing(TetrisManager *manager, TetrisControl *control); // 消⾏检测void keydownControl(TetrisManager *manager, TetrisControl *control, int key); // 键按下void setPoolColor(const TetrisManager *manager, TetrisControl *control); // 设置颜⾊void gotoxyWithFullwidth(short x, short y); // 以全⾓定位void printPoolBorder(); // 显⽰游戏池边界void printTetrisPool(const TetrisManager *manager, const TetrisControl *control); // 显⽰游戏池void printCurrentTetris(const TetrisManager *manager, const TetrisControl *control); // 显⽰当前⽅块void printNextTetris(const TetrisManager *manager); // 显⽰下⼀个和下下⼀个⽅块void printScore(const TetrisManager *manager); // 显⽰得分信息void runGame(TetrisManager *manager, TetrisControl *control); // 运⾏游戏void printPrompting(); // 显⽰提⽰信息bool ifPlayAgain(); // 再来⼀次// ============================================================================= // 主函数int main(){TetrisManager tetrisManager;TetrisControl tetrisControl;initGame(&tetrisManager, &tetrisControl); // 初始化游戏do{printPrompting(); // 显⽰提⽰信息printPoolBorder(); // 显⽰游戏池边界runGame(&tetrisManager, &tetrisControl); // 运⾏游戏if (ifPlayAgain()) // 再来⼀次{SetConsoleTextAttribute(g_hConsoleOutput, 0x7);system("cls"); // 清屏restartGame(&tetrisManager, &tetrisControl); // 重新开始游戏else{break;}} while (1);gotoxyWithFullwidth(0, 0);CloseHandle(g_hConsoleOutput);return 0;}// ============================================================================= // 初始化游戏void initGame(TetrisManager *manager, TetrisControl *control){CONSOLE_CURSOR_INFO cursorInfo = { 1, FALSE }; // 光标信息g_hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); // 获取控制台输出句柄SetConsoleCursorInfo(g_hConsoleOutput, &cursorInfo); // 设置光标隐藏SetConsoleTitleA("俄罗斯⽅块控制台版——By: NEWPLAN");restartGame(manager, control);}// ============================================================================= // 重新开始游戏void restartGame(TetrisManager *manager, TetrisControl *control){memset(manager, 0, sizeof(TetrisManager)); // 全部置0// 初始化游戏池memcpy(manager->pool, gs_uInitialTetrisPool, sizeof(uint16_t [28]));srand((unsigned)time(NULL)); // 设置随机种⼦manager->type[1] = rand() % 7; // 下⼀个manager->orientation[1] = rand() & 3;manager->type[2] = rand() % 7; // 下下⼀个manager->orientation[2] = rand() & 3;memset(control, 0, sizeof(TetrisControl)); // 全部置0giveTetris(manager); // 给下⼀个⽅块setPoolColor(manager, control); // 设置颜⾊}// ============================================================================= // 给⼀个⽅块void giveTetris(TetrisManager *manager){uint16_t tetris;manager->type[0] = manager->type[1]; // 下⼀个⽅块置为当前manager->orientation[0] = manager->orientation[1];manager->type[1] = manager->type[2];// 下下⼀个置⽅块为下⼀个manager->orientation[1] = manager->orientation[2];manager->type[2] = rand() % 7;// 随机⽣成下下⼀个⽅块manager->orientation[2] = rand() & 3;tetris = gs_uTetrisTable[manager->type[0]][manager->orientation[0]]; // 当前⽅块// 设置当前⽅块y坐标,保证刚给出时只显⽰⽅块最下⾯⼀⾏// 这种实现使得玩家可以以很快的速度将⽅块落在不显⽰出来的顶部4⾏内if (tetris & 0xF000){manager->y = 0;}else{manager->y = (tetris & 0xFF00) ? 1 : 2;}manager->x = 6; // 设置当前⽅块x坐标if (checkCollision(manager)) // 检测到碰撞manager->dead = true; // 标记游戏结束}else // 未检测到碰撞{insertTetris(manager); // 将当前⽅块加⼊游戏池}++manager->tetrisTotal; // ⽅块总数++manager->tetrisCount[manager->type[0]]; // 相应⽅块数printNextTetris(manager); // 显⽰下⼀个⽅块printScore(manager); // 显⽰得分信息}// ============================================================================= // 碰撞检测bool checkCollision(const TetrisManager *manager){// 当前⽅块uint16_t tetris = gs_uTetrisTable[manager->type[0]][manager->orientation[0]];uint16_t dest = 0;// 获取当前⽅块在游戏池中的区域:// 游戏池坐标x y处⼩⽅格信息,按低到⾼存放在16位⽆符号数中dest |= (((manager->pool[manager->y + 0] >> manager->x) << 0x0) & 0x000F);dest |= (((manager->pool[manager->y + 1] >> manager->x) << 0x4) & 0x00F0);dest |= (((manager->pool[manager->y + 2] >> manager->x) << 0x8) & 0x0F00);dest |= (((manager->pool[manager->y + 3] >> manager->x) << 0xC) & 0xF000);// 若当前⽅块与⽬标区域存在重叠(碰撞),则位与的结果不为0return ((dest & tetris) != 0);}// ============================================================================= // 插⼊⽅块void insertTetris(TetrisManager *manager){// 当前⽅块uint16_t tetris = gs_uTetrisTable[manager->type[0]][manager->orientation[0]];// 当前⽅块每4位取出,位或到游戏池相应位置,即完成插⼊⽅块manager->pool[manager->y + 0] |= (((tetris >> 0x0) & 0x000F) << manager->x);manager->pool[manager->y + 1] |= (((tetris >> 0x4) & 0x000F) << manager->x);manager->pool[manager->y + 2] |= (((tetris >> 0x8) & 0x000F) << manager->x);manager->pool[manager->y + 3] |= (((tetris >> 0xC) & 0x000F) << manager->x);}// ============================================================================= // 移除⽅块void removeTetris(TetrisManager *manager){// 当前⽅块uint16_t tetris = gs_uTetrisTable[manager->type[0]][manager->orientation[0]];// 当前⽅块每4位取出,按位取反后位与到游戏池相应位置,即完成移除⽅块manager->pool[manager->y + 0] &= ~(((tetris >> 0x0) & 0x000F) << manager->x);manager->pool[manager->y + 1] &= ~(((tetris >> 0x4) & 0x000F) << manager->x);manager->pool[manager->y + 2] &= ~(((tetris >> 0x8) & 0x000F) << manager->x);manager->pool[manager->y + 3] &= ~(((tetris >> 0xC) & 0x000F) << manager->x);}// ============================================================================= // 设置颜⾊void setPoolColor(const TetrisManager *manager, TetrisControl *control){// 由于显⽰游戏池时,先要在游戏池⾥判断某⼀⽅格有⽅块才显⽰相应⽅格的颜⾊// 这⾥只作设置即可,没必要清除// 当移动⽅块或给⼀个⽅块时调⽤int8_t i, x, y;// 当前⽅块uint16_t tetris = gs_uTetrisTable[manager->type[0]][manager->orientation[0]];for (i = 0; i < 16; ++i)y = (i >> 2) + manager->y; // 待设置的列if (y > ROW_END) // 超过底部限制{break;}x = (i & 3) + manager->x; // 待设置的⾏if ((tetris >> i) & 1) // 检测的到⼩⽅格属于当前⽅块区域{control->color[y][x] = (manager->type[0] | 8); // 设置颜⾊}}}// ============================================================================= // 旋转⽅块void rotateTetris(TetrisManager *manager, TetrisControl *control){int8_t ori = manager->orientation[0]; // 记录原旋转状态removeTetris(manager); // 移⾛当前⽅块// 顺/逆时针旋转manager->orientation[0] = (control->clockwise) ? ((ori + 1) & 3) : ((ori + 3) & 3);if (checkCollision(manager)) // 检测到碰撞{manager->orientation[0] = ori; // 恢复为原旋转状态insertTetris(manager); // 放⼊当前⽅块。
c++俄罗斯方块算法描述_解释说明
![c++俄罗斯方块算法描述_解释说明](https://img.taocdn.com/s3/m/7860d7e9dc3383c4bb4cf7ec4afe04a1b071b01b.png)
c++俄罗斯方块算法描述解释说明1. 引言1.1 概述俄罗斯方块是一款经典的益智游戏,它以其简单却富有挑战性的玩法而受到了广大玩家的喜爱。
这款游戏的核心在于使用各种形状的方块来填满一个平面,并尽可能消除已填满的行。
本文将详细描述和解释俄罗斯方块中所涉及到的算法,并给出实现示例和优化建议。
1.2 文章结构文章主要分为五个部分:引言、俄罗斯方块算法描述、算法解释说明、实现示例和优化建议、结论与展望。
在引言部分,我们将对整篇文章进行概述,并介绍文章的结构框架。
接下来,我们将详细描述俄罗斯方块中所用到的算法,包括方块生成算法和方块下落以及碰撞检测算法。
然后,我们将重点解释游戏状态管理算法、消行判断和消行算法以及分数计算和难度调整算法。
在实现示例和优化建议部分,我们将给出一个具体的代码示例,并提供一些关于如何优化该代码的建议。
最后,在结论与展望部分,我们将总结俄罗斯方块算法描述及其实现效果,并展望未来俄罗斯方块的改进方向和研究内容。
1.3 目的本文的目的是通过详细描述和解释俄罗斯方块中所涉及到的算法,让读者对该游戏中各个环节的实现有更深入的理解。
同时,我们还希望通过给出一个具体的实现示例和优化建议,能够帮助读者更好地掌握算法在实际编程中的应用。
最后,我们也将对俄罗斯方块算法描述进行总结,并提出一些关于未来改进和研究方向的展望。
2. 俄罗斯方块算法描述:2.1 游戏规则介绍:在俄罗斯方块游戏中,玩家需要通过操作和控制方块的移动、旋转来填满游戏区域的水平行,当一行被完全填满时,该行将被消除并得分。
游戏区域由一个固定大小的矩形网格组成,起初是空的。
方块以7种不同的形态出现,并从游戏区域顶部下落。
玩家可以通过左右移动、快速下落和旋转来操作当前下落方块。
当方块无法再下落时,则会生成新的方块并开始新一轮操作。
2.2 方块生成算法:俄罗斯方块中的七种基本形态(I、J、L、O、S、T和Z)以及它们可能出现在哪个位置都是预先定义好的。
俄罗斯方块c语言程序带注释
![俄罗斯方块c语言程序带注释](https://img.taocdn.com/s3/m/845d5784e53a580216fcfe43.png)
1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,}; /*方块模板*/int shape,dir,next_shape,next_dir;struct position{int x;int y;} now_position; /*纪录现在方块的位置*/int speed_level=1;int fall_to_land,be_lined; /*判断方块是否着地的*/ /*----------------------------------------*/void clscreen();void setxy(int x,int y);void display_back();void display_interface();void display_fk(int x,int y,int shape,int dir);void init();//int getkey();/*取键盘的扫描码*/void getinput();void m_sound(int freq,int time);void eras_fk(int x,int y,int shape,int dir);/*擦除方块*/void fk_down(bool quickly = false);bool is_illegal(int x,int y,int changed_dir);/*判断方块移动后坐标是否非法,非法1,合法0*/int get_random(int n); /*生成一个0----n-1的随机数*/void check_line(); /*检查是否有行可以消去,如果有就消去*/void game_over();/*----------------------------------*/int main(){int i;init();while (true){display_back();now_position.x=10;now_position.y=2;/*复原初始坐标*/be_lined=0; /*一个方块刚出现时没有成行*/shape=next_shape;dir=next_dir;next_shape=get_random(7);next_dir=get_random(4);eras_fk(55,5,shape,dir);/*擦去前一个方块*/display_fk(55,5,next_shape,next_dir);/*显示下一个方块*/display_fk(now_position.x,now_position.y,shape,dir);/*显示目前方块*/fall_to_land=0;while (!fall_to_land){for (i=15000-1500*speed_level;i>0;i--){getinput();}/*接受键盘输入*/fk_down(); /*方块自动下落*/}//m_sound(350,500); /*块落下的声音*/ check_line(); /*检查有没有可消去的行*/if (be_lined)m_sound(250,1000);elsem_sound(350,500);}return0;}/*------------------------------------*/void init(){int i,j;for (i=0;i<20;i++)for (j=0;j<10;j++)background[i][j]=0;/*背景数组赋初值0*/next_shape=(get_random(7)+5)/7;next_dir=(get_random(4)+2)/4;/*预先产生一个方块*/display_interface();/*画界面*/}void display_interface(){clscreen();setxy(40,5);printf("The Next: ");setxy(1,1);}/*-----------------------------------------*/void display_back()/*显示背景*/{int i,j;for (i=0;i<20;i++){for (j=0;j<10;j++){setxy(2*(j+1),i+2); /*数组下标到屏幕坐标的变换*/if (!background[i][j])/*背景数组中值为0*/printf(" ");elseprintf("[]");}}}/*---------------------------------------*/void display_fk(int x,int y,int shape,int dir)/*显示方块*/{int i,j;for (i=0;i<4;i++){for (j=0;j<4;j++){if (fang_kuai[shape][dir][i][j]){setxy((x+2*j),(y+i));/*结合现在方块的位置*/printf("[]");}}}}/*-----------------------------------*/void getinput(){if(GetAsyncKeyState(VK_LEFT)){if (!is_illegal(now_position.x-2,now_position.y,dir)){eras_fk(now_position.x,now_position.y,shape,dir);now_position.x=now_position.x-2;display_fk(now_position.x,now_position.y,shape,dir);Sleep(1000);}elsem_sound(440,500);/*如果没有遇阻,方块位置左移一格*/}else if(GetAsyncKeyState(VK_RIGHT)){if (!is_illegal(now_position.x+2,now_position.y,dir)){eras_fk(now_position.x,now_position.y,shape,dir);now_position.x=now_position.x+2;display_fk(now_position.x,now_position.y,shape,dir);Sleep(1000);}elsem_sound(440,500);/*如果没有遇阻,方块位置右移一格*/}else if(GetAsyncKeyState(VK_UP)){if (!is_illegal(now_position.x,now_position.y,(dir+1)%4)){eras_fk(now_position.x,now_position.y,shape,dir);dir=(dir+1)%4;display_fk(now_position.x,now_position.y,shape,dir);Sleep(1000);}}else if(GetAsyncKeyState(VK_DOWN)){fk_down(true);}else if(GetAsyncKeyState(VK_SPACE)){game_over();}}/*------------------------------------*/void m_sound(int freq,int time){Beep(freq,time);}/*--------------------------------*/void eras_fk(int x,int y,int shape,int dir)/*擦除方块*/{int i,j;for (i=0;i<4;i++){for (j=0;j<4;j++){if (fang_kuai[shape][dir][i][j]){setxy((x+2*j),(y+i));/*结合现在方块的位置*/printf(" ");}}}}/*----------------------------------------------------*/ void fk_down(bool quickly) /*方块下落*/{int i,j,x,y;if (!is_illegal(now_position.x,now_position.y+1,dir))/*下落没有阻碍*/{eras_fk(now_position.x,now_position.y,shape,dir);now_position.y=now_position.y+1;display_fk(now_position.x,now_position.y,shape,dir);if(quickly){Sleep(10);}else{Sleep(1000);}}else/*不可再下落了*/{/*方块并入背景*/x=now_position.x;y=now_position.y; /*x,y表示方便*/for (i=0;i<4;i++){for (j=0;j<4;j++){if (fang_kuai[shape][dir][i][j]==1) background[(y-2+i)][(x/2-1+j)]=1;}}fall_to_land=1; /*告诉主程序方块着地*/}}/*-----------------------------------------------------*/ bool is_illegal(int x,int y,int changed_dir){int i,j;bool illegal=false;/*先判断有没有出界,如果有x,y在界外并且此x,y处方块数组为1,就返回1*/for (i=0;i<4;i++)for (j=0;j<4;j++)if (fang_kuai[shape][changed_dir][i][j]==1&&((x+j*2)>21 || (x+j*2)<2 || (y+i)>21 || (y+i)<2))illegal=true;/*再判断是否有原方块阻碍*/if (!illegal){for (i=0;i<4;i++)for (j=0;j<4;j++)if (fang_kuai[shape][changed_dir][i][j]==1&&background[(y-2+i)][(x/2-1+j)]==1)illegal=true;/*有阻碍返回一*/}return illegal;}/*-----------------------------------------------------*/int get_random(int n){int x;Sleep(500);/*randomize();x=random(n);*/srand( (unsigned)time(NULL));x=rand()%n;return(x);}/*--------------------------------------------------------------*/void check_line() /*待修改*/{/*检查背景数组*/int i,j,k;int line,n;for (i=19;i>=0;i--){k=1; /*开始默认成行*/for (j=9;j>=0;j-- ){if (background[i][j]==0) /*不成行的条件*/k=0;}if (k==1) /*如果成行*/{be_lined=1; /*成行标志*/for (line=i;line>0;line--)for (n=9;n>=0;n--)background[line][n]=background[line-1][n];/*逐次下移一行*/i=i+1; /*把下一次待检的行重新设定*/}}}/*--------------------------------------------------------------*/void game_over(){clscreen();setxy(35,1);printf("GAME OVER");exit(0);}void clscreen(){system("cls");}void setxy(int x,int y){HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);COORD place;place.X = x;place.Y = y;SetConsoleCursorPosition(hConsole, place);}/* Colors defined for SetColor(int) */enum {BLACK = 0,DARK_BLUE = 1,DARK_GREEN = 2,TEAL = 3,DARK_RED = 4,DARK_PURPLE = 5,GOLD = 6,GREY = 7,DARK_WHITE = 8,BLUE = 9,GREEN = 10,CYAN = 11,RED = 12,PURPLE = 13,YELLOW = 14,WHITE = 15};void SetColor(const int foreground, const int background) {int Color = foreground + (background * 16);HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);}你把这段拿回去看哈吧,这是一个俄罗斯方块的程序,就是在控制台运行的,就是用你所说的纯数字和字符所运行,你现在只能在dos 下显示那些纯数字的东西,是因为你很多技术性的手法,你还不会,但你学习到一定程度后,你就会有所领悟,也不要太心急,当你练好内功后,修炼招数,应该会很快的!希望对你有帮助。
俄罗斯方块最详解
![俄罗斯方块最详解](https://img.taocdn.com/s3/m/1567fc66f5335a8102d2204c.png)
俄罗斯方块最详解(C语言实现)俄罗斯方块最详解做每一件事前,都会有一个粗略的构想。
编程更应该这样,现在先说一些大的、粗略的东西。
******************************************************************************* **************************************************************************************** *********目录:●屏幕的划分●图形显示●三种坐标。
绝对坐标、相对坐标、左上角坐标●方块的构造●动画效果●键盘控制●判断方块碰撞●消行●变形●关于菜单的制作●附录(完整的源程序)******************************************************************************* **************************************************************************************** *********1、屏幕的划分将整个屏幕划分成四部分:a、一个没盖的杯子;b、一个不断下落4*4数组的盒子;c、一个给预览下一个方块4*4数组的盒子;d、提示信息。
由于提示信息比较简单,这里只讨论前三样。
没盖的杯子:即平时说玩这款游戏时,下落方块不可超出的那个边界,下落的方块从这个“杯口”的上方往下下落,方块只在“杯子”里移动、变形、停止。
游戏空间指的是整个游戏主要的界面(呵呵,其实就是所说的“杯子”)。
实际上是一个宽10格子、高20格子的游戏板。
用一个全局数组GameSpace[22][12]表示。
表示的时候:GameSpace[x][y]为1时表示游戏板上(x,y)这个位置上已经有方块占着了,GameSpace[x][y]为0表示游戏板上这位置还空着。
C语言实现俄罗斯方块小游戏
![C语言实现俄罗斯方块小游戏](https://img.taocdn.com/s3/m/890ef40a6ad97f192279168884868762caaebb48.png)
C语⾔实现俄罗斯⽅块⼩游戏C语⾔实现俄罗斯⽅块⼩游戏的制作代码,具体内容如下#include <stdio.h>#include <stdlib.h>#include <unistd.h>#define TTY_PATH "/dev/tty"#define STTY_ON "stty raw -echo -F"#define STTY_OFF "stty -raw echo -F"int map[21][14];char direct;int node[7][4][16]={{{0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0},//长⽅形{0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0},{0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0},{0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0}},{{1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},//正⽅形{1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},{1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},{1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0}},{{0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0},//3边加⼀中点{0,1,0,0,0,1,1,0,0,1,0,0,0,0,0,0},{0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0},{0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0}},{{0,1,1,0,0,1,0,0,0,1,0,0,0,0,0,0},//右锄头型{0,0,0,0,1,1,1,0,0,0,1,0,0,0,0,0},{0,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0},{1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0}},{{1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0},//左锄头型{0,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0},{0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,0},{0,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0}},{{0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0},//右曲折型{0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0},{0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0},{0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0}},{{0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0},//左曲折型{1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0},{0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0},{1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0}}};typedef struct block{int x;int y;int blockType;int blockDirect;}Block;Block bl;void init_map()//初始化边框{int i,j;for(i=0; i<21; i++)for(j=0; j<14; j++){if(j==0 || j==13)map[i][j] = 200;else if(i==20)map[i][j] = 201;elsemap[i][j] = 0;}}void new_block()//⽣成随机的俄罗斯⽅块{int blockType = rand()%7;int blockDirect = rand()%4;int x = 1;int y = 5;bl.x = x;bl.y = y;bl.blockType = blockType;bl.blockDirect = blockDirect;}void input()//将移动后的俄罗斯⽅块,导⼊地图中作标记{int i, j;for(i=0; i<4; i++)for(j=0; j<4; j++)if(node[bl.blockType][bl.blockDirect][i*4+j]==1){map[bl.x+i][bl.y+j] = 1;}}void output()//移动时,将之前俄罗斯⽅块在地图信息清空。
俄罗斯方块c语言报告
![俄罗斯方块c语言报告](https://img.taocdn.com/s3/m/f8571c380166f5335a8102d276a20029bd6463f6.png)
俄罗斯方块c语言报告一、问题描述俄罗斯方块是一款电视游戏机和掌上游戏机游戏,它山俄罗斯人阿列克谢·帕基特诺大发明,故得此名。
俄罗斯方块的基木规则是移动、旋转和摆放游戏自动输出的各种方块,使之排列成完整的一行或多行并且消除得分。
在本次报告设计中,要求支持键盘操作和若干种不同类型方块的旋转变换,并且界面上显示下一个方块的提示以及当前的玩家的得分,随着游戏的进行,等级越高,游戏难度越大,即方块的下落速度越快,相应的等级,等级越高,为玩家提供了不同的选择。
二、功能分析I、俄罗斯方块游戏需要解决的问题包括:(1)随机产生方块并自动下移(2)用Esc键退出游戏(3)用↑键变体(4)用←键和→键左右移动方块(5)用空格键使游戏暂停(6)能正确判断满行并消行、计分、定级别(7)设定游戏为不同级别,级别越高难度越大II、俄罗斯方块游戏需要设计的功能函数包括:(1)、声明俄罗斯方块的结构体(2)函数原型声明(3)制作游戏窗口(4)制作俄罗斯方块(5)判断是否可动(6)随机产生俄罗斯方块类型的序号(7)打印俄罗斯方块(8)清除俄罗斯方块的痕迹(9)判断是否满行并删除满行的俄罗斯方块三、程序设计(1)游戏方块预览功能。
在游戏过程中,游戏界面右侧会有预览区。
由于在此游戏中存在多种不同的游戏方块,所以在游戏方块预览区域中显示随机生成的游戏方块有利于游戏玩家控制游戏的策略。
(2)游戏方块控制功能。
通过各种条件的判断,实现对游戏方块的左移、右移、自由下落、旋转功能,以及行满消除行的功能。
(3)游戏数据显示功能。
在游戏玩家进行游戏过程中,需要按照一定的游戏规则给玩家计算游戏分数。
例如,消除一行加100分,游戏分数达到一定数量之后,需要给游戏者进行等级的上升,每上升一个等级,游戏方块的下落速度将加快,游戏的难度将增加。
以上游戏数据均会在游戏界面右侧显示以提示玩家。
(4)游戏信息提示功能。
玩家进入游戏后,将有对本游戏如何操作的友情提示。
C语言的俄罗斯方块
![C语言的俄罗斯方块](https://img.taocdn.com/s3/m/ec63ac0ee87101f69e31952a.png)
大概在最近两天之内编码完成,但此前一天开始构思。
第一天晚上主要完成了方块旋转算法,第二天也就是今天加了消方块的处理算法。
但是可能还有一些考虑不周的地方,比如,没有采用定时中断,而是图方便采用了和cpu频率有关的delay()函数来模拟时间间隔,这是需要改进的地方。
其中的主要逻辑有:(1)由于c的随机性函数不好,所以每次游戏开始根据bios时间设置种子。
(2)得分越高,方块下降速度越快(每200分为单位)。
(3)每下落一个方块加1分,每消除一行加10分,两行加30分,三行加70分,四行加150分。
初试分数为100分。
游戏控制:up-旋转;空格-下落到底;左右下方向键-控制方向。
P-开始或暂停游戏。
ESC-退出。
特点:(1)由于tc不支持中文,所以基本都是英文注释。
(2)函数命名尽可能规范的表达其内部处理目的和过程。
(3)代码加上注释仅有577行。
(我下载过的两个俄罗斯方块代码一个在1087行,一个在993行,我的比它们代码少)。
(4)除了消除空格时算法比较复杂,其他算法都比较简单易读。
(5)绘图效率和局部代码效率扔有待提高。
(6)FrameTime参数可能依据不同硬件环境进行具体设置,InitGame需要正确的TC路径。
俄罗斯方块源于大约9年前上大一时的一个梦,我们在学习c语言时,我的同寝室友邀请我合作一起完成俄罗斯方块(课外作业性质),但是当时限于我们的水平比较菜和学习状态比较懒散,我们没有完成。
大一的时候我在机房里无意发现别人留下的俄罗斯方块程序,运行,老师发现后激动的问我是我写的吗,我惭愧的摇摇头。
那时看到别人做c的大程序深感羡慕(自己只是写几十行的程序)。
数年后我仍然看到有不同样式的实现,但是我一直没有实现它,知道今天忽然有这个想法去做,算是弥补多年前的遗憾和心愿吧。
----------------------------【以下是我的代码文件:】---------------------------------/********************************//* Desc: 俄罗斯方块游戏 *//* By: hoodlum1980 *//* Email: jinfd@ *//* Date: 2008.03.12 22:30 *//********************************/#include <stdio.h>#include <bios.h>#include <dos.h>#include <graphics.h>#include <string.h>#include <stdlib.h>#define true 1#define false 0#define BoardWidth 12#define BoardHeight 23#define _INNER_HELPER /*inner helper method *//*Scan Codes Define*/enum KEYCODES{K_ESC =0x011b,K_UP =0x4800, /* upward arrow */K_LEFT =0x4b00,K_DOWN =0x5000,K_RIGHT =0x4d00,K_SPACE =0x3920,K_P =0x1970};/* the data structure of the block */typedef struct tagBlock{char c[4][4]; /* cell fill info array, 0-empty, 1-filled */ int x; /* block position cx [ 0,BoardWidht -1] */ int y; /* block position cy [-4,BoardHeight-1] */ char color; /* block color */char size; /* block max size in width or height */char name; /* block name (the block's shape) */} Block;/* game's global info */int FrameTime= 1300;int CellSize= 18;int BoardLeft= 30;int BoardTop= 30;/* next block grid */int NBBoardLeft= 300;int NBBoardTop= 30;int NBCellSize= 10;/* score board position */int ScoreBoardLeft= 300;int ScoreBoardTop=100;int ScoreBoardWidth=200;int ScoreBoardHeight=35;int ScoreColor=LIGHTCYAN;/* infor text postion */int InfoLeft=300;int InfoTop=200;int InfoColor=YELLOW;int BorderColor=DARKGRAY;int BkGndColor=BLACK;int GameRunning=true;int TopLine=BoardHeight-1; /* top empty line */int TotalScore=100;char info_score[20];char info_help[255];char info_common[255];/* our board, Board[x][y][0]-isFilled, Board[x][y][1]-fillColor */ unsigned char Board[BoardWidth][BoardHeight][2];char BufferCells[4][4]; /* used to judge if can rotate block */ Block curBlock; /* current moving block */Block nextBlock; /* next Block to appear *//* function list */int GetKeyCode();int CanMove(int dx,int dy);int CanRotate();int RotateBlock(Block *block);int MoveBlock(Block *block,int dx,int dy);void DrawBlock(Block *block,int,int,int);void EraseBlock(Block *block,int,int,int);void DisplayScore();void DisplayInfo(char* text);void GenerateBlock(Block *block);void NextBlock();void InitGame();int PauseGame();void QuitGame();/*Get Key Code */int GetKeyCode(){int key=0;if(bioskey(1)){key=bioskey(0);}return key;}/* display text! */void DisplayInfo(char *text){setcolor(BkGndColor);outtextxy(InfoLeft,InfoTop,info_common);strcpy(info_common,text);setcolor(InfoColor);outtextxy(InfoLeft,InfoTop,info_common);}/* create a new block by key number,* the block anchor to the top-left corner of 4*4 cells*/void _INNER_HELPER GenerateBlock(Block *block){int key=(random(13)*random(17)+random(1000)+random(3000))%7; block->size=3;/* because most blocks' size=3 */memset(block->c,0,16);switch(key){case 0:block->name='T';block->color=RED;block->c[1][0]=1;block->c[1][1]=1, block->c[2][1]=1;block->c[1][2]=1;break;case 1:block->name='L';block->color=YELLOW;block->c[1][0]=1;block->c[1][1]=1;block->c[1][2]=1, block->c[2][2]=1; break;case 2:block->name='J';block->color=LIGHTGRAY;block->c[1][0]=1;block->c[1][1]=1;block->c[1][2]=1, block->c[0][2]=1; break;case 3:block->name='z';block->color=CYAN;block->c[0][0]=1, block->c[1][0]=1; block->c[1][1]=1, block->c[2][1]=1; break;case 4:block->name='5';block->color=LIGHTBLUE;block->c[1][0]=1, block->c[2][0]=1; block->c[0][1]=1, block->c[1][1]=1; break;case 5:block->name='o';block->color=BLUE;block->size=2;block->c[0][0]=1, block->c[1][0]=1; block->c[0][1]=1, block->c[1][1]=1; break;case 6:block->name='I';block->color=GREEN;block->size=4;block->c[1][0]=1;block->c[1][1]=1;block->c[1][2]=1;block->c[1][3]=1;break;}}/* get next block! */void NextBlock(){/* copy the nextBlock to curBlock */curBlock.size=nextBlock.size;curBlock.color=nextBlock.color;curBlock.x=(BoardWidth-4)/2;curBlock.y=-curBlock.size;memcpy(curBlock.c,nextBlock.c,16);/* generate nextBlock and show it */EraseBlock(&nextBlock,NBBoardLeft,NBBoardTop,NBCellSize);GenerateBlock(&nextBlock);nextBlock.x=1,nextBlock.y=0;DrawBlock(&nextBlock,NBBoardLeft,NBBoardTop,NBCellSize);}/* rotate the block, update the block struct data */int _INNER_HELPER RotateCells(char c[4][4],char blockSize){char temp,i,j;switch(blockSize){case 3:temp=c[0][0];c[0][0]=c[2][0], c[2][0]=c[2][2], c[2][2]=c[0][2], c[0][2]=temp;temp=c[0][1];c[0][1]=c[1][0], c[1][0]=c[2][1], c[2][1]=c[1][2], c[1][2]=temp;break;case 4: /* only 'I' block arived here! */c[1][0]=1-c[1][0], c[1][2]=1-c[1][2], c[1][3]=1-c[1][3];c[0][1]=1-c[0][1], c[2][1]=1-c[2][1], c[3][1]=1-c[3][1];break;}}/* judge if the block can move toward the direction */int CanMove(int dx,int dy){int i,j,tempX,tempY;for(i=0;i<curBlock.size;i++){for(j=0;j<curBlock.size;j++){if(curBlock.c[i][j]){/* cannot move leftward or rightward */tempX = curBlock.x + i + dx;if(tempX<0 || tempX>(BoardWidth-1)) return false; /* make sure x is valid! *//* cannot move downward */tempY = curBlock.y + j + dy;if(tempY>(BoardHeight-1)) return false; /* y is only checked lower bound, maybe negative!!!! *//* the cell already filled, we must check Y's upper bound before check cell ! */if(tempY>=0 && Board[tempX][tempY][0]) return false;}}}return true;}/* judge if the block can rotate */int CanRotate(){int i,j,tempX,tempY;/* update buffer */memcpy(BufferCells, curBlock.c, 16);RotateCells(BufferCells,curBlock.size);for(i=0;i<curBlock.size;i++){for(j=0;j<curBlock.size;j++){if(BufferCells[i][j]){tempX=curBlock.x+i;tempY=curBlock.y+j;if(tempX<0 || tempX>(BoardWidth-1))return false;if(tempY>(BoardHeight-1))return false;if(tempY>=0 && Board[tempX][tempY][0])return false;}}}return true;}/* draw the block */void _INNER_HELPER DrawBlock(Block *block,int bdLeft,int bdTop,int cellSize) {int i,j;setfillstyle(SOLID_FILL,block->color);for(i=0;i<block->size;i++){for(j=0;j<block->size;j++){if(block->c[i][j] && (block->y+j)>=0){floodfill(bdLeft+cellSize*(i+block->x)+cellSize/2,bdTop+cellSize*(j+block->y)+cellSize/2,BorderColor);}}}}/* Rotate the block, if success, return true */int RotateBlock(Block *block){char temp,i,j;int b_success;if(curBlock.size==2)return;if(( b_success=CanRotate())){EraseBlock(block,BoardLeft,BoardTop,CellSize);memcpy(curBlock.c,BufferCells,16);DrawBlock(block,BoardLeft,BoardTop,CellSize);}return b_success;}/* erase a block, only fill the filled cell with background color */void _INNER_HELPER EraseBlock(Block *block,int bdLeft,int bdTop,int cellSize) {int i,j;setfillstyle(SOLID_FILL,BkGndColor);for(i=0;i<block->size;i++){for(j=0;j<block->size;j++){if(block->c[i][j] && (block->y+j>=0)){floodfill(bdLeft+cellSize*(i+block->x)+cellSize/2,bdTop+cellSize*(j+block->y)+cellSize/2,BorderColor);}}}}/* move by the direction if can, donothing if cannot* return value: true - success, false - cannot move toward this direction*/int MoveBlock(Block *block,int dx,int dy){int b_canmove=CanMove(dx,dy);if(b_canmove){EraseBlock(block,BoardLeft,BoardTop,CellSize);curBlock.x+=dx;curBlock.y+=dy;DrawBlock(block,BoardLeft,BoardTop,CellSize);}return b_canmove;}/* drop the block to the bottom! */int DropBlock(Block *block){EraseBlock(block,BoardLeft,BoardTop,CellSize);while(CanMove(0,1)){curBlock.y++;}DrawBlock(block,BoardLeft,BoardTop,CellSize);return 0;/* return value is assign to the block's alive */}/* init the graphics mode, draw the board grid */void InitGame(){int i,j,gdriver=DETECT,gmode;struct time sysTime;/* draw board cells */memset(Board,0,BoardWidth*BoardHeight*2);memset(nextBlock.c,0,16);strcpy(info_help,"P: Pause Game. --by hoodlum1980");initgraph(&gdriver,&gmode,"c:\\tc\\");setcolor(BorderColor);for(i=0;i<=BoardWidth;i++){line(BoardLeft+i*CellSize, BoardTop, BoardLeft+i*CellSize, BoardTop+ BoardHeight*CellSize);}for(i=0;i<=BoardHeight;i++){line(BoardLeft, BoardTop+i*CellSize, BoardLeft+BoardWidth*CellSize, BoardTop+ i*CellSize);}/* draw board outer border rect */rectangle(BoardLeft-CellSize/4, BoardTop-CellSize/4,BoardLeft+BoardWidth*CellSize+CellSize/4,BoardTop+BoardHeight*CellSize+CellSize/4);/* draw next block grids */for(i=0;i<=4;i++){line(NBBoardLeft+i*NBCellSize, NBBoardTop, NBBoardLeft+i*NBCellSize, NBBoardTop+4*NBCellSize);line(NBBoardLeft, NBBoardTop+i*NBCellSize, NBBoardLeft+4*NBCellSize, NBBoardTop+ i*NBCellSize);}/* draw score rect */rectangle(ScoreBoardLeft,ScoreBoardTop,ScoreBoardLeft+ScoreBoardWidth,ScoreBoardTop+Sco reBoardHeight);DisplayScore();/* set new seed! */gettime(&sysTime);srand(sysTime.ti_hour*3600+sysTime.ti_min*60+sysTime.ti_sec);GenerateBlock(&nextBlock);NextBlock(); /* create first block */setcolor(DARKGRAY);outtextxy(InfoLeft,InfoTop+20,"Up -rotate Space-drop");outtextxy(InfoLeft,InfoTop+35,"Left-left Right-right");outtextxy(InfoLeft,InfoTop+50,"Esc -exit");DisplayInfo(info_help);}/* set the isFilled and fillcolor data to the board */void _INNER_HELPER FillBoardData(){int i,j;for(i=0;i<curBlock.size;i++){for(j=0;j<curBlock.size;j++){if(curBlock.c[i][j] && (curBlock.y+j)>=0){Board[curBlock.x+i][curBlock.y+j][0]=1;Board[curBlock.x+i][curBlock.y+j][1]=curBlock.color;}}}}/* draw one line of the board */void _INNER_HELPER PaintBoard(){int i,j,fillcolor;for(j=max((TopLine-4),0);j<BoardHeight;j++){for(i=0;i<BoardWidth;i++){fillcolor=Board[i][j][0]? Board[i][j][1]:BkGndColor;setfillstyle(SOLID_FILL,fillcolor);floodfill(BoardLeft+i*CellSize+CellSize/2,BoardTop+j*CellSize+CellSize/2,Border Color);}}}/* check if one line if filled full and increase the totalScore! */void _INNER_HELPER CheckBoard(){int i,j,k,score=10,sum=0,topy,lines=0;/* we find the top empty line! */j=topy=BoardHeight-1;do{sum=0;for(i=0;i< BoardWidth; i++){sum+=Board[i][topy][0];}topy--;} while(sum>0 && topy>0);/* remove the full filled line (max remove lines count = 4) */do{sum=0;for(i=0;i< BoardWidth; i++)sum+=Board[i][j][0];if(sum==BoardWidth)/* we find this line is full filled, remove it! */ {/* move the cells data down one line */for(k=j; k > topy;k--){for(i=0;i<BoardWidth;i++){Board[i][k][0]=Board[i][k-1][0];Board[i][k][1]=Board[i][k-1][1];}}/*make the top line empty! */for(i=0;i<BoardWidth;i++){Board[i][topy][0]=0;Board[i][topy][1]=0;}topy++; /* move the topline downward one line! */lines++; /* lines <=4 */TotalScore+=score;score*=2; /* adding: 10, 30, 70, 150 */}elsej--;} while(sum>0 && j>topy && lines<4);/* speed up the game when score is high, minimum is 400 */FrameTime=max(1200-100*(TotalScore/200), 400);TopLine=topy;/* update the top line *//* if no lines remove, only add 1: */if(lines==0)TotalScore++;}/* display the score */void _INNER_HELPER DisplayScore(){setcolor(BkGndColor);outtextxy(ScoreBoardLeft+5,ScoreBoardTop+5,info_score);setcolor(ScoreColor);sprintf(info_score,"Score: %d",TotalScore);outtextxy(ScoreBoardLeft+5,ScoreBoardTop+5,info_score);}/* we call this function when a block is inactive. */void UpdateBoard(){FillBoardData();CheckBoard();PaintBoard();DisplayScore();}/* pause the game, and timer handler stop move down the block! */int PauseGame(){int key=0;DisplayInfo("Press P to Start or Resume!");while(key!=K_P && key!=K_ESC){while(!(key=GetKeyCode())){}}DisplayInfo(info_help);return key;}/* quit the game and do cleaning work. */void QuitGame(){closegraph();}/* the entry point function. */void main(){int i,flag=1,j,key=0,tick=0;InitGame();if(PauseGame()==K_ESC)goto GameOver;/* wait until a key pressed */while(key!=K_ESC){/* wait until a key pressed */while(!(key=GetKeyCode())){tick++;if(tick>=FrameTime){/* our block has dead! (can't move down), we get next block */ if(!MoveBlock(&curBlock,0,1)){UpdateBoard();NextBlock();if(!CanMove(0,1))goto GameOver;}tick=0;}delay(100);}switch(key){case K_LEFT:MoveBlock(&curBlock,-1,0);break;case K_RIGHT:MoveBlock(&curBlock,1,0);break;case K_DOWN:MoveBlock(&curBlock,0,1);break;case K_UP:RotateBlock(&curBlock);break;case K_SPACE:DropBlock(&curBlock);break;case K_P:PauseGame();break;}}GameOver:DisplayInfo("GAME OVER! Press any key to exit!");getch(); /* wait the user Press any key. */QuitGame();}----------------------【代码文件结尾】-------------------------------基本实现了大部分功能没有加时钟控件,所以方块不能自行下降.没有计分器主要精力放在功能实现及结构上希望有高手能指点下不足之下.全部源码如下using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Configuration;namespace WindowsApplication2{public class MainRun{public static void Main(){Form1 f=new Form1();f.Width=309;f.Height=485;Application.Run(f);}}public partial class Form1 : Form{public Form1(){Csh(); //程序初始化}TxPaint tx; //自定义图形绘制类void Csh(){this.BackColor = Color.AliceBlue;tx = new TxPaint(new txfactory(),this.BackColor); //初始化图形工厂tx.CreateTx();}protected override void OnPaint(PaintEventArgs e){tx.Paint(CreateGraphics());}protected override void OnKeyDown(KeyEventArgs e){Rectangle re = new Rectangle(0, 0, this.Width, this.Height);tx.KeyEvent(e,re);//tx.Paint(this.CreateGraphics());}}/// <summary>/// 抽象图形类/// </summary>public abstract class TxClass{public Rectangle[] r; //储存图形public SolidBrush blueBrush; //储存颜色/// <summary>/// 图形绘制/// </summary>/// <param name="gg">传入需绘制的Graphics</param>public void paint(Graphics gg){Pen rPen = new Pen(Color.Black);Graphics g = gg;g.DrawRectangles(rPen, r);for (int i = 0; i < r.Length; i++){r[i].Inflate(-1, -1);}g.FillRectangles(blueBrush, r);for (int i = 0; i < r.Length; i++){r[i].Inflate(1, 1);}}/// <summary>/// 键盘点击事件/// </summary>/// <param name="e">键盘点击值</param>/// <param name="MoveRe">积木图形移动范围</param>public void KeyEvent(KeyEventArgs e,Rectangle MoveRe){#region 键盘的上下左右点击事件int intkey = e.KeyValue;// 下if (intkey == 83 || intkey == 40){//if (GetMax_Y() + 90 < MoveRe.Height) //将往下移动限制范围取消,以便于落底时左右移动的判断//{for (int i = 0; i < r.Length; i++){r[i].Offset(0, 30);}//}}//// 上if (intkey == 87 || intkey == 38){for (int i = 0; i < r.Length; i++){r[i].Offset(0, -30);}}// 左if (intkey == 65 || intkey == 37){if (GetMix_X() - 30 > 0 || GetMix_X() - 30 == 0) {for (int i = 0; i < r.Length; i++){r[i].Offset(-30, 0);}}}//右if (intkey == 68 || intkey == 39){if (GetMax_X() + 60 < MoveRe.Width){for (int i = 0; i < r.Length; i++){r[i].Offset(30, 0);}}}#endregionif (intkey == 74 || intkey == 97){BX(MoveRe);}}/// <summary>/// 变形/// </summary>public abstract void BX(Rectangle re);/// <summary>/// 获取最大X坐标/// </summary>/// <returns></returns>public int GetMax_X(){int itemp = r[0].X;for (int i = 0; i < r.Length - 1 ; i++){if (itemp < r[i + 1].X){itemp = r[i + 1].X;}}return itemp;}/// <summary>/// 获取最小X坐标/// </summary>/// <returns></returns>public int GetMix_X(){int itemp = r[0].X;for (int i = 0; i < r.Length - 1; i++){if (itemp > r[i + 1].X){itemp = r[i + 1].X;}}return itemp;}/// <summary>/// 获取最大Y坐标/// </summary>/// <returns></returns>public int GetMax_Y(){int itemp = r[0].Y;for (int i = 0; i < r.Length - 1; i++){if (itemp < r[i + 1].Y){itemp = r[i + 1].Y;}}return itemp;}/// <summary>/// 克隆/// </summary>/// <param name="T">传入对象数据类型</param>/// <returns></returns>public TxClass Clone(Type T){TxClass TempTxClass = (TxClass)Activator.CreateInstance(T); for (int i = 0; i < r.Length; i++){//TempTxClass.r[i].Height = r[i].Height;//TempTxClass.r[i].Width = r[i].Width;//TempTxClass.r[i].X = r[i].X;//TempTxClass.r[i].Y = r[i].Y;TempTxClass.r[i] = r[i]; // Rectangle 为结构值类型TempTxClass.blueBrush = blueBrush;return TempTxClass;}}/// <summary>/// 派生类/// </summary>public class TxLong : TxClass{public TxLong(){Size s = new Size(30, 30);Point po = new Point(120, -120);Rectangle re0 = new Rectangle(po, s);po.Y = -90;Rectangle re1 = new Rectangle(po, s);po.Y = -60;Rectangle re2 = new Rectangle(po, s);po.Y = -30;Rectangle re3 = new Rectangle(po, s);po.Y = 0;Rectangle re4 = new Rectangle(po, s);r = new Rectangle[] { re0, re1, re2, re3, re4 };blueBrush = new SolidBrush(Color.Yellow);}public override void BX(Rectangle re){if (r[0].X == r[1].X && r[1].Y > 0){if (r[0].X - 30 > 0 && r[4].X + 90 < re.Width){r[0].Location = new Point(r[2].X - 60, r[2].Y);r[1].Location = new Point(r[2].X - 30, r[2].Y);r[2].Location = new Point(r[2].X, r[2].Y);r[3].Location = new Point(r[2].X + 30, r[2].Y);r[4].Location = new Point(r[2].X + 60, r[2].Y);}}else{if (r[4].Y + 120 < re.Height){r[0].Location = new Point(r[2].X, r[2].Y - 60);r[1].Location = new Point(r[2].X, r[2].Y - 30);r[2].Location = new Point(r[2].X, r[2].Y);r[3].Location = new Point(r[2].X, r[2].Y + 30);r[4].Location = new Point(r[2].X, r[2].Y + 60);//MessageBox.Show(string.Format("{0} {1}", r[4].Y, re.Height)); }}}}/// <summary>/// 派生类long/// </summary>public class TxBox : TxClass{public TxBox(){Size s = new Size(30, 30);Point po = new Point(90, -30);Rectangle re0 = new Rectangle(po, s);po.X = 120;Rectangle re1 = new Rectangle(po, s);po.X = 90;po.Y = 0;Rectangle re2 = new Rectangle(po, s);po.X = 120;Rectangle re3 = new Rectangle(po, s);r = new Rectangle[] { re0, re1, re2, re3 }; blueBrush = new SolidBrush(Color.Moccasin);}public override void BX(Rectangle re){}}/// <summary>/// 派生类Z/// </summary>public class TxZ : TxClass{public TxZ(){Size s = new Size(30, 30);Point po = new Point(90, -30);Rectangle re0 = new Rectangle(po, s);po.X = 120;Rectangle re1 = new Rectangle(po, s);po.Y = 0;Rectangle re2 = new Rectangle(po, s);po.X = 150;Rectangle re3 = new Rectangle(po, s);r = new Rectangle[] { re0, re1, re2, re3 }; blueBrush = new SolidBrush(Color.PaleGoldenrod); }public override void BX(Rectangle re){if (r[2].Y == r[3].Y){//if (r[0].X + 30 > 0)//{r[2].Location = new Point(r[2].X - 30, r[2].Y);r[3].Location = new Point(r[3].X - 30, r[3].Y - 60); //}}else{if (r[0].X + 90 < re.Width){r[2].Location = new Point(r[2].X + 30, r[2].Y);r[3].Location = new Point(r[3].X + 30, r[3].Y + 60); }}}}/// <summary>/// 派生类S/// </summary>public class TxS : TxClass{public TxS(){Size s = new Size(30, 30);Point po = new Point(120, -30);Rectangle re0 = new Rectangle(po, s);po.X = 150;Rectangle re1 = new Rectangle(po, s);po.Y = 0;po.X = 90;Rectangle re2 = new Rectangle(po, s);po.X = 120;Rectangle re3 = new Rectangle(po, s);r = new Rectangle[] { re0, re1, re2, re3 }; blueBrush = new SolidBrush(Color.Aqua);}public override void BX(Rectangle re){if (r[2].Y == r[3].Y){//if (r[0].X + 30 > 0)//{r[2].Location = new Point(r[2].X + 30, r[2].Y - 60); r[3].Location = new Point(r[3].X + 30, r[3].Y);//}}else{if (r[2].X - 30 > 0 || r[2].X - 30 == 0){r[2].Location = new Point(r[2].X - 30, r[2].Y + 60); r[3].Location = new Point(r[3].X - 30, r[3].Y);}}}}/// <summary>/// 派生类L/// </summary>public class TxL : TxClass{public TxL(){Size s = new Size(30, 30);Point po = new Point(120, -30);Rectangle re0 = new Rectangle(po, s);po.Y = 0;Rectangle re1 = new Rectangle(po, s);po.X = 150;Rectangle re2 = new Rectangle(po, s);po.X = 180;Rectangle re3 = new Rectangle(po, s);po.X = 210;Rectangle re4 = new Rectangle(po, s);r = new Rectangle[] { re0, re1, re2, re3, re4 };blueBrush = new SolidBrush(Color.BurlyWood);}public override void BX(Rectangle re){if (r[0].X == r[1].X && r[0].X < r[4].X){if (r[4].Y + 120 < re.Height || r[4].Y + 60 == re.Height) //下限制{r[0].Location = new Point(r[0].X + 30, r[0].Y);r[1].Location = new Point(r[1].X, r[1].Y - 30);r[2].Location = new Point(r[2].X - 30, r[2].Y);r[3].Location = new Point(r[3].X - 60, r[3].Y + 30);r[4].Location = new Point(r[4].X - 90, r[4].Y + 60);}}else if (r[0].Y == r[1].Y && r[0].Y < r[4].Y){if (r[1].X > 0 && r[0].X + 50 < re.Width) //左右限制{r[0].Location = new Point(r[0].X + 30, r[0].Y + 30);r[1].Location = new Point(r[1].X + 60, r[1].Y);r[2].Location = new Point(r[2].X + 30, r[2].Y - 30);r[3].Location = new Point(r[3].X, r[3].Y - 60);r[4].Location = new Point(r[4].X - 30, r[4].Y - 90);}}else if (r[0].X == r[1].X && r[0].X > r[4].X){if (r[0].Y + 90 < re.Height || r[0].Y + 90 == re.Height) //下限制{r[0].Location = new Point(r[0].X - 60, r[0].Y + 30);r[1].Location = new Point(r[1].X - 30, r[1].Y + 60);r[2].Location = new Point(r[2].X, r[2].Y + 30);r[3].Location = new Point(r[3].X + 30, r[3].Y);r[4].Location = new Point(r[4].X + 60, r[4].Y - 30);}}else if (r[0].Y == r[1].Y && r[0].Y > r[4].Y){if (r[4].X + 90 < re.Width || r[4].X + 90 == re.Width) //右限制{r[0].Location = new Point(r[0].X, r[0].Y - 60);r[1].Location = new Point(r[1].X - 30, r[1].Y - 30);r[2].Location = new Point(r[2].X, r[2].Y);r[3].Location = new Point(r[3].X + 30, r[3].Y + 30);r[4].Location = new Point(r[4].X + 60, r[4].Y + 60);}}}}/// <summary>/// 图形工厂/// </summary>abstract class AbstractTxFactory{abstract public TxClass CreateTx();}/// <summary>/// 工厂类/// </summary>class txfactory : AbstractTxFactory{/// <summary>/// 随机生成一个图形类实例/// </summary>/// <returns></returns>public override TxClass CreateTx(){//return new TxL();Random ran = new Random();switch (ran.Next(5)){case 0:return new TxLong();//break;case 1:return new TxBox();//break;case 2:return new TxZ();//reak;case 3:return new TxS();case 4:return new TxL();default :return null;//break;}}}/// <summary>/// 图形绘制类/// </summary>class TxPaint{List<TxClass> LTx;TxClass tx;AbstractTxFactory txCreate; //创建工厂Graphics graphics; //用于储存当前图形活动区域Color color; //储存背景色/// <summary>/// 构造函数/// </summary>/// <param name="txCreate">图形生成工厂</param>/// <param name="graphics">绘制图形</param>/// <param name="color">擦除颜色</param>public TxPaint(AbstractTxFactory txCreate,Color color){this.txCreate = txCreate;this.color = color;LTx = new List<TxClass>();}/// <summary>/// 创建一个新图形/// </summary>public void CreateTx(){tx = txCreate.CreateTx();}/// <summary>/// 重新绘制图形/// </summary>/// <param name="graphics"></param>public void Paint(Graphics graphics){this.graphics = graphics;foreach (TxClass t in LTx){t.paint(graphics);}SetupGraphics();tx.paint(graphics);}/// <summary>/// 键盘点击事件/// </summary>public void KeyEvent(KeyEventArgs k, Rectangle re){TxClass tempTxC = tx.Clone(tx.GetType());tx.KeyEvent(k, re);if (TxPd()) //如果有重叠现象则恢复上次位置(下降或变形){tx = tempTxC;if (k.KeyValue == 83 || k.KeyValue == 40) //往下按键时碰到其他图形时ClsTx(re); //消除满条图形,并重新创建新积本}}else if (tx.GetMax_Y() > re.Height - 60) //往下按键时到底部时{tx = tempTxC;graphics.Clear(color); //清除当前活动图形tx.paint(graphics); //重绘活动图形新坐标位ClsTx(re);}else{graphics.Clear(color);tx.paint(graphics);}}/// <summary>/// 图形重叠判断/// </summary>/// <returns>是/否</returns>bool TxPd(){List<Rectangle> l = new List<Rectangle>();foreach (TxClass Lt in LTx){foreach (Rectangle Lr in Lt.r){l.Add(Lr);}}foreach (Rectangle r in tx.r){if (l.Contains(r)){return true;}}return false;}/// <summary>/// 满条图形消除/// </summary>void ClsTx(Rectangle re){LTx.Add(tx);CreateTx();if (TxPd()) //创建的同时发生图形重叠则game over{GameOver(re);}else{#region 图形满格消除for (int i = 0; i < LTx.Count; i++)。
使用C语言写俄罗斯方块
![使用C语言写俄罗斯方块](https://img.taocdn.com/s3/m/eb07c2f0ba0d4a7302763aea.png)
我设想的俄罗斯方块如下图:我们先弹出一个窗口。
首先,新建一个windows应用工程,如下图:然后删除工程里预写好的代码,添加如下代码:然后再点击“编译并运行”按钮,弹出窗口:这样,我们的第一步,就算完成了,呵。
以后的我们的所有代码都是在上边代码的基础上添加而成的。
如图:上图是一种方块变形的四种情况,为表示以上所有的四的情况,我们需要建立一个三维数组:上边建立的三维数组应该不难理解吧,m_olshapePiece[0][x][y]就表示第一种形状,m_olshapePiece[1][x][y]表示第二种形状,m_olshapePiece[2[x][y]表示第三种形状,m_olshapePiece[3][x][y]表示第四种形状。
我们按照同样的方法,把其它几种形状的矩阵弄好,并且把它们设为全局变量,如下:接下来,让我们来看仔细看看我们游戏的布局:如上图所示,我们的游戏由五大块组成:一、按钮:这个就是完成一些特定功能的,比如开始、停止、暂停等等,第一个按钮在窗口上的坐标是(12,16)。
二、BigMap:它是我们游戏的主要区域,它由二维数组BigMap[12][21]来储存该格子是已有方块,BigMap由DrawBigMap()函数完成在窗口上的绘制。
它在窗口上的坐标是(12,66)。
三、CurPiece:它是当前正在掉落的方块,它由三维数组CurPiece[4][5][5]来储存,CupPiece是一个5*5的二维平面,但因为它有4种变形,所以我们需要准备4个二维平面。
CurPiece由DrawCurPiece()函数完成在窗口上的绘制。
它在窗口上的坐标由变量xPos、yPos储存。
四、NextPiece:它表示下一个要掉落的方块,它由三维数组NextPiece[4][5][5]来储存,由DrawNextPiece()函数完成在窗口上的绘制。
它在窗口上的坐标是(277,66)。
五、Score:它表示当前得分和游戏等级,由变量score和level储存(为了方便,我们还需要同时字符串scoreString[20]和levelString[20]储存),由DrawScore()函数完成在窗口上的绘制。
C语言的俄罗斯方块
![C语言的俄罗斯方块](https://img.taocdn.com/s3/m/38a1acaddd3383c4bb4cd2c2.png)
操作:
方向键向上:旋转(顺时针旋转)
方向键向下:加速下落
方向键向左:左移
方向键向右:右移
空格键:暂停
ESC:退出
R建:重新开始
计分规则:
一次消去一行:10分
一次消去二行:30分
一次消去三行:50分
一次消去四行:80分
测试源代码并生成可执行文件:
要测试源代码,必须将源代码文件“俄罗斯方块.c”放在turboC编译器的指定文件夹内(如TC2.0是直接放在TC目录下,TC201E版本要放在目录下的project文件夹内),还需拷贝附件中的GRAPHICS.LIB文件放在tc目录下LIB文件夹中(要覆盖掉原来的),运行就可得到能在任何目录或其它兼容机上运行的可执行程序俄罗斯方块.exe。
GRAPHICS.LIB文件是装入了EGA VGA.OBJ的目标模块的库文件。
运行游戏会在游戏目录中自动生成HIGHSCOR文件和LASTSCOR文件,这两个文件分别是用来储存最高分记录和上次得分记录的。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
for (i = 0; i < 4; i++) { view_x = STARTX + SCREEN_WIDTH*2 + 7; for (j = 0; j < 4; j++) { goto_rood(view_x, view_y); n = (bk >> (3 - j) + 4 * (3 - i)) & 1; if (n) printf("□"); else printf(" "); view_x += 2; } view_y++; }
int gamescreen[SCREEN_LENGTH + 2][SCREEN_WIDTH + 2]; //界面数组,包含边框
int blockdata[4][4]; //用于存放方块的数据 //隐藏光标函数 void hide_curcor() {
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_CURSOR_INFO cci; GetConsoleCursorInfo(hOut, &cci); cci.bVisible = false; SetConsoleCursorInfo(hOut, &cci); }
goto_rood(STARTX, STARTY + i); printf("┃"); goto_rood(STARTX + (SCREEN_WIDTH + 1) * 2, STARTY + i); printf("┃"); goto_rood(STARTX + (SCREEN_WIDTH + CONTRAL_WIDTH + 2) * 2, STARTY + i); printf("┃"); }
}
//CLOCKS_PER_SECOND
1000000
返 回 值 是 clock() /
//随机生成一个小于 max 的数 int Random(int max) {
time_t num; num = time(NULL) % max; return num; } //初始化游戏窗口 void IniGameWindow() { int i, j; //将游戏区域屏幕初始化为 0, 即无填充状态 for (i = 0; i < 4; i++)
Message("[SpaceBack]", STARTX + 2 * SCREEN_WIDTH + 4, STARTY + 18); Message("退出 [ESC]", STARTX + 2 * SCREEN_WIDTH + 4, STARTY + 20); Message("设置 S", STARTX + 2 * SCREEN_WIDTH + 4, STARTY + 22);
gamescreen[0][j] = gamescreen[SCREEN_LENGTH + 1][j] = 1; for (i = 0; i < SCREEN_LENGTH + 2; i++)
gamescreen[i][0] = gamescreen[i][SCREEN_WIDTH + 1] = 1;
Message("--------------", STARTX + 2 * SCREEN_WIDTH + 4, STARTY + 5); Message("分数: ", STARTX + 2 *SCREEN_WIDTH + 4, STARTY + 7);
Message("--------------", STARTX + 2 * SCREEN_WIDTH + 4, STARTY + 9); Message("等级: ", STARTX + 2 * SCREEN_WIDTH + 4, STARTY + 11);
//光标跳转函数 void goto_rood(int x, int y) {
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); COORD pos; pos.X = x; pos.Y = y; SetConsoleCursorPosition(hOut, pos); }
int i, j;
int screen_r = yy - STARTY; int screen_c = (xx - STARTX) / 2;
for (j = 0; j < 4; j++) for (i = 0; i < 4; i++) { if (block[i][j]) if (gamescreen[screen_r + i][screen_c + j])//如果相邻位置已有方块占据 return TRUE; }
printf("┛"); goto_rood(STARTX, STARTY + SCREEN_LENGTH + 1); printf("┗"); for (i = 0; i < SCREEN_WIDTH + CONTRAL_WIDTH + 1; i++)
printf("━"); goto_rood(STARTX + (SCREEN_WIDTH + 1) * 2, STARTY + SCREEN_LENGTH + 1); printf("┻"); for(i = 1; i <= SCREEN_LENGTH; i++) {
}//1 3 10 14 15 17 typedef unsigned __int16 u_int16; //新定义一个只表示 16 位的 int 的数据类型,其实直接 short int 就行。。 = =
//总共 19 种方块,这个数组用于表示 19 种方块的数据
u_int16 blockinds[19] = { 0x6600, //方块 □
//例如 0x6600,表示成二进制就是
0x4444, 0x0F00, // | — 0x2640, 0xC600, // =_ ∟ 块的样式
// 0110 // 0110
发现没有 1 表示的区域就是所绘方
0x4620, 0x3600, // _=
//
0x2700, 0x2620, 0x7200, 0x4640, // ⊥
}
// 越界函数特别需要注意------------------------------------------------------------------bool LeftCollision(int xx, int yy, int block[][4]) //能否向左移,即向左移是否发生碰撞 {
Message("--------------", STARTX + 2 * SCREEN_WIDTH + 4, STARTY + 13); Message("开始 [回车]", STARTX + 2 * SCREEN_WIDTH + 4, STARTY + 15); Message("暂停 / 开始", STARTX + 2 * SCREEN_WIDTH + 4, STARTY + 17);
for (j = 0; j < 4; j++) blockdata[i][j] = 0; //初始化方块数据
for (i = 1; i <= SCREEN_LENGTH; i++) for (j = 1; j <= SCREEN_WIDTH; j++) gamescreen[i][j] = 0;
//将屏幕边框初始化为 1,即满填充状态 for (j = 0; j < SCREEN_WIDTH + 2; j++)
//显示文字信息 void Message(char *s, int x, int y) {
goto_rood(x, y); puts(s); }
void delay(int ms) //延迟函数 {
int start, finish; start = finish = clock();
CLOCKS_PER_SECOND while (start + ms > finish) finish = clock();
}
void RemoveBlock(int xx, int yy) //消除方块 //传递当前矩阵的位置
{ int i, j; int x1, y1 = yy; for (i = 0; i < 4; i++) { x1 = xx; for (j = 0; j < 4; j++) { goto_rood(x1, y1); if (blockdata[i][j]) printf(" "); x1 += 2; } y1++; }