MFC俄罗斯方块

<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类的成员函数与变量

游戏类的成员函数

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();//开始游戏

游戏类的成员变量

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

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

//绘制游戏的背景,正在下落的,和已经堆积的
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,变为为第一行,中间列

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执行

 <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;
 
 

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

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;

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;

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行。

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

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

//·½¿éµÄÒƶ¯º¯Êý
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

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

//ÓÎÏ·½áÊø
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

源程序下载

点击打开链接

  • 6
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

四夕立羽

你的鼓励将是我创作的最大动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值