前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MFC俄罗斯方块

MFC俄罗斯方块

作者头像
立羽
发布2023-08-24 12:54:37
1250
发布2023-08-24 12:54:37
举报
文章被收录于专栏:Unity3d程序开发Unity3d程序开发
代码语言:javascript
复制
<span style="font-family: 黑体; font-size: 16pt; background-color: rgb(255, 255, 255);">MFC俄罗斯方块设计报告</span>

第一章 项目描述

1.1功能描述

使用MFC设计一款俄罗斯方块。实现方块下落,方块移动,方块叠加,方块变形,消行等功能。

1.2所需技术

MFC双缓冲绘图,方块移动,下落,叠加,变形,消行处理。

第二章  总体设计

2.1运行流程

如附录图2-1俄罗斯方块运行流程图所示。

第三章  详细设计

3.1CTetrisGame类的成员函数与变量

游戏类的成员函数

代码语言:javascript
复制
bool gameOver();//游戏结束判断
	void rectLineDel();//满行进行消行处理
	bool rectChange(bool bufTmp[][4],CPoint &pot);//方块变形处理
	void rectMove(int iDirect);//方块移动
	bool hitJudge(bool bufTmp[][4],int iDirect,CPoint &pot);//方块碰撞判断,包含移动处理
	void willRectProduce();//下一个方块随机产生
	void fontDraw(CDC* pCDC);//绘制游戏界面的文字
	void willRectDraw(CDC *pCDC);//绘制将要出现的方块
	void mapDraw(CDC * pCDC);//绘制游戏的地图
	void gameStart();//开始游戏

游戏类的成员变量

代码语言:javascript
复制
bool m_bEndFlg;//游戏结束判断
	CPoint m_potNow;//当前掉下方块的左上点的位置
	int m_iScore;//分数
	bool m_bufMap[MAX_ROW][MAX_COL];//游戏的地图
	bool m_bufNow[MIN_ROW_ROL][MIN_ROW_ROL];//当前这在掉落的方块
	bool m_bufWill[MIN_ROW_ROL][MIN_ROW_ROL];//将要出现的方块

说明:后面所说的块是指4*4的二维数组,地图块是指整张游戏的背景。

3.2方块掉落,平移,变形过程绘制mapDraw

所有实现是通过绘制一个一个的方块实现的。

代码语言:javascript
复制
//绘制游戏的背景,正在下落的,和已经堆积的
void CTetrisGame::mapDraw(CDC *pCDC)
{
	int iRow = 0;
	int iCol = 0;

	CPen penMap;                          
	penMap.CreatePen(PS_SOLID,1,RGB(0,0,0));   //定义白色画笔绘制蛇的边框,第一个参数代表
	pCDC->SelectObject(&penMap);                
	
	for ( iRow = 4; iRow < MAX_ROW; iRow++)//初始化地图,全部置0
	{
		for( iCol = 0; iCol < MAX_COL; iCol++)
		{
			if (m_bufMap[iRow][iCol] == FALSE)
			{
				CBrush brushMap;//这里要特别注意,虽然两次是不同的颜色,但是要分别载入画刷
				brushMap.CreateSolidBrush(RGB(255,255,255)); 
				pCDC->SelectObject(&brushMap);   
				pCDC->Rectangle(CRect(iCol*RECT_SIZE,(iRow-4)*RECT_SIZE,(iCol+1)*RECT_SIZE,(iRow+1-4)*RECT_SIZE));
			}
			if(m_bufMap[iRow][iCol] == TRUE)
			{
				CBrush brushMap;
				brushMap.CreateSolidBrush(RGB(0,255,255)); //蓝色为背景
				pCDC->SelectObject(&brushMap);  
				pCDC->Rectangle(CRect(iCol*RECT_SIZE,(iRow-4)*RECT_SIZE,(iCol+1)*RECT_SIZE,(iRow+1-4)*RECT_SIZE));
			}
		}
	}
}

通过扫描地图二维数组m_bufMap的每个元素的值,根据真假分别填充不同颜色的画刷。实际上每个方块掉落,并不是绘制单独绘制每个方块,而是根据掉落方块的m_bufNow的真值,以及当前掉落块的最左上角的坐标m_potNow,实时赋值给m_bufMap,掉落块走过的区域,又会进行清零处理,直到m_bufNow不动了。全部的过程绘制都是在扫描m_bufMap进行绘制。

3.3随机方块产生willRectProduce

主要为几步:

1.把上一次产生m_bufWill赋值m_bufNow

2.上一次产生m_bufWill清零

3.对生成的随机数对7进行取余,得到将要生成的m_bufWill

4.初始化当前掉落快最左上角的坐标m_potNow,变为为第一行,中间列

代码语言:javascript
复制
m_potNow.x = 0;//ÖØж¨ÒåµôÂä·½¿éµÄµã
	m_potNow.y = MAX_COL/2;

说明:在初始化时要调用willRectProduce( )两次,因为初始化时还没有产生m_bufWill;在当前块落地后,还用调用willRectProduce( )一次,产生新的下落块。

3.4方块碰撞检测及坐标改变hitJudge

函数bool CTetrisGame::hitJudge(bool bufTmp[][4], int iDirect, CPoint &pot)主要做掉落块与地图块碰撞检测,当前有碰撞发生,返回真,当没碰撞发生,根据方向移动坐标m_potNow。主要为下面几步:

1.扫描下落块为真点,把地图块上相应点清零:实现下落块轨迹擦除

2.扫描下落块为真点,结合当前m_potNow,和移动方向,判断下落块与左右下边界以及地图块上真点是否重合:若重合,说明不可移动,跳转到HIT_TRUE执行

代码语言:javascript
复制
 <pre name="code" class="cpp">case DIR_DOWN://
					{
						if ((pot.x+iRow+1) >= MAX_ROW )//µ±µãµÄºá×ø±ê+1³¬¹ý×îÏÂÃæµÄʱºò
							goto HIT_TRUE;
						if ( m_bufMap[pot.x+iRow+1][pot.y+iCol] == TRUE)
							goto HIT_TRUE;
					}break;
				case DIR_LEFT:
					{
						if ((pot.y+iCol-1)<0)//˵Ã÷Åöµ½×ó±ß½çÁË
							goto HIT_TRUE;
						if ( m_bufMap[pot.x+iRow][pot.y+iCol-1] == TRUE)
							goto HIT_TRUE;
					}break;
				case DIR_RIGHT:
					{
						if ((pot.y+iCol+1)>=MAX_COL)//˵Ã÷Åöµ½Óұ߽çÁË
							goto HIT_TRUE;
						if ( m_bufMap[pot.x+iRow][pot.y+iCol+1] == TRUE)//ÕâÀï¶à´ÖÐÄ´òÒ»¸ö¼ÓºÅ£¬ÒªÐ¡ÐÄ£¡
							goto HIT_TRUE;
					}break;
代码语言:javascript
复制

3.若没有发生碰撞,结合方向,把坐标m_potNow做出相应的方向+1,再把方向块真点结合变化后的m_potNow赋值给地图块,就这样产生移动,视觉上看上就是下落块在移动,其实是在重绘地图块发生的“错觉”。

代码语言:javascript
复制
for ( iRow = 0; iRow < MIN_ROW_ROL; iRow++)//ûÓÐÅöײ·¢Éúʱ£¬°Ñµ±Ç°µÄ×ø±ê+1¸³Öµ¸øµØͼ
	{
		for ( iCol = 0; iCol < MIN_ROW_ROL; iCol++ )
		{
			if (bufTmp[iRow][iCol] == TRUE)
			{
				m_bufMap[pot.x+iRow][pot.y+iCol] = TRUE;
			}
		}
	}

4.若发生碰撞,执行HIT_TRUE:与上面的区别是m_potNow不会变化,其他一样。但是向下掉落的方向是一直被定时器调用的。所以即使不能左右平移还会往下掉。

3.5方块变形rectChange

当按下向上方向键时,调用rectChange函数。主要为下面几步:

1.初始化最终变化块bufAfter,全部置为FALSE,把下落块逆时针旋转90°赋值给中间块bufMid;

代码语言:javascript
复制
for ( iRow = 0; iRow < MIN_ROW_ROL; iRow++)
		{
			for ( iCol = 0; iCol < MIN_ROW_ROL; iCol++)
			{
				bufMid[iRow][iCol] = bufTmp[iCol][3-iRow];//°Ñµ±Ç°ÏÂÂänow·½¿éÄæʱÕëÐýת90¡ã¸øÖмäÔÝ´æÊý×é
				bufAfter[iRow][iCol] = FALSE;//ÐýתºóµÄÊý×éÏÈÈ«²¿ÖÃÁã 
			}
		}

2.找到bufMid为真的最小行和列,即块中有填充的点的最小行号和列号;

3.根据找到的bufMid最小行列对变换后的矩阵平移到左上角,赋值给bufAfter;

代码语言:javascript
复制
for ( iRow = iRowMin; iRow < MIN_ROW_ROL; iRow++)
		{
			for ( iCol = iColMin; iCol < MIN_ROW_ROL; iCol++)
			{
				bufAfter[iRow-iRowMin][iCol-iColMin] = bufMid[iRow][iCol];//°Ñ±ä»»ºóµÄmidÊý×éƽÒƵ½×óÉϽǣ¬³ÉΪafterÊý×é
			}
		}

4.bufAfter块真点结合m_potNow,与地图块进行比较,如果重合说明不能变形,返回FALSE;

5.若能够变形,把bufAfter赋值给m_bufNow,实现下落块的变形,返回真。

3.6消行处理rectLineDel

地图块上某一行全满了,要进行消行处理,即该行上一行的信息全部赋值给该行,依次类推,直到第0行。

代码语言:javascript
复制
for ( iRow = 0; iRow < MAX_ROW; iRow++)
	{
		bLineDelFlg = TRUE;
		for (iCol = 0; iCol < MAX_COL; iCol++)
		{
			if ( m_bufMap[iRow][iCol] == FALSE)
				bLineDelFlg = FALSE; //ÈôÒ»ÐÐÖÐÓÐûÂúµÄ£¬°Ñ±ê־λÖÃ0
		}

		if (bLineDelFlg == TRUE)//ÏûÐбê־Ϊ1
		{
			for ( int iRowTmp = iRow; iRowTmp > 0; iRowTmp--)
			{
				for (int iColTmp = 0; iColTmp < MAX_COL; iColTmp++)
				{
					m_bufMap[iRowTmp][iColTmp] = m_bufMap[iRowTmp-1][iColTmp];
				}
			}
			for ( int iFirst = 0; iFirst < MAX_COL; iFirst++)
			{
				m_bufMap[0][iFirst] = FALSE;
			}
			m_iScore++;
		}
	}

3.7方块移动rectMove

这里根据按键按下的方向,进行相应的处理。

代码语言:javascript
复制
//·½¿éµÄÒƶ¯º¯Êý
void CTetrisGame::rectMove(int iDirect)
{
	int iHitState = -1;

	switch (iDirect)
	{
	case DIR_UP:
		{
			hitJudge(m_bufNow,DIR_UP,m_potNow);
		}break;
	case DIR_DOWN:
		{
			iHitState = hitJudge(m_bufNow,DIR_DOWN,m_potNow);//µÃµ½ÅöײµÄ״̬£¬²¢ÇÒÈç¹ûûÓÐÅöײ£¬»á·¢ÉúÒƶ¯º¯Êý
			if ( iHitState == TRUE)//Èç¹ûµ×²¿ÊÇ·¢ÉúÅöײ
			{
				rectLineDel();//ÿ´Îµ×²¿ÂäµØºó½øÐÐÊÇ·ñÏû³ýÐеÄÅжÏ
				willRectProduce();//µ×²¿ÂäµØºóÒª½øÐвúÉúеķ½¿é£¬²¢ÇÒm_potNowµÄλÖÃÒª³õʼ»¯
				m_bEndFlg = gameOver();//ÿ´ÎÂäµØºóÒª½øÐÐÓÎÏ·ÊÇ·ñ½áÊøµÄÅжÏ
				break;
			}
			
		}break;
	case DIR_LEFT:
		{
			hitJudge(m_bufNow,DIR_LEFT,m_potNow);
		}break;
	case DIR_RIGHT:
		{
			hitJudge(m_bufNow,DIR_RIGHT,m_potNow);	
		}break;
	}
}

说明:下落方向移动时,如果落地,要进行消行判断处理,产生下一个m_bufWill,是否游戏结束判断处理。当按下向上方向键时,在碰撞函数hitJudge中会是否进行rectChange处理。

3.8游戏结束gameOver

当向下着地后进行是否游戏结束判断。

代码语言:javascript
复制
//ÓÎÏ·½áÊø
bool CTetrisGame::gameOver()
{
	int iRow = 0;
	int iCol = 0;

	for ( iCol = 0; iCol < MAX_COL; iCol++)
	{
		if ( m_bufMap[2][iCol] == TRUE)
			return TRUE;
	}
	return FALSE;
}

第四章  运行结果

附录

设计文档下载

http://download.csdn.net/detail/luoyikun/8223053

源程序下载

点击打开链接

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2014-12-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第一章 项目描述
    • 1.1功能描述
      • 1.2所需技术
      • 第二章  总体设计
        • 2.1运行流程
        • 第三章  详细设计
          • 3.1CTetrisGame类的成员函数与变量
            • 3.2方块掉落,平移,变形过程绘制mapDraw
              • 3.3随机方块产生willRectProduce
                • 3.4方块碰撞检测及坐标改变hitJudge
                  • 3.5方块变形rectChange
                    • 3.6消行处理rectLineDel
                      • 3.7方块移动rectMove
                        • 3.8游戏结束gameOver
                        • 第四章  运行结果
                        • 附录
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档