俄罗斯方块实现基本功能项目

        今天学习一下俄罗斯方块项目的基本功能,首先对俄罗斯方块程序进行用例分析。

       由用例分析,首先对下落的功能具体分析,并画出对应的逻辑图,俄罗斯方块分为下落的方块与下落停下的方块,这里我们将两者分为落块与实块;落块下落时,如果不被其他方块阻挡并且不出界,会一直下落直到结束;如果下落时被其他方块阻挡或者出界时,就会变成实块;实块包括合并、消除行、计算得分功能,最后判断是否结束,若结束则game over,若未结束则出新的落块。

功能逻辑图如下所示:

        然后对左移动进行具体功能分析,判断左是否出界,若出界游戏结束,若不出界则判断是否碰到左侧实块,若碰到则结束,若未碰到继续左移动,具体如图所示:

 右移动判断跟左移动一样,这里就用再画了。

      接下来我们进行编程,首先打开V-S软件,建立一个RussianBlock的空项目,在头文件建立6个.h文件,分别为all.h文件用于存放全部的头文件、datatype.h文件用于进行类型的变换、gloablvar.h文件用于存放全局变量、luokuai.h文件用于描述落块的基本功能、shikuai.h用于描述实块的基本功能、game.h用于描述游戏界面得分等级等功能。

       all.h文件存放一些头文件,主要为了下面程序执行时更方便,只用调用all.h文件即可,不用调用每一个头文件。

       datatype.h文件宏定义TRUE为1FALSE为0,将int类型用_BOOL_类型替换,枚举一下方块的形状,用TYPE替换。

        gloablvar.h文件定义一些程序要用到的全局变量。

 luokuai.h文件用于描述落块的基本功能。

shikuai.h用于描述实块的基本功能。

game.h用于描述游戏界面得分等级等功能。

     下面我首先具体编写一下落块的功能,在luokuai.h文件中鼠标放在函数名上点击快速创建luokuai.cpp文件,luokuai.cpp文件头要调用“all.h”文件。

       第一步:编写显示落块函数,在showLuoKuai函数中利用双循环遍历落块,若落块不为0则显示落块,代码如下:

/*显示落块*/
void showLuoKuai()
{
	for (int h = 0; h < 20; h++)
	{
		for (int l = 0; l < 10; l++)
		{
			if (luoKuai[h][l] != 0)
			{
				drawImage(30 + l * 30, 5 + h * 30, &imgfk[luoKuai[h][l]]);
			}
		}
	}
}

       第二步:编写出新的落块函数功能,在createNewLuoKuai函数中编写方块的种类、颜色都是随机的,然后用switch选择函数进行赋色,这里利用二维数组让同一类型的方块颜色相同,具体实现代码如下所示:

void createNewLuoKuai()
{
	//1方块种类:随机
	TYPE type = (TYPE)(rand() % 5);
	//2方块颜色:随机
	color = rand() % 10 + 1;//随机颜色
	switch (type)
	{
	case Z:
		luoKuai[0][3] = luoKuai[0][4] = color;
		luoKuai[1][4] = luoKuai[1][5] = color;
		break;
	case T:
		luoKuai[0][3] = luoKuai[0][4] = luoKuai[0][5] = color;
		luoKuai[1][4] = color;
	    break;
	case TIAN:
		luoKuai[0][3] = luoKuai[0][4] = color;
		luoKuai[1][3] = luoKuai[1][4] = color;
		break;
	case L:
		luoKuai[0][3] = color;
		luoKuai[1][3] = color;
		luoKuai[2][3] = luoKuai[2][4] = color;
		break;
	case ONE:
		luoKuai[0][3] = color;
		luoKuai[1][3] = color;
		luoKuai[2][3] = color;
		luoKuai[3][3] = color;
		break;
	}
}

       第三步:编写向下移动函数功能,在downMove函数中编写向下移动函数,本质就是在行和列的双循环内将数组上面一行的数据复制给下面一行,然后把上面一行的数据清零,代码如下所示:

 

/*下移动*/
void downMove()
{
	for (int h=18 ;h>=0 ;h--)
	{
		for (int k=0 ;k<10 ;k++)
		{
			luoKuai[h + 1][k] = luoKuai[h][k];
			luoKuai[h][k] = 0;
		}
	}
}

      第四步:编写下不出界函数,在downNotOut函数中利用for循环遍历数组的10列,判断第20行的每一列是否为0,若为不为0则返回FALSE,若为0则返回TRUE;代码如下所示:

/*下不出界 */
_BOOL_ downNotOut()
{
	for (int k=0 ;k<10 ;k++)
	{
		if (luoKuai[19][k]!=0)
		{
			return FALSE;
		}
	}
	return TRUE;
}

       第五步:编写下不阻挡函数,在downNotStop函数中利用循环套循环遍历落块与实块每一行每一列是否相同,若相同则返回FALSE,若不同则返回TRUE,代码如下所示:

/*下不阻挡 */
_BOOL_ downNotStop()
{
	for (int h=18 ;h>=0 ;h--)
	{
		for (int k=0 ;k<10 ;k++)
		{
			if (luoKuai[h][k] && shiKuai[h+1][k])
			{
				return FALSE;
			}
		}
	}
	return TRUE;
}

      第六步:编写左移动函数,在leftMove函数中使用双循环遍历落块的行与列,让落块同行的右一列复制给左一列,并把右列清零,代码如下:

/*左移动*/
void leftMove()
{
	for (int k=1 ;k<10 ;k++)
	{
		for (int h=0 ;h<20 ;h++)
		{
			luoKuai[h][k - 1] = luoKuai[h][k];
			luoKuai[h][k] = 0;
		}
	}
}

       第七步:编写左不出界函数,在leftNotOut函数中利用循环遍历每一行的第0列是否存在,若存在则返回FALSE,若不存在则返回TRUE,代码如下:

/*左不出界 */
_BOOL_ leftNotOut()
{
	for (int h=0 ;h<20 ;h++)
	{
		if (luoKuai[h][0])
		{
			return FALSE;
		}
	}
	return TRUE;
}

       第八步:编写左不阻挡函数,在leftNotStop函数中利用双循环遍历每行与列,判断落块所在的行和列与实块所在的行和左一列是否同时存在,若存在则返回FALSE,不同时存在返回TRUE,代码如下:

/*左不阻挡 */
_BOOL_ leftNotStop()
{
	for (int k = 1; k < 10; k++)
	{
		for (int h = 0; h < 20; h++)
		{
			if (luoKuai[h][k] && shiKuai[h][k-1])
			{
				return FALSE;
			}
		}
	}
	return TRUE;
}

       第九步:分别编写右移动、右不出界、右不阻挡函数,方法与左侧一样,这里不具体分析,代码如下:

/*右不出界 */
_BOOL_ rightNotOut()
{
	for (int h = 0; h < 20; h++)
	{
		if (luoKuai[h][9])
		{
			return FALSE;
		}
	}
	return TRUE;
}

/*右不阻挡 */
_BOOL_ rightNotStop()
{
	for (int k = 8; k >= 0; k--)
	{
		for (int h = 0; h < 20; h++)
		{
			if (luoKuai[h][k] && shiKuai[h][k+1])
			{
				return FALSE;
			}
		}
	}
	return TRUE;
}

/*右移动*/
void rightMove()
{
	for (int k = 8; k >=0; k--)
	{
		for (int h = 0; h < 20; h++)
		{
			luoKuai[h][k + 1] = luoKuai[h][k];
			luoKuai[h][k] = 0;
		}
	}
}

       其次编写一下实块的功能,在shikuai.h文件中鼠标放在函数名上点击快速创建shikuai.cpp文件,shikuai.cpp文件头要调用“all.h”文件。

        第一步:编写显示实块函数,代码如下:

/*显示实块*/
void showShiKuai()
{
	for (int h = 0; h < 20; h++)
	{
		for (int l = 0; l < 10; l++)
		{
			if (shiKuai[h][l] != 0)
			{
				drawImage(30 + l * 30, 5 + h * 30, &imgfk[shiKuai[h][l]]);
			}
		}
	}
}

       第二步:编写合并函数,在merge函数中循环遍历每一行与列,如果落块存在,就把落块复制给实块,然后清空落块,代码如下:

/*合并*/
void merge()
{
	for (int h=0 ;h<20 ;h++)
	{
		for (int k = 0; k < 10; k++)
		{
			if (luoKuai[h][k])
			{
				shiKuai[h][k] = luoKuai[h][k];
				luoKuai[h][k] = 0;
			}
		}
	}
}

       第三步:编写清空行函数,在cleanLines函数中首先遍历所有行,其次看哪行可以清除,若能清除然后清除,最后记录行数,代码如下:

/* 清除行
返回:行数
*/
int cleanLines()
{
	//1 遍历所有行
	int count = 0;//记录消除的行数
	for (int h=1; h<20; h++)
	{
		//2 看哪行能消除
		_BOOL_ neng = TRUE;
		for (int k = 0; k < 10; k++)
		{
			if (shiKuai[h][k]==0)
			{
				neng = FALSE; //推翻假设
				break;
			}
		}
		if (neng)
		{
			//3 消除
			for (int xh = h - 1; xh >= 0; xh--)
			{
				for (int xk = 0; xk < 10; xk++)
				{
					shiKuai[xh + 1][xk] = shiKuai[xh][xk];
					shiKuai[xh][xk] = 0;
				}
			}
			//4 记录行数
			count++;
		}
	}
	return count;
}

        第四步:编写计算得分函数, 在setScore函数中使用switch函数进行选择,1行得20分,2行得50分,3行得100分,4行得200分,代码如下:

/*
根据消除的行数  计算得分
*/
void setScore(int lines)
{
	switch (lines)
	{
	case 1:
		score += 20;
		break;
	case 2:
		score += 50;
		break;
	case 3:
		score += 100;
		break;
	case 4:
		score += 200;
		break;
	}
}

        第五步:编写能否结束函数,在enabledOver函数中在0行3~6列这个范围是否有方块,若存在能结束,不存在继续游戏,代码如下:


/*能否结束*/
_BOOL_ enabledOver()
{
	for (int k=3 ;k<7 ;k++)
	{
		if (shiKuai[0][k])
		{
			return TRUE;
		}
	}
	return FALSE;
}

       然后编写游戏界面函数,在game.h文件中鼠标放在函数名上点击快速创建game.cpp文件,game.cpp文件头要调用“all.h”文件。

        第一步:编写游戏结束函数,在gameover函数中编写stop=1代表游戏结束,代码如下:

void gameover()
{
	stop = 1;
}

        第二步:编写背景初始化函数。

/*初始化背景*/
void initBg()
{
	loadimage(&imgbg, L".\\images\\2\\bg-1.png");
}

        第三步:编写显示背景函数。

/*显示背景*/
void showBg()
{
	putimage(0, 0, &imgbg);
}

       第四步:编写加载方块图函数。

/*加载方块图*/
void loadFKImage()
{
	for (int c = 0; c < 11; c++)
	{
		_stprintf(imgPath, L".\\images\\2\\%d.png", c);
		loadimage(&imgfk[c], imgPath);
	}
}

       第五步:编写显示得分函数。

void showScore()
{
	settextstyle(18, 0, _T("黑体"));
	settextcolor(0xffffff);
	TCHAR str[100];
	_stprintf(str, L"%d分", score);
    outtextxy(390, 228, str);
}

        第六步:编写显示等级函数。

void showLevel()
{
	settextstyle(18, 0, _T("黑体"));
	TCHAR str[100];
	
	_stprintf(str, L"Level %d", 1);
	outtextxy(390, 294, str);
}

       最后在主函数ELSFKGame.cpp文件中调用上述函数功能就可以实现俄罗斯方块基本功能。

在头调用“all.h”文件。

       第一步:游戏初始化函数,包括对背景初始化,加载方块图,创建新的落块函数的调用,代码如下:

void gameInit()
{
	initBg(); /*初始化背景*/
	loadFKImage();/*加载方块图*/
	createNewLuoKuai();
}

      第二步:绘图处理函数,包括对显示背景,显示落块,显示实块,显示得分和等级函数的调用,代码如下:

void gamePaint()
{
	showBg();/*显示背景*/

	//---------显示下落方块-------------//
	showLuoKuai();
	//---------显示落实方块-------------//
	showShiKuai();
	//---------显示  得分 等级-------------//
	showScore();
	showLevel();
}

      第三步:定时处理函数,代码如下:

void gameInterval()
{
	if (downNotOut() && downNotStop())
	{
		downMove();
	}
	else
	{
		merge();
		setScore(cleanLines());
		if (enabledOver())
		{
			gameover();
		}
		else
		{
			createNewLuoKuai();
		}
	}
}

      第四步:键盘处理函数,代码如下:

void gameKeypress(int key)
{
	switch (key)
	{
	case VK_LEFT:
		if (leftNotOut() && leftNotStop())
		{
			leftMove();
		}
		break;
	case VK_RIGHT:
		if (rightNotOut() && rightNotStop())
		{
			rightMove();
		}
		break;
	case VK_UP:
		 
		break;
	case VK_DOWN:
		if (downNotOut() && downNotStop())
		{
			downMove();
		}
		break;
	}
}

以上就是俄罗斯方块的基本功能实现。

/* *游戏说明:此为我边学边做的,但有很多的BUG,参照了我从网上下载的游戏方块设计 * 一、游戏的BUG * 1、提示分数那地方,玩过游戏后,长了分数后,再玩时,后面的数据没清掉 * 2、重级BUG:当在游戏过程中,切换了一个旁边的后,再切换回来后, * 刚才的方块不显了,而且游戏区的数据也不见了。 * 3、我在刚开始做时,没有要窗口上的关闭,现在想要,但不知道怎么加。 * 4、如果用鼠标点了菜单后,再回到游戏区,数据方块又不见了。 * * 二、此游戏没有版权,可以乱改,反正我也是在学习,谢谢那些无私的网友们,不过 * 请你们下次提交上来的源程序有个说明好不好,看得我头都大了,流程图也没得, * 设计说明也没有,完全看源代码,很费力的!谢谢对新人的支持。 * * 三、如果那位高手愿意,请收我为徒弟吧,我学过c/c++、数据结构、编译原理、操作系统等( * 计算机专业的),但对于VC这个大东西来说,,好像一点用也没有,现在在边学边做,门不好入呀! * * 四、请高手们帮帮我,请给分析一下问题在哪,谢谢,我对VC还不是很清楚,在文件目录下 * 有设计时的流程图。设计说明我没有写,我是针对每一个流程图模块来设计和编码的。 * * 五、在游戏中,我加了很多注释,以方便理解,主要的代码都在CChileView.h、CChileView.CPP中 * 我想的是,如果新人也想看看的话,可能理解起来快点。不过有点乱,编码中有些冗余。没来 * 得及改。如果你改好了,请给我一份,我想学学。谢谢! * *================================================================================================ * *编译环境: * 1、操作系统 :WindowsXP SP2 * 2、编译器 :Visual C++ 8.0 * *包含文件:所有源文件都在此。 * * *编译参考:此目录下有一个文件名为:Russia.sln的文件,用Visual C++ 8.0 打开,直接就可编译 * 此游戏是我编译通过后,才压缩的。如果编译不了,请联系我,下面有我的QQ和email。 * * *其它事宜:如果还有什么问题我没有提到的,请联系我,愿向你学习。 * *================================================================================================ * *Version :BUG Edtion * *Aauthor :lin_liu60 * *E-mail :lin_liu60@163.com * *QQ :994165 (网名:刘羽峰) * *Date :2006/9/27 * */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

努力编程的晓宇

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

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

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

打赏作者

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

抵扣说明:

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

余额充值