补:写的这些程序没运行,写之后就直接弄上来了,后来用这些程 序来合成时,发现有些小错误,如有汉字字符,或名字写错,Rectangle函数的参数用错等。这里就不再改了,太过于麻烦,那些错误大家一眼就看看出来 的。在合成版本中,所有错误均为被纠正过来J。
二 各部分的实现
1 设定方块的 大小及游戏区坐标
对此我们可以 这样写 :
- const int SquareSize = 20;
- const int GameSizeX = 50;
- const int GameSizeY = 50;
这样我们定义了方 块各边的大小为 20 。游戏区开始坐标为 (50,50);
这里的数组并不唯 一,根据个人爱好而定。
我们这里我们还是 有必要定义一下游戏区的信息:
- const int GameRegionWidth = 10;
- const int GameRegionHeight = 20;
- int GameMapStates[20][10];
// 这里我曾试过分别使用 GameRegionWidth 和 GameRegionHeight 代 // 替 10 和 20 ,但我使用的编译 器不支持。
2 建立游戏区 :
建立游戏去, 即一个 20 行, 10 列的网格游戏去,当然这个网格是隐藏的,是不显示出来的。也不需 要我们区画的。只要我们心中有这个网格就 OK 。 J
好,我们现在 开始画了。我们使用的函数为 .
- BOOL Rectangle(
- HDC hdc,
- int nLeftRect,
- int nTopRect,
- int nRightRect,
- int nBottomRect
- );
我们既然决定要使用这个函数我们就的得到该函数相应的参数。
- int LeftX = GameSizeX; //游戏区左上角横坐标
- int LeftY = GameSzieY; //游戏区坐上角纵坐标
- //游戏区右下角横坐标
- int RightX = GameSizeX + GameRegionWidth * SquareSize;
- //游戏区右下角纵坐标
- int RightY = GameSizeY + GameRegionHeight * SquareSize;
好的,我们已经得到 5 个参数中的四个参数了。至于 HDC ,我们可以根据当时的情况来获得。我们该函数不同的用处获得 HDC 的方式不同。好了,画游戏区的功能已经实现了,但我们总不能每 次调用的时候都写这么多吧?我想为了美观与程序的易读性我们还是用个函数封装下好 J 。
好的,我们来封装一下该函数:
- void DrawGameRegion( HDC hdc)
- {
- int LeftX = GameSizeX; //游戏区左上角横坐标
- int LeftY = GameSzieY; //游戏区坐上角纵坐标
- //游戏区右下角横坐标
- int RightX = GameSizeX + GameRegionWidth * SquareSize;
- //游戏区右下角纵坐标
- int RightY = GameSizeY + GameRegionHeight * SquareSize;
- Rectangle(hdc,LeftX,LeftY,RightX,RightY);
- }
封装成功 !
3 初始化俄罗斯方块的 7 中图形
- const POINT Terics[7][4][4] =
- {
- {
- 0,0,1,0,0,1,-1,1,
- 0,0,0,1,1,1,1,2,
- 0,0,1,0,0,1,-1,1,
- 0,0,0,1,1,1,1,2
- },
- {
- 0,0,1,0,1,1,2,1,
- 0,0,0,1,-1,1,-1,2,
- 0,0,1,0,1,1,2,1,
- 0,0,0,1,-1,1,-1,2
- },
- {
- 0,0,0,1,0,2,1,2,
- 0,0,0,1,-1,1,-2,1,
- 0,0,1,0,1,1,1,2,
- 0,0,0,1,1,0,2,0
- },
- {
- 0,0,0,1,0,2,-1,2,
- 0,0,1,0,2,0,2,1,
- 0,0,1,0,0,1,0,2,
- 0,0,0,1,1,1,2,1
- },
- {
- 0,0,0,1,0,2,0,3,
- 0,0,1,0,2,0,3,0,
- 0,0,0,1,0,2,0,3,
- 0,0,1,0,2,0,3,0
- },
- {
- 0,0,1,0,0,1,1,1,
- 0,0,1,0,0,1,1,1,
- 0,0,1,0,0,1,1,1,
- 0,0,1,0,0,1,1,1
- },
- {
- 0,0,1,0,2,0,1,1,
- 0,0,0,1,0,2,1,1,
- 0,0,0,1,-1,1,1,1,
- 0,0,0,1,0,2,-1,1
- }
- };
这个我也曾下到我的思路里了。为了完美只好在这里再写一遍了 J 。
哇,一大推的数字是什么意思啊 ?:-D ,看似很难,其实很简单的。你
只需当前图形的形状和方向判断组成它的每个方块的右上角坐标比
当前坐标便宜多少,然后添上去就 OK 了。注意这里的坐标是游戏区
的坐标。即,偏移 1 相当于原来的坐标偏移一个方块边长的大小。
4 画方块
说了半天如何画一个方块还没实现呢, J 这 里我们仍然是函数封装。
- void DrawRectangle( HDC hdc, int x, int y)
- {
- int LeftX = GameSizeX + x * SquareSize;
- int LeftY = GameSizeY + y * SquareSize;
- int RightX = GameSizeX + SquareSize;
- int RightY = GameSizeY + SquareSize;
- Rectangle(hdc,LeftX,LeftY,RightX,RightY);
- }
5 画俄罗斯方块
方块画好了, 我们该画各种形状的俄罗斯方块了。。仍然是函数封装哦 J 。
- void DrawTetromino( HDC hdc, int shape, int dir, int x, int y)
- {
- int index,nx,ny;
- for ( index = 0; index < 4; ++index)
- {
- nx = Terics[shape][dir][index].x + x;
- ny = Terics[shape][dir][index].y + y;
- DrawRectangle(hdc,nx,ny);
- }
- }
6 判断范围
该画的我们都 画好了,在让他移动之前我们先将它的范围设定一下吧。别急哦 J
- BOOL IsOutOfRegion( int shape, int dir, int x, int y)
- {
- int index;
- int nx,ny;
- for (index = 0; index < 4; ++index)
- {
- nx = Terics[shape][dir][index].x + x;
- ny = Terics[shape][dir][index].y + y;
- if (ny < 0 || ny >= GameRegionHeight || nx < 0 || nx >= GameRegionWidth || GameMapStates[nx][ny] != 0)
- {
- return TRUE;
- }
- }
- return FALSE;
- }
7 保存游戏区当前的状态
该是保存状态的时候了。。 J 这 应该是写俄罗斯方块里最难得东西了(个人认为哈)。并不是这里的代码有多难,而是它的思想难。
- void SaveStateofTerics( int shape, int dir, int x, int y)
- {
- int index;
- int nx,ny;
- for ( index = 0; index < 4; ++index)
- {
- nx = Terics[shape][dir][i].x + x;
- nx = Terics[shape][dir][i].y + y;
- GameMapStates[nx][ny] = 1;
- }
- }
8 消去一行
- void DeleteTericsFromOfGameRegion( int shape, int dir, int x, int y)
- {
- bool flag = TRUE;
- int indexX,indexY;
- int m,n;
- for (indexX = 0; indexX < GameRegionHeight; ++index)
- for (indexY = 0; indexY < GameRegionWidth; ++indexY)
- {
- if (GameMapStates[indexX][indexY] != 1)
- {
- flag = FALSE;
- }
- if (flag)
- {
- for (m = indexX; m >= 0; --m)
- for (n = 0; n < GameRegionWidth;++n)
- {
- GameMapStates[m][n] = GameMapStates[m-1][n]
- }
- }
- }
9 显示问题
对于显示问 题,我们使用我们的思路里的第二种方法来实现,故我们需要定义擦除函数,加载函数。好的,我们开始吧。 J
- void EraseGameRegion( HDC hdc)
- {
- RECT rect;
- rect.left = GameSizeX;
- rect.top = GameSizeY;
- rect.right = GameSizeX + GameRegionWidth * SquareSize;
- rect.bottom = GameSizeY + GameRegionHeight * SquareSize;
- HBRUSH brush = CreateSolidBrush(RGB(255,255,255));
- FillRect(hdc,&rect,brush);
- DrawGameRegion(hdc); //游戏区被删除,重新画一边
- }
定义加载函数
- void LoadCurrentTerics( HDC hdc)
- {
- int indexX,indexY;
- for (indexX = 0; indexX < GameRegionWidth; ++indexX)
- for (indexY = 0; indexY < GameRegionHeight; ++indexY)
- {
- if (GameMapStates[indexX][indexY] == 1)
- {
- DrawRectangle(hdc,indexX,indexY);
- }
- }
- }
10 初始化问题
在俄罗斯方块 游戏中因为每次新方块都是从固定的地方出来,所以我们应该对之有一个初始化。为此我们还应该定义一个变量来保存当前图形的形状,方向,坐标;
- struct CurrentTerics{
- int shape,dir,x,y;
- }CurrentTericInfo;
注意这个应该 为一个全局的。
封装一个初始 化函数:
- void InitTericsInfo()
- {
- srand((unsigned)time(NULL));
- CurrentTericsInfo.shape = rand()%7;
- CurrentTericsInfo.dir = 0;
- CurrentTericsInfo.x = 4;
- CurrentTericsInfo.y = 0;
- }
好的。至此一 个俄罗斯方块的各部分都已实现,只剩下组装工作了。至于如何组装,该把这些函数放到那里,我的理路里都已有了大部分的方法。
参照帖子:http://www.rupeng.com/forum/thread-2533-1-1-uid2704.html