我罗斯方块最终篇

我罗斯方块最终篇

这个作业属于哪个课程 2020面向对象程序设计
这个作业要求在哪里 查看详情
这个作业的目标 实现并展示我罗斯方块
作业正文 作业链接
作业要求 代码的 git 仓库链接、 运行截图/运行视频、 代码要点、 收获与心得、依然存在的问题
项目地址 仓库一
仓库二
小组成员 031902407林建斌
031902408林蒋辉

一、运行效果截图

二、代码要点

1. 渲染类

  • 负责静态的界面
class Drawing {
public:
	void drawMap();//游戏运行的静态边框
	void welcome();//欢迎界面
	void overScreen(int s1, int s2);//结束界面
};

2. 方块类

  • 方块基类,将以它为基类派生七个不同方块的基本形状,其中change()声明为虚函数,以便派生类调用
class Block
{
public:
	int x0, y0;//玩家地图基点
	fangge f[4];//方块四个方格坐标
	int shape;//方块的形状
	int state;//之前是想表示方块状态,后来发觉没啥用,改的话派生类得改很多
	void clearNextBlock(int wanjia);//显示下一个方块前,清除上一次显示的
	void drawNextBlock(int a,int wanjia);//在小地图画下一个方块
	virtual void change() {}//同类方块之间切换形状,声明为虚函数
	void down();//下降
	void moveLeft();//左移
	void moveRight();//右移
	bool checkLeft();//检查能否左移
	bool checkRight();//检查能否右移
	bool checkDown();//检查能否下降
	void show();//显示方块
	void hide();//消除方块
	bool checkOver();//检查游戏是否结束
	
};
  • 一字型方块,还有余下六种与之类似
class Block2 :public Block
{
public:
	Block2(int x0, int y0);//构造函数声明方块的四个点坐标,形状
	void change();//换形函数,通过改变坐标,实现换形
};
  • change()函数 ,发现180°的翻转只要坐标通过改变加减符号即可。
void Block2::change() {
	if (state == 1) {
		hide();
		switch (shape) {
		case 0:
		case 2:
			if (MapValue[f[0].x + 2][f[0].y - 1] != 0 || MapValue[f[2].x - 2][f[2].y + 1] || MapValue[f[3].x - 4][f[3].y + 2] != 0) break;
			f[0].x += 2; f[0].y -= 1;
			f[2].x -= 2; f[2].y += 1;
			f[3].x -= 4; f[3].y += 2;
			shape = (++shape) % 4;
			break;
		case 1:
		case 3:
			if (MapValue[f[0].x - 2][f[0].y + 1] != 0 || MapValue[f[2].x + 2][f[2].y - 1] || MapValue[f[3].x + 4][f[3].y - 2] != 0) break;
			f[0].x -= 2; f[0].y += 1;
			f[2].x += 2; f[2].y -= 1;
			f[3].x += 4; f[3].y -= 2;
			shape = (++shape) % 4;
			break;
		}
		show();
	}
}

3. 玩家类

+两个玩家的区别,双人游戏实现的基础

class Player1 :public Block
{
private:
	int n, m;//产生连个随机数
	Block* b;//作为基类指针,以便后面指向新产生的方块
	int Time;//双人游戏时,对时间的控制
public:
	int score;//记录得分
	Player1();//构造函数
	void readKey(Block *b);//键盘读入
	int checkFull();//检查是否满行,并消行
	void Run();//游戏运行,方块下落
	void newShow(int i);//消行或增加垃圾行后刷新画布
	void showScore();//分数变化时,刷新分数
	void addLine();//增加垃圾行
};
  • 消行函数
int Player1::checkFull()
{
	int count = 0;//计算消行数
	for (int i = MapHeight - 1; i > 3; i--) //从下往上读
	{
		int flag = 1;
		for (int j = x0 + 2; j < x0 + MapWidth-1; j += 2)//从左往右读
		{
			if (MapValue[j][i] == 0) {
				flag = 0; break;
			}
		}
		if (flag == 1)
		{
			for (int j = x0 + 2; j < x0 + MapWidth-1; j += 2) 
			{
				for (int k = i; k > 3; k--) {
					MapValue[j][k] = MapValue[j][k - 1];//将游戏地图值上移一行
				}
			}
			count++;
			newShow(i);
			i++;
		}
	}
	line2 = count;
	score += count * 100;
	showScore();
	return 0;
}
  • 增加垃圾行
void Player1::addLine()
{
	while (line1--) {//增加line1行
		for (int j = x0 + 2; j < x0 + MapWidth - 1; j += 2)//将游戏地图值往上移一行
		{
			for (int k = 4; k < MapHeight; k++) {
				MapValue[j][k] = MapValue[j][k + 1];
			}
		}
		for (int j = x0 + 2; j < x0 + MapWidth - 1; j += 2) {//随机增加一行
			int n = getRandRange(0, 1);
			setMapValue(j, MapHeight - 1, n);
		}
		newShow(MapHeight - 1);
	}
}
  • 运行函数
void Player1::Run()
{
	while (1)
	{
		//判断是否产生垃圾行
		if(line1!=0){
			addLine();
			line1 = 0;
		}
		if (Time > 150) { //标记时间,与双人有关
			Time = 0;
			//下落
			if (b->checkDown()) b->down();
			//不能下落
			else {
				//消行,并改变玩家二的line值,玩家二产生垃圾行
				checkFull();
				//准备下落新方块,并产生下一个方块
				m = n;
				n = getRandRange(1, 7);
				drawNextBlock(n, 1);
				switch (m)
				{
				case 1:b = new Block1(x0, y0); break;
				case 2:b = new Block2(x0, y0); break;
				case 3:b = new Block3(x0, y0); break;
				case 4:b = new Block4(x0, y0); break;
				case 5:b = new Block5(x0, y0); break;
				case 6:b = new Block6(x0, y0); break;
				case 7:b = new Block7(x0, y0); break;
				}
				//检查产生新方块时,是否已经到达上端
				if (!(b->checkOver())) {
					score = -1;
					GameState = 0;
				}
			}

		}
		//读入按键
		readKey(b);
		//值越小读入按键更流畅,速度也更快
		//通过Sleep和Time的使用,run1和run2交替执行,实现双人
		Sleep(0.00001);
		Time++;
		break;
	}
}

玩家二与玩家一基本相同

4. 游戏类

class Game
{
public:
	void RunGame();
};
  • 运行函数
void Game::RunGame()
{
	HideCursor();//隐藏光标
	Drawing Draw;
	Draw.welcome();
	system("cls");
	Draw.drawMap();
	Player1 player1;
	Player2 player2;
	//运行游戏
	while (GameState) {
		player1.Run();
		player2.Run();
	}
	system("cls");
	Draw.overScreen(player1.score, player2.score);
	system("pause>nul");
}

5. 其他

//结构体表示方块坐标x,y
struct fangge {
	int x, y;
};
//隐藏光标
void HideCursor();
//光标去到某处
void gotoXY(int x, int y);
//枚举将颜色与数字关联
enum Color{};
//设置颜色 
void setColor (enum Color color);
//获取min到max之间的随机数
int getRandRange(int min, int max);

三、仍然存在的问题

1. 代码较为冗长,规模比较大,有些代码在后面基本没有起作用,比较多余,类与类之间的逻辑关系、函数的归类,逻辑不够清晰,在完成代码后回顾发现一些代码能够精简优化,例如在实现玩家类时分别写了两个玩家的类来实现,但实际上两个玩家类要实现的功能大同小异,如果先写一个玩家的基类再用继承的方式实现可以大大精简代码的数量,没有很好的体现c++的优势,可以多加用所学的多态和继承进行完善。

2. 游戏界面设计不是十分美观,没有设置汉字的大小,方块下落时会一闪一闪的,游戏流畅度的进一步优化。

四、收获与心得

第一次实现了图形化的编程,打破了代码只能输出打印数字文字的固有印象,发掘了代码的趣味性,增加了对学习编程的兴趣。这也是第一次自己做出了一个游戏,从中收获的成就感和兴奋也很宝贵。增强了自行解决问题和查阅资料的能力,在最后运行游戏时出现了两个玩家不能同时进行的问题,虽然一开始不知道怎么解决,但是通过寻找网络上的资料和不断调试,进行学习,最终也实现了这个功能。第一次尝试到了团队合作完成一个项目的经历,虽然第一次配合不是很默契,分工有些不均,但是万事开头难嘛。后续希望能继续完善,可以增加单人模式,和增加模式选择,完善界面。

posted @ 2020-06-13 16:52  Linyib  阅读(244)  评论(2编辑  收藏  举报