共有回帖数  0  个 
	 
	
	
	
     
          
          
               
				
			 
				
					 
 
            
				   - 
						
						
							 
									俄罗斯方块终于成型了,由于同时还在写其他项目,总是写着写着就思路中断了,看来写代码还是需要一气呵成。好啦,废话不多说,直接开喷,哦不,开讲^_^。
  
 这次时间虽长,其实我是用心的,duang,做了一个动态的开始界面,注意是动态的哦,看来是不是像加了特技。
  
 游戏主界面是这个样子的。 
 下面介绍一下游戏的玩法:
 1 一个方块由4个格子组成,穷尽4个格子能够组成的所有图形,共有19种图形(方向不同也算是一种),19种图形分为7组分别是:
  
 2 随机生成这19种方块中的一种,对这个方块可以进行左移,右移,或者按顺序改变成这个方块所在的组内的其他方块,共三种操作。
 3 方块会不断的下落,碰到障碍物就停止下落,变成一个不再能操作的方块。
 4 当落下的方块使得一行堆满时,就可以消去一行,并加分。
 5 最终不能操作的方块的高度超过最大高度时,游戏失败。以上就是玩法,其实游戏都是根据玩法编写的,俄罗斯方块的玩法大家当然是知道的,总结玩法时其实就是在思考如何用代码实现这些玩法。
 以下是游戏代码,这次的代码比较多,得有小一千行,不过这次我多写了一些函数声明,同时全局变量的声明也比较占地方。网页上黏代码看起来实在蛋疼,上传pdf版,自己下下来看哈:
 #include "stdafx.h"
 #include "Tetris.h"
 #include windows.h
 #include time.h
 #include conio.h
 #includestdlib.h
 
 /************************************************************************
 * 该工程完成得比较粗糙,还有很多功能没有实现,也还有些BUG没有更改。
 * 针对该项目有任何意见,或不解的地方都欢迎大家在群里提出!!!
 *
 * 该工程以Visual Studio 2013编写,有可能其他版本的编译编译不过
 * (1)工程属性-配置属性- 常规-平台工具集(当前编译器)
 * (2)vs2013中加入了很多C11标准 比如 结构体,数组赋值 “{}”全赋值为0
 /************************************************************************/
 
 // 字体颜色
 #define F_BLUE FOREGROUND_BLUE // 深蓝
 #define F_H_BLUE 0x0001|0x0008 // 亮蓝
 #define F_GREEN 0x0002 // 深绿
 #define F_H_GREEN 0x0002|0x0008 // 亮绿
 #define F_RED 0x0004 // 深红
 #define F_H_RED 0x0004|0x0008 // 亮红
 #define F_YELLOW 0x0002|0x0004 // 深黄
 #define F_H_YELLOW 0x0002|0x0004|0x0008 // 亮黄
 #define F_PURPLE 0x0001|0x0004 // 深紫
 #define F_H_PURPLE 0x0001|0x0004|0x0008 // 亮紫
 #define F_CYAN 0x0002|0x0004 // 深青
 #define F_H_CYAN 0x0002|0x0004|0x0008 // 亮青
 #define F_WHITE 0x0004|0x0002|0x0001 //白
 #define F_H_WHITE 0x0004|0x0002|0x0001|0x0008 //空白
 
 #define WALL 1 //墙
 #define SHAPE 2 //方块
 
 int g_Map[40][30] = {};
 //记录19种图形的结构体,这个思维数组初学者还是不太容易理解的,这里可能需要仔细的想一想
 char g_aCubeShape[7][4][4][4] = {
 {
 {
 { 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, 1 } //■■■■
 },
 {
 { 0, 1, 0, 0 }, //■
 { 0, 1, 0, 0 }, //■
 { 0, 1, 0, 0 }, //■
 { 0, 1, 0, 0 }, //■
 },
 },
 
 {
 
 {
 { 0, 0, 0, 0 },
 { 0, 0, 0, 0 },
 { 0, 1, 1, 0 }, // ■■
 { 1, 1, 0, 0 } //■■
 
 },
 {
 { 0, 0, 0, 0 },
 { 1, 0, 0, 0 }, //■
 { 1, 1, 0, 0 }, //■■
 { 0, 1, 0, 0 } // ■
 }
 },
 {
 {
 { 0, 0, 0, 0 },
 { 0, 0, 0, 0 },
 { 1, 1, 0, 0 }, //■■
 { 0, 1, 1, 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, 0, 0 }, // ■
 { 0, 1, 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, 0 },
 { 1, 1, 1, 0 }, //■■■
 { 1, 0, 0, 0 } //■
 },
 {
 { 0, 0, 0, 0 },
 { 0, 0, 0, 0 },
 { 0, 0, 1, 0 }, // ■
 { 1, 1, 1, 0 } //■■■
 }
 
 },
 {
 {
 { 0, 0, 0, 0 },
 { 1, 1, 0, 0 }, //■■
 { 1, 0, 0, 0 }, //■
 { 1, 0, 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 },
 { 0, 0, 0, 0 },
 { 0, 0, 1, 0 }, // ■
 { 1, 1, 1, 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 },
 { 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, 0, 0 }, //■■
 { 0, 1, 0, 0 } // ■
 }
 },
 };
 
 typedef struct _RANDOM
 {
 int Dir; //随机出方向 0-3
 int Shape; //随机出形状 0-4
 int Colour; //随机出颜色 0-11
 }RANDOM, *pRANDOM;
 
 typedef struct _SHAPEINFO
 {
 BOOL IsObj; //是否正在移动
 COORD pos; //方块坐标
 int Dir; //方块方向
 int NewShape; //当前方块的形状
 DWORD Colour; //方块颜色
 }SHAPEINFO,*pSHAPEINFO;
 
 static int g_Score = 0; //当前分数
 static int g_Grade = 0; //当前等级
 
 
 ///////////////////////////////////////////////////////////////////////////////////
 //该函数作用:隐藏光标,设置光标位置,设置字符颜色
 void WriteChar(int Wide, int High, char*m_pszChar, int m_wArr);
 
 //该函数作用:欢迎界面
 void DrawPicture(void);
 
 // 该函数作用:初始化地图边界
 void InitMap();
 
 //该函数作用:在屏幕上打印地图边框
 void DrawMap();
 
 //该函数作用:设置控制台窗口大中及缓冲区大小
 void LniSehomepage();
 
 //该函数作用:当前行被填满时,消除当前行,并且将该行以上的图案向下移动一行
 void ClsShaep(int PosY);
 
 //该函数作用:判断该行是否填满
 BOOL CountScore();
 
 //该函数作用:产生随机数,随机第几类方块,该方块当前方向,随机方块颜色
 void Random(pRANDOM pRand);
 
 //该函数作用:擦除当前方块 在大数组中及屏幕上
 void ClcShanp(SHAPEINFO Shape);
 
 //该函数作用:画当前方块 在大数组中及屏幕上
 void DrawShanp(SHAPEINFO Shape);
 
 //该函数作用:将所有已经落下的不能移动的方块都在数组中赋值为墙,主要方便我判断碰撞
 void DrawShanpBuff(SHAPEINFO Shape);
 
 //该函数作用:判断方块是否能移动
 BOOL IsMove(SHAPEINFO Shape);
 
 //该函数作用:在地图右侧显示将要出现的图案
 void DrawOffsideInfo(SHAPEINFOShape);
 
 //该函数作用:相当于画,擦,判段方块都在这里面
 BOOL CollideEngine(pSHAPEINFO Shape, pSHAPEINFO OldShape);
 
 
 
 int _tmain(int argc, _TCHAR* argv[])
 {
 sinA:
 LniSehomepage();
 
 InitMap();
 DrawMap();
 COORD Pos = { 15, 3 }; //初始化方块出生点(右下角为中心点)
 RANDOM m_Rand = {};
 Random(&m_Rand); //随机
 
 SHAPEINFO m_NewShape = { true, Pos, 0, 1, m_Rand.Colour}; //当前出现的方块
 
 Random(&m_Rand);
 SHAPEINFO m_FutShape = { true, Pos, 0, 1, m_Rand.Colour}; //下一次将要出现的方块
 SHAPEINFO m_OldShape = m_NewShape;
 
 DrawShanp(m_NewShape); //绘制方块图案
 DrawOffsideInfo(m_FutShape); //绘制在右侧
 
 int iTime = 10000;
 while (true)
 {
 if (!m_NewShape.IsObj) //标志为假时,则重新生成图案
 {
 DrawShanpBuff(m_OldShape); //方块在数组中赋值为墙
 if (!CountScore()) //判断该行是否填满,并计分
 {
 break;
 }
 m_NewShape = m_FutShape;
 m_OldShape = m_FutShape;
 
 Random(&m_Rand);
 
 m_FutShape.Dir = 0;
 m_FutShape.NewShape =m_Rand.Shape;
 m_FutShape.Colour =m_Rand.Colour;
 
 DrawOffsideInfo(m_FutShape); //绘制在右侧
 DrawShanp(m_NewShape); //绘制方块图案
 }
 iTime--; //当iTime为假时,则自动向下移动一格
 if (!iTime)
 {
 m_NewShape.pos.Y++;
 CollideEngine(&m_NewShape,&m_OldShape); //相当于画,擦,判段方块
 iTime = 10000;
 
 }
 
 if (!_kbhit()) //没有键盘消息时,回到循环开始位置
 {
 continue;
 }
 char ch = _getch();
 switch (ch)
 {
 case 'W':
 case 'w': //变换方向
 {
 m_NewShape.Dir++;
 //方块,不用变化
 if (0 == m_NewShape.NewShape)
 {
 m_NewShape.Dir = 0;
 }
 //竖条,有两种变化
 else if (1 ==m_NewShape.NewShape)
 {
 if (m_NewShape.Dir  1)
 {
 m_NewShape.Dir = 0;
 }
 }
 //Z字型,有两种变化
 else if (2 ==m_NewShape.NewShape)
 {
 if (m_NewShape.Dir  1)
 {
 m_NewShape.Dir = 0;
 }
 }
 //倒Z字型,有两种变化
 else if (3 ==m_NewShape.NewShape)
 {
 if (m_NewShape.Dir  1)
 {
 m_NewShape.Dir = 0;
 }
 }
 //其余的都是四种变化
 else
 {
 if (m_NewShape.Dir  3)
 {
 m_NewShape.Dir = 0;
 }
 }
 }
 break;
 case 'S':
 case 's':
 {
 m_NewShape.pos.Y++;
 }
 break;
 case 'A':
 case 'a':
 {
 m_NewShape.pos.X--;
 }
 break;
 case 'D':
 case 'd':
 {
 m_NewShape.pos.X++;
 }
 break;
 case ' ':
 {
 
 }
 break;
 default:
 break;
 }
 CollideEngine(&m_NewShape,&m_OldShape);
 }
 //最后结束游戏未完成
 system("cls");
 WriteChar(15, 20, "游戏结束!", F_H_RED);
 while (!(_kbhit()))
 {
 WriteChar(26, 25, "PRESS ANY KEY TO CONTINUE", F_H_RED);
 Sleep(300);
 WriteChar(26, 25, " ", F_H_WHITE);
 Sleep(300);
 }
 system("cls");
 goto sinA;
 return 0;
 }
 
 
 /************************************************************************
 * 该函数作用:隐藏光标,设置光标位置,设置字符颜色
 * 参数:
 * wide: X坐标
 * High: Y坐标
 * m_pszChar: 字符
 * m_wArr: 颜色
 * 返回值:
 * void
 /************************************************************************/
 void WriteChar(int Wide, int High, char*m_pszChar, int m_wArr)
 {
 CONSOLE_CURSOR_INFO m_cci;
 m_cci.bVisible =FALSE; // 将该标志设为false 表示不显示光标
 SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &m_cci); // 设置某个控制台屏幕缓冲区的光标属性,如大小,是否可见
 COORD loc;
 loc.X = Wide * 2; // Y坐标的缓冲区是X的2倍,在控制台属性里能体现出来
 loc.Y = High;
 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), m_wArr); // 设置某个控制台屏幕缓冲区中的字符的颜色和背景色
 SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), loc); // 设置光标位置
 printf("%s",m_pszChar);
 }
 
 
 /************************************************************************
 * 该函数作用:初始化地图边界
 * 参数:
 * void
 * 返回值:
 * void
 /************************************************************************/
 void InitMap()
 {
 memset(g_Map, 0, sizeof(g_Map)); //将数组清空
 
 for (int Y =0; Y 40;Y++)
 {
 for (int X =0; X  30;X++)
 {
 if ((0 ==Y)||(39==Y)||(0 ==X)||(29 ==X))
 {
 g_Map[Y][X] =WALL;
 }
 }
 }
 }
 
 /************************************************************************
 * 该函数作用:在屏幕上打印地图边框
 * 参数:
 * void
 * 返回值:
 * void
 /************************************************************************/
 void DrawMap()
 {
 for (int Y = 0;Y  40; Y++)
 {
 for (int X = 0;X  30; X++)
 {
 if (1 == g_Map[Y][X]) //根据数组中的值打印相应图案
 {
 WriteChar(X, Y, "■", F_WHITE);
 }
 else
 {
 WriteChar(X, Y, " ", F_H_WHITE);
 }
 }
 printf("n");
 }
 
 //打印右侧信息
 WriteChar(32, 2, "分数:", F_YELLOW);
 WriteChar(32, 4, "等级:", F_YELLOW);
 char buffer[6] = {};
 g_Score = 0;
 sprintf_s(buffer, sizeof(buffer), "%d", g_Score); //将int型数据转换成char类型
 WriteChar(36, 2, buffer, F_H_RED);
 
 char buffer1[6] = {};
 g_Grade = 0;
 sprintf_s(buffer1, sizeof(buffer1), "%d", g_Grade);
 WriteChar(36, 4, buffer1,F_H_RED);
 }
 
 /************************************************************************
 * 该函数作用:欢迎界面
 * 参数:
 * void
 * 返回值:
 * void
 /************************************************************************/
 void DrawPicture(void)
 {
 //COORD 结构体保存图型开始位置(X,Y)
 COORD PosDown ={ 9, 0 }; //下
 COORD PosRight ={ 39, 11 }; //左
 COORD PosLeft ={ 0,29 }; //右
 COORD PosUp ={ 29, 41 }; //上
 
 while (true)
 {
 Sleep(100); //休眠库函数(包含stdlib.h)
 //↓
 if (PosDown.Y  PosLeft.Y)
 {
 WriteChar(PosDown.X,PosDown.Y, "┃┃", F_RED);
 PosDown.Y++;
 }
 //←
 if (PosRight.X  PosDown.X+1)
 {
 WriteChar(PosRight.X,PosRight.Y, "━", F_RED);
 WriteChar(PosRight.X,PosRight.Y + 1, "━", F_RED);
 PosRight.X--;
 }
 //→
 if (PosLeft.X  PosUp.X)
 {
 WriteChar(PosLeft.X,PosLeft.Y, "━", F_RED);
 WriteChar(PosLeft.X,PosLeft.Y + 1, "━", F_RED);
 PosLeft.X++;
 }
 //↑
 if (PosUp.Y  PosRight.Y+1)
 {
 WriteChar(PosUp.X,PosUp.Y, "┃┃", F_RED);
 PosUp.Y--;
 }
 else
 break;
 }
 Sleep(1000); //消屏库函数
 system("cls");
 WriteChar(3, 11, "■■■■■ ■■■■■ ■■■■■ ■■■■ ■■■■■ ■■■■", F_RED);
 WriteChar(3, 12, "■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■", F_RED);
 WriteChar(3, 13, " ■ ■ ■ ■ ■ ■ ■ ■ ", F_RED);
 WriteChar(3, 14, " ■ ■■■ ■ ■■■ ■ ■■ ", F_RED);
 WriteChar(3, 15, " ■ ■ ■ ■ ■ ■ ■ ■ ", F_RED);
 WriteChar(3, 16, " ■ ■ ■ ■ ■ ■ ■", F_RED);
 WriteChar(3, 17, " ■ ■ ■ ■ ■ ■ ■ ■ ■", F_RED);
 WriteChar(3, 18, " ■■■ ■■■■■ ■■■ ■■■ ■■■■■■■ ■■■■", F_RED);
 WriteChar(25, 20, "--by--QQ群:420297600", F_H_RED);
 
 //_kbhit() 判断是否有键盘输入,有则返回1,否则返回0 库函数(conio.h)
 //_getch() 接收从键盘上输入的一个字符,不需要回车 0x0d:表示回车键 库函数(conio.h)
 while (!(_kbhit() && _getch() == 0x0d))
 {
 WriteChar(26, 25, "PRESS ENTER TO START", F_H_RED);
 Sleep(300);
 WriteChar(26, 25, " ", F_H_WHITE);
 Sleep(300);
 }
 system("cls");
 }
 
 /************************************************************************
 * 该函数作用:设置控制台窗口大中及缓冲区大小
 * 参数:
 * void
 * 返回值:
 * void
 /************************************************************************/
 void LniSehomepage()
 {
 //具体参考“控制台编程”
 SetConsoleTitle(L"Tetris"); //设置控制台标题
 HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); //输出句柄 (STD_INPUT_HANDLE)为输入宏
 COORD BufferSize ={ 80, 42 }; //初始化窗口缓冲区大小
 SMALL_RECT srctWindow ={ 0, 0, 80 - 1, 42- 1 }; //初始化窗口大小
 SetConsoleScreenBufferSize(hStdOut,BufferSize); //设置窗口的缓冲区
 SetConsoleWindowInfo(hStdOut, true, &srctWindow); //创建窗口大小
 DrawPicture();
 }
 
 /************************************************************************
 * 该函数作用:产生随机数,随机第几类方块,该方块当前方向,随机方块颜色
 * 参数:
 * pRANDOM 随机数结构体指针 因为要将结果返回
 * 返回值:
 * void
 /************************************************************************/
 void Random(pRANDOM pRand)
 {
 //库函数 (time.h)
 srand((unsigned)time(NULL)); //随机数 产生一个随机种子
 pRand-Shape = rand() % 5; //方块形状
 pRand-Dir = rand() % 3; //方块方向
 pRand-Colour = rand() % 11; //方块颜色
 while (true)
 {
 srand((unsigned)time(NULL)); //随机数
 
 //因为第一种型状的图案只有一个方向
 if (0 ==pRand-Shape) //■■
 { //■■
 pRand-Dir =0;
 break;
 }
 if (1 ==pRand-Shape&&pRand-Dir1) //同上
 {
 pRand-Dir =rand() % 4; //方块方向
 }
 else
 break;
 }
 
 //随机分配方块颜色
 switch (pRand-Colour)
 {
 case 0:
 case 1:
 pRand-Colour =F_BLUE;
 break;
 case 2:
 pRand-Colour = F_H_BLUE;
 break;
 case 3:
 pRand-Colour = F_GREEN;
 break;
 case 4:
 pRand-Colour = F_H_GREEN;
 break;
 case 5:
 pRand-Colour = F_RED;
 break;
 case 6:
 pRand-Colour = F_H_RED;
 break;
 case 7:
 pRand-Colour = F_YELLOW;
 break;
 case 8:
 pRand-Colour = F_H_YELLOW;
 break;
 case 9:
 pRand-Colour = F_PURPLE;
 break;
 case 10:
 pRand-Colour = F_H_PURPLE;
 break;
 case 11:
 pRand-Colour = F_CYAN;
 break;
 }
 }
 
 
 /************************************************************************
 * 该函数作用:擦除当前方块 在大数组中及屏幕上
 * 参数:
 * SHAPEINFO 方块数结构体
 * 返回值:
 * void
 /************************************************************************/
 void ClcShanp(SHAPEINFO Shape)
 {
 //以右下角为中心点 依次从左上角开始循环遍历16个点
 for (int Y = Shape.pos.Y - 3; Y = Shape.pos.Y;Y++)
 {
 for (int X =Shape.pos.X - 3; X = Shape.pos.X;X++)
 {
 //定义的方块型状结构体,根据该数组对应的值擦除大数组中的值及屏幕上的字符
 if (g_aCubeShape[Shape.NewShape][Shape.Dir][Y - Shape.pos.Y+ 3][X - Shape.pos.X + 3])
 {
 g_Map[Y][X] = 0;
 WriteChar(X, Y, " ", F_H_WHITE);
 }
 }
 }
 }
 
 
 /************************************************************************
 * 该函数作用:画当前方块 在大数组中及屏幕上
 * 参数:
 * SHAPEINFO 方块数结构体
 * 返回值:
 * void
 /************************************************************************/
 void DrawShanp(SHAPEINFO Shape)
 {
 //该函数同擦除函数 和擦除函数几乎没差别 唯一差别在传入的坐标值的不一样
 //擦除是擦除老坐标,画则画新坐标
 for (int Y = Shape.pos.Y - 3; Y = Shape.pos.Y;Y++)
 {
 for (int X = Shape.pos.X - 3; X = Shape.pos.X;X++)
 {
 if (g_aCubeShape[Shape.NewShape][Shape.Dir][Y - Shape.pos.Y+ 3][X - Shape.pos.X + 3])
 {
 g_Map[Y][X] = SHAPE;
 WriteChar(X, Y, "■", Shape.Colour);
 }
 }
 }
 //有可能方块图案出生时将边框覆盖掉。
 for (int X =12;X = 15;X++)
 {
 g_Map[0][X] = WALL;
 WriteChar(X, 0, "■", F_WHITE);
 }
 }
 
 /************************************************************************
 * 该函数作用:将所有已经落下的不能移动的方块都在数组中赋值为墙,主要方便我判断碰撞
 * 参数:
 * SHAPEINFO 方块数结构体
 * 返回值:
 * void
 /************************************************************************/
 void DrawShanpBuff(SHAPEINFO Shape)
 {
 for (int Y = Shape.pos.Y - 3; Y = Shape.pos.Y;Y++)
 {
 for (int X = Shape.pos.X - 3; X = Shape.pos.X;X++)
 {
 if (g_aCubeShape[Shape.NewShape][Shape.Dir][Y - Shape.pos.Y+ 3][X - Shape.pos.X + 3])
 {
 WriteChar(X, Y, "■", F_H_GREEN);
 g_Map[Y][X] = WALL; //方块在数组中赋值为墙
 }
 }
 }
 }
 
 /************************************************************************
 * 该函数作用:判断方块是否能移动
 * 参数:
 * SHAPEINFO 方块数结构体
 * 返回值:
 * BOOL 能移动返回true,否则返回false
 /************************************************************************/
 BOOL IsMove(SHAPEINFO Shape)
 {
 for (int Y = Shape.pos.Y; Y = Shape.pos.Y - 3; Y--)
 {
 for (int X =Shape.pos.X - 3; X = Shape.pos.X;X++)
 {
 //1.数组当前位置有值
 //2.方块型状数组对应的点有值
 if (1 == g_Map[Y][X] &&g_aCubeShape[Shape.NewShape][Shape.Dir][Y- Shape.pos.Y + 3][X - Shape.pos.X + 3])
 {
 return FALSE;
 }
 }
 }
 return TRUE;
 }
 
 
 /************************************************************************
 * 该函数作用:当前行被填满时,消除当前行,并且将该行以上的图案向下移动一行
 * 参数:
 * int PosY 当前Y坐标
 * 返回值:
 * void
 /************************************************************************/
 void ClsShaep(int PosY)
 {
 //从最后一行开始 Y=38
 //二维数组第一个下标表示行,第二个下标表示列。
 //此工程中 行都以'Y'表示,列以'X'表示
 for (int X = 1;X  29; X++)
 {
 WriteChar(X, PosY, "■", F_RED); //该行以满,用红色表示一下
 }
 Sleep(50);
 for (int X = 1;X 29 ;X++)
 {
 g_Map[PosY][X] = 0;
 WriteChar(X, PosY, " ", F_H_WHITE); //消空该行
 }
 
 //将以满的行以上的图案向下移动一格
 for (int X = 1;X  29; X++)
 {
 for (int Y = PosY - 1; Y  3; Y--)
 {
 if (!g_Map[Y][X])
 {
 break;
 }
 for (int J = Y +1; J = 38; J++)
 {
 if (!g_Map[J][X])
 {
 g_Map[Y][X] = 0;
 WriteChar(X, Y, " ", F_H_WHITE);
 g_Map[J][X] = WALL;
 WriteChar(X, J, "■", F_H_GREEN);
 continue;
 }
 break;
 }
 }
 }
 
 //计分及等级
 g_Score += 50;
 switch (g_Score / 100)
 {
 case 3:
 g_Grade++;
 break;
 case 8:
 g_Grade++;
 break;
 case 15:
 g_Grade++;
 break;
 case 24:
 g_Grade++;
 break;
 case 35:
 g_Grade++;
 break;
 case 50:
 g_Grade++;
 break;
 case 70:
 g_Grade++;
 break;
 case 95:
 g_Grade++;
 break;
 case 175:
 g_Grade++;
 break;
 case 230:
 g_Grade++;
 break;
 }
 }
 
 
 /************************************************************************
 * 该函数作用:判断该行是否填满
 * 参数:
 * void
 * 返回值:
 * BOOL
 /************************************************************************/
 BOOL CountScore()
 {
 for (int Y = 38;Y  3;Y--)
 {
 sig:
 int iCount = 0;
 int X = 1;
 for (; X  28;X++)
 {
 for (int J = 1;J  28;J++)
 {
 if (1 == g_Map[4][J])
 {
 return FALSE;
 }
 }
 if (!g_Map[Y][X])
 {
 break;
 }
 iCount++;
 }
 //当iCount为什27时,则表示填满
 if (iCount == 27)
 {
 ClsShaep(Y);
 Y = 38;
 goto sig;
 }
 }
 
 //显示到右侧
 char buffer[6] = {};
 sprintf_s(buffer, sizeof(buffer), "%d", g_Score);
 WriteChar(36, 2, buffer, F_H_RED);
 
 char buffer1[6] = {};
 sprintf_s(buffer1, sizeof(buffer1), "%d", g_Grade);
 WriteChar(36, 4, buffer1,F_H_RED);
 return TRUE;
 }
 
 /************************************************************************
 * 该函数作用:相当于画,擦,判段方块都在这里面
 * 参数:
 * pSHAPEINFO Shape 当前方块的信息 以向下移动,或方向有变化
 * pSHAPEINFO OldShape 上一次方块的信息
 * 返回值:
 * BOOL 能移动返回true,否则返回false
 /************************************************************************/
 BOOL CollideEngine(pSHAPEINFO Shape, pSHAPEINFO OldShape)
 {
 if (IsMove(*Shape)) //判断是否能移动
 {
 ClcShanp(*OldShape); //擦除之前的方块
 DrawShanp(*Shape); //画新的方块
 *OldShape =*Shape; //更新信息
 return TRUE;
 }
 
 //当前如果是往左右移动刚好也不能移动时,应该让其继续向下移动
 //将坐标 Y++ 在判断是否能移动
 SHAPEINFO obj =*OldShape;
 obj.pos.Y++;
 if (IsMove(obj))
 {
 *Shape =*OldShape;
 return TRUE;
 }
 //如果上面两种情况都为假时,则将该标志标为false
 //以便生成新的图案
 Shape-IsObj =0;
 return FALSE;
 }
 
 /************************************************************************
 * 该函数作用:在地图右侧显示将要出现的图案
 * 参数:
 * SHAPEINFO Shape 当前方块的信息
 * 返回值:
 * void
 /************************************************************************/
 void DrawOffsideInfo(SHAPEINFO Shape)
 {
 COORD pos ={ 36, 15 };
 for (int Y=pos.Y; Y =pos.Y - 3; Y--)
 {
 for (int X=pos.X; X =pos.X - 3; X--)
 {
 WriteChar(X, Y, " ", F_H_WHITE);
 if (g_aCubeShape[Shape.NewShape][Shape.Dir][pos.Y - Y][pos.X-X])
 {
 WriteChar(X, Y, "■", Shape.Colour);
 }
 }
 }
 }
 楼主 2015-06-20 18:24 回复 
 
 
   
             
                  
                  
 
 
 
     
	 
  
	Copyright © 2010~2015 直线网 版权所有,All Rights Reserved.沪ICP备10039589号
	
	意见反馈 | 
	关于直线 | 
	版权声明 | 
	会员须知