我罗斯方块最终篇

这个作业属于哪个课程 2020面向对象程序设计
这个作业要求在哪里 【我罗斯方块最终篇】(https://edu.cnblogs.com/campus/fzu/2020OOP/homework/10814)
这个作业的目标 获取运行截图,汇报代码要点报告收获与问题
github地址 https://github.com/xanxusEX/Tetris
小组成员 031902102 方文昱 031902142詹珊
游戏画面
游戏刚开始:

游戏对局:

消行得分:

游戏结束:

游戏视频:
鉴于条件不太允许,我们并未录制视频,不过在测试时我罗斯方块基本可以实现我们所想要的效果。
代码要点:
block类:

class Block {
public:
	int directions;
	matrix matrix_block[4];
	int color;
	Block() {}
	friend class Game;
	friend class Render;//随机得到方块
	friend void InitBlocks();//构造方块
	friend void print_block(Block* p, int x, int y, int cur_direction);
	friend void clear_block(Block* p, int x, int y, int cur_direction);

}block_arr[7];

其中,void InitBlocks()采用诸如 block_arr[0].matrix_block[0] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, };来形成方块。
以及采用如下代码来随机获取到不同形状的方块:

void rand_getblock(Block* p)//随机得到一种方块
{
	switch (rand() % 7) {
	case 0:*p = block_arr[0]; break;
	case 1:*p = block_arr[1]; break;
	case 2:*p = block_arr[2]; break;
	case 3:*p = block_arr[3]; break;
	case 4:*p = block_arr[4]; break;
	case 5:*p = block_arr[5]; break;
	case 6:*p = block_arr[6]; break;
	default: *p = block_arr[0];
	}
	rand_color(p->color);
}

Render类:

class Render
{
public:
	Player p;
	Render(int score0, int key) :p(score0, key) {}
	void score_add(int num, int x, int y)//控制分数增加 
	{
		HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
		p.score += num;
		gotoxy(hOut, x + 2 * W_SINGLE + 3, y + 5);
		cout << "SCORE :  " << p.score << endl;

	}
	void set_frame(int x0 = F_X0, int y0 = F_Y0);//设置边框  
	bool map_check(Block* p, char key, int cur_direction, int x, int y);//检查指令是否可行
	void map_update(Block* b, int cur_direction, int x, int y);//更新后台地图 
	friend class Game;
}win1(0, 1), win2(0, 0);

Render类是为了形成一个良好的游戏界面,其中设置边框部分在上一次作业中我们已经将其解决。现在着重在另外两个函数:

bool Render::map_check(Block* b, char key, int cur_direction, int x, int y)
{
	if (key == 72 || key == 'w') //up or w
	{
		for (int i = 0; i < 8; i++)
			for (int j = 0; j < 4; j++)
				if (b->matrix_block[(cur_direction + 1) % 4].matr[j][i / 2] == 1 && p.a[x + i][y + j] >= 1)
					return false;
		return true;
	}
	else if (key == 77 || key == 'd')//right or d
	{
		for (int i = 0; i < 8; i++)
			for (int j = 0; j < 4; j++)
				if (b->matrix_block[cur_direction % 4].matr[j][i / 2] == 1 && p.a[x + 2 + i][y + j] >= 1)
					return false;
		return true;
	}
	else if (key == 75 || key == 'a')//left or a
	{
		for (int i = 0; i < 8; i++)
			for (int j = 0; j < 4; j++)
				if (b->matrix_block[cur_direction % 4].matr[j][i / 2] == 1 && p.a[x - 2 + i][y + j] >= 1)
					return false;
		return true;
	}
	else//down or s
	{
		for (int i = 0; i < 8; i++)
			for (int j = 0; j < 4; j++)
				if (b->matrix_block[cur_direction % 4].matr[j][i / 2] == 1 && p.a[x + i][y + j + 1] >= 1)
					return false;
		return true;
	}
}
void Render::map_update(Block* b, int cur_direction, int x, int y)
{
	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
	for (int i = 0; i < 8; i++)
		for (int j = 0; j < 4; j++)
		{
			if (b->matrix_block[cur_direction % 4].matr[j][i / 2])
			{
				p.a[x + i][y + j] = 1;
			}
		}
}

Game类:
这个类,就是我们真正用于实现游戏。游戏中方块降落是否满行以及满行后的消行等操作都是在这一部分进行的。

class Game
{
public:
	void Game_start(); //开始游戏  
	void Line_check(Render& win, int x, int y, int color1, Render& win2, int x2, int y2, int color2);//检测是否满行 
	void Delete_line(Render& win, int x, int y, int color, int line_num);//消除一行方块 
	void Duel_penalization(Render& win, int x, int y, int color);//对战模式中的惩罚判定 
	void Game_over(int flag);//胜负已分,结束游戏 
}mainctrol;

void Game::Duel_penalization(Render& win, int x, int y, int color)
{
	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
	int i, j, order = rand() % 2;
	for (i = y - 1; i < y + H_SINGLE - 1; i++)
	{
		for (j = x + 2; j < x + 2 * W_SINGLE - 2; j++)
		{
			win.p.a[j][i] = win.p.a[j][i + 1];
		}
	}
	for (j = x + 2; j < x + 2 * W_SINGLE - 2; j += 2)
	{
		win.p.a[j][i] = order % 2;
		win.p.a[j + 1][i] = order % 2;
		order++;
	}
	for (i = y + H_SINGLE - 1; i > y; i--)
	{
		for (j = x + 2; j < x + 2 * W_SINGLE - 2; j += 2)
		{
			gotoxy(hOut, j, i);
			if (win.p.a[j][i] == 1) print_color("■", color);
			else print_color("■", 0);
		}
	}
}

其中,消行的操作得益于一下这个函数:

void Game::Delete_line(Render& win, int x, int y, int color, int line_num)
{
	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
	int i, j;
	for (i = line_num; i > y; i--)
	{
		for (j = x + 2; j < x + 2 * W_SINGLE - 2; j++)
		{
			win.p.a[j][i] = win.p.a[j][i - 1];
		}
	}
	for (i = line_num; i > y + 1; i--)
	{
		for (j = x + 2; j < x + 2 * W_SINGLE - 2; j += 2)
		{
			gotoxy(hOut, j, i);
			if (win.p.a[j][i] == 1) print_color("■", color);
			else print_color("■", 0);
		}
	}
	sndPlaySound(TEXT("SEB_platinum.wav"), SND_FILENAME | SND_NOSTOP);

}

不仅如此,我们还让这个游戏多了音效(虽然这个音效不太好听),也就是

#include <windows.h>
#include <Mmsystem.h>
#pragma comment(lib,"winmm.lib")
sndPlaySound(TEXT("SEB_platinum.wav"), SND_FILENAME | SND_NOSTOP);

此外,对方块是否满行操作的函数:

void Game::Line_check(Render& Win1, int x1, int y1, int color1, Render& Win2, int x2, int y2, int color2)
{
	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
	int flag = 0;
	for (int i = y1 + H_SINGLE - 1; i > y1; i--)
	{
		flag = 0;
		for (int j = x1 + 2; j < x1 + 2 * W_SINGLE - 2; j += 2)
		{
			if (Win1.p.a[j][i] == 0)
			{
				flag = 1;
				break;
			}
		}
		if (!flag)
		{
			Delete_line(Win1, x1, y1, color1, i);
			Duel_penalization(Win2, x2, y2, color2);
			Win1.score_add(100, x1, y1);
		}

	}

}

收获心得
对于此次我罗斯的开发,其实我们还是站在了巨人的肩膀上。毕竟,在前期我们还是参考了网上关于俄罗斯方块的代码,同时还在网上学习了很多关于渲染的方法。不过,在这次我罗斯的开发中还是遇到了好多问题,比如方块降落却“穿墙”,还有“幻影方块”,都是因为在编码过程中出现了bug,不过经过后面的调整最终还是将bug修复。也是通过这次的经历,明白了写程序之前最好将程序拆分成几部分,分部写,还要在每一部结束之后及时修改bug,避免bug堆积在一起导致后面的程序无法运行。通过此次的程序开发,可以深刻地认识到平时所写的代码与真正程序开发的不同,这也告诉我们之后不应该只局限于PTA上的作业,这样子我们将不能真正的成为一名合格的程序员。
存在问题:
1、整个游戏界面渲染不足;
2、整个程序设计结构过于一体,模块化不足;
3、代码过于冗长,不够精简;音效的衔接处理不够温和。

posted @ 2020-06-13 16:11  十又二分之一  阅读(180)  评论(1编辑  收藏  举报