当前位置:文档之家› 教你用c语言写俄罗斯方块

教你用c语言写俄罗斯方块

来如鹏挺长时间了,受益很多希望更多的朋学加入进来做俄罗斯方块是因为无意中在杨老师的帖子看到说最少也要能做出俄罗斯方块这样的东西出来,我想这个意思能做出俄罗斯方块就说明水平到了一个层次了吧。

刚才注意到音乐播放器居然下载超过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.。

相关主题