俄罗斯方块,纯C++实现

#include<iostream>
#include<Windows.h>
#include<string>
#include<vector>
#include<ctime>
#include<conio.h>
using namespace std;
static const int LEVEL = 10;//最高等级
const int LEFT = 15;//游戏界面的左边界
const int RIGHT = 29;//游戏界面的右边界
const int TOP = 5;//游戏界面的上边界
const int BOTTOM = 20;//游戏界面的下边界
class Position {
public:
	Position() {}
	~Position() {}
	void locateXy(int x, int y);
};
void Position::locateXy(int x, int y) {
	COORD pos;
	pos.X = x;
	pos.Y = y;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}//定位到X,Y,左上角为(0,0)

//游戏界面框架  Framework
class Framework {
public:
	Framework() {

	}
	~Framework() {

	}
	void printFrame();
	void printScore(int score);
	void printLevel(int level);
};

//Frame类函数实现
void Framework::printFrame() {
	Position p;
	for (int i = LEFT; i < RIGHT+1; i++) {
		p.locateXy(i, TOP);
		cout << "*";
	}
	for (int i = LEFT; i < RIGHT+1; i++) {
		p.locateXy(i, BOTTOM);
		cout << "*";
	}
	for (int j = TOP + 1; j < BOTTOM; j++) {
		p.locateXy(LEFT, j);
		cout << "*";
	}
	for (int j = TOP + 1; j < BOTTOM; j++) {
		p.locateXy(RIGHT, j);
		cout << "*";
	}
	p.locateXy(0, 0);//重置
}


void Framework::printScore(int score) {
	cout << "Now your score is " << score << endl;
}

void Framework::printLevel(int level) {
	cout << "Now your level is " << level << ".(Attenton:Speed increases with level.)" << endl;
}


//方块构成 Formation
class Formation {
public:
	Formation(int x, int y) {
		this->x = x;
		this->y = y;
	}
	int getX() {
		return x;
	}
	int getY() {
		return y;
	}
	void setX(int x) {
		this->x = x;
	}
	void setY(int y) {
		this->y = y;
	}
private:
	int x;
	int y;
};



//Block 方块
class Block : {
public:
	Block();
	~Block() {}
	int getLevel() {
		return level;
	};
	void create();
	void rotate();//方块旋转
	void printBlock();//显示方块
	void fall();//方块下落
	void setSpeed(int speed);
	bool isDead();//判断游戏是否结束
	int eliminate();//实现方块消除
	bool stop();//方块碰到底部或者下一行有方块时停止下落
	void shift();//左移,右移,速降
	void play();//控制游戏进程
	void replay();
private:
	int level = 0;
	int score = 0;
	int Speed[LEVEL] = { 700,650,600,550,500,450,400,400,400,400 };//用时间度量速度
	bool isoccupied[25][20];//二维数组,当有方块时值为1,25与20防止越界
	int speed = 800;// 初始速度
	vector<Formation>arr;// 对象数组,记录组成方块的xy值
};


Block::Block() {
	for (int i = 0; i <= RIGHT - LEFT - 2; i++) {
		for (int j = 0; j <= BOTTOM - TOP - 2; j++) {
			isoccupied[i][j] = 0;//游戏界面内的所有格子初始化为没有方块占据
		}
	}
}


void Block::create() {
	int shape;//方块形状对应的数字
	int rotation;//旋转状态对应的数字
	int midpoint = (RIGHT - LEFT) / 2;

	//这里利用系统时间生成随机数初始化shape和rotation,以实现方块形状和旋转方向的丰富性
	srand(time(NULL));
	shape = rand() % 9;
	//基本方块有5种,但为将游戏难度降低,多分配了四种情况,提高了四连正方形,城墙形,正方形的出现概率
	rotation = rand() % 5;
	//四种旋转状态
	arr.clear();//需要多次调用该函数,每次调用时清零arr
	Position p;
	switch (shape)
	{
	case 0:case 5:
		arr.clear();
		for (int i = 0; i < 4; ++i)
		{
			Formation formation(i + LEFT + midpoint + 1, TOP + 1);             
			arr.push_back(formation);
		}//四连长方形
		for (int i = 0; i < rotation; ++i)
		{
			rotate();//rotate函数实现方块旋转;
		}
		break;
	case 1:case 6:case 7:
		arr.clear();
		for (int i = 0; i < 2; ++i)
		{
			for (int j = 0; j < 2; ++j)
			{
				Formation formation(i + LEFT + midpoint + 1, TOP + 1 + j);   
				arr.push_back(formation);
			}
		} //正方形
		break;//正方形旋转还是正方形,所以不必旋转
	case 2:                                                        
		arr.clear();
		arr.push_back(Formation(LEFT + midpoint + 1, TOP + 1));
		arr.push_back(Formation(LEFT + midpoint + 2, TOP + 1));
		arr.push_back(Formation(LEFT + midpoint + 3, TOP + 1));
		arr.push_back(Formation(LEFT + midpoint + 3, TOP + 2));
		for (int i = 0; i < rotation; ++i)
		{
			rotate();
		}//枪形
		break;
	case 3:                                                         
		arr.clear();
		arr.push_back(Formation(LEFT + midpoint + 1, TOP + 1));
		arr.push_back(Formation(LEFT + midpoint + 1, TOP + 2));
		arr.push_back(Formation(LEFT + midpoint + 2, TOP + 2));
		arr.push_back(Formation(LEFT + midpoint + 2, TOP + 3));
		for (int i = 0; i < rotation; ++i)
		{
			rotate();
		} //梯形
		break;
	case 4: case 8:
		arr.clear();                                               
		arr.push_back(Formation(LEFT + midpoint + 1, TOP + 1));
		arr.push_back(Formation(LEFT + midpoint + 2, TOP + 1));
		arr.push_back(Formation(LEFT + midpoint + 3, TOP + 1));
		arr.push_back(Formation(LEFT + midpoint + 2, TOP + 2));
		for (int i = 0; i < rotation; ++i)
		{
			rotate();
		}//城墙形
		break;
	}

	for (int i = 0; i < 4; ++i)
	{
		isoccupied[arr[i].getX() - 1 - LEFT][arr[i].getY() - 1 - TOP] = true;
	}//方块创建之后,将方块所在的格子全部赋值为1,其余保持为0
}


//旋转方块,rotate相当于create的一个子函数;左上角方块位置不变,其余方块以左上角方块为轴逆时针旋转90度
void Block::rotate() {
	for (int i = 0; i < 4; ++i)
	{
		isoccupied[arr[i].getX() - 1 - LEFT][arr[i].getY() - TOP - 1] = false;
	}// 旋转后方块位置变化,先将旋转前的值清零;旋转后再在create之中赋1
	for (int i = 1; i <= 3; ++i)
	{//i从1开始,左上角不动
		int distanceOfX = arr[i].getX() - arr[0].getX();
		int distanceOfY = arr[i].getY() - arr[0].getY();
		arr[i].setX(arr[0].getX() - distanceOfY);
		arr[i].setY(arr[0].getY() + distanceOfX);
	}
}


//显示方块
void Block::printBlock() {
	//遍历整个棋盘,有方块的地方显示方块,没有方块的地方打上空格
	Position p;
	char sym = '#';
	for (int i = LEFT + 1; i < RIGHT; ++i)
	{
		for (int j = TOP + 1; j < BOTTOM; ++j)
		{
			if (isoccupied[i - LEFT - 1][j - TOP - 1] == true)
			{
				p.locateXy(i, j);
				cout << sym;
			}
			else
			{
				p.locateXy(i, j);
				cout << " ";
			}
		}
	}
	return;
}


void Block::fall() {//方块下落,Y坐标加1
	for (int i = 0; i < 4; ++i)
	{
		isoccupied[arr[i].getX() - 1 - LEFT][arr[i].getY() - TOP - 1] = false;
	}//先清零,下落后重新赋值为1
	for (int i = 0; i < 4; ++i)
	{
		arr[i].setY(arr[i].getY() + 1);
	}//方块下落一格
	for (int i = 0; i < 4; ++i)
	{
		isoccupied[arr[i].getX() - 1 - LEFT][arr[i].getY() - TOP - 1] = true;
	}
}


void Block::setSpeed(int speed) {
	this->speed = speed;
}

//检测游戏是否输了,直接检测最上面一排即可
bool Block::isDead() {//检测棋盘最顶层有无方块,若有,返回1
	for (int i = LEFT; i < RIGHT - 1; ++i) {
		if (isoccupied[i - LEFT][0]== true){
			return 1; 
		}
	}
	return 0;
}


//实现方块的消除
int Block::eliminate() {
	{
		int level = 0;
		int i = 0;
		for (i = BOTTOM - TOP - 2; i >= 0; --i)
		{//从最下面一行开始检测,遍历所有行
			bool temp = true;
			for (int j = 0; j < RIGHT - LEFT - 1; ++j)
			{// 对单独每一行进行检测
				if (isoccupied[j][i] == false)
					temp = false;
			}//只有当该行全部有方格时才能使得temp=1;满足消除条件
			if (temp == true)
			{
				level++;//消除一行,返回1;消除n行,返回n

				for (int k = 0; k < RIGHT - LEFT - 1; ++k)
				{
					for (int t = i; t > 0; --t)
					{
						isoccupied[k][t] = isoccupied[k][t - 1];
					}
				}//消除的行的上面依次下落一行,直到最上面一行
				i++;                                         //检测刚刚替补的一行
			}
			temp = true;
		}
		return level;
	}
}


bool Block::stop()
{
	bool flag = false;
	for (int i = 0; i < 4; ++i)
	{
		isoccupied[arr[i].getX() - LEFT - 1][arr[i].getY() - TOP - 1] = false;
		//先清零,后重新赋值
	}
	for (int i = 0; i < 4; ++i)
	{
		if (arr[i].getY() == BOTTOM - 1)
			flag = true;
		//第一种情况,方块已经到了最下面一行
		if (isoccupied[arr[i].getX() - LEFT - 1][arr[i].getY() + 1 - TOP - 1] == true)
			flag = true;
		//第二种情况,方块所在行下面一行已经有了方块
	}
	for (int i = 0; i < 4; ++i)
	{
		isoccupied[arr[i].getX() - LEFT - 1][arr[i].getY() - TOP - 1] = true;
	}
	return flag;
	//以上两种情况,返回值为1
}


void Block::shift()
{
	vector<Formation> arr2;
	for (int i = 0; i < 4; ++i)
	{
		arr2.push_back(arr[i]);
		//用arr2记录下arr原本的位置, 如果arr的方块撞到了左右墙壁,则用arr2重新初始化arr
		isoccupied[arr[i].getX() - 1 - LEFT][arr[i].getY() - TOP - 1] = false;
	}
	while (_kbhit())//检测是否由键盘输入
	{
		switch (_getch())//获取键盘输入的字符
		{
		case 97: case 65:                                 //左移   A,a对应的ASIC码
			for (int i = 0; i < 4; ++i)
			{
				int m = arr[i].getX();
				arr[i].setX(m - 1);
			}
			break;
		case 100:case 68:                             //右移   D,d对应的ASIC码
			for (int i = 0; i < 4; ++i)
			{
				int m = arr[i].getX();
				arr[i].setX(m + 1);
			}
			break;
		case 82:case 114:                                    //旋转    R,r对应的ASIC码
			rotate();
			break;
		case 83:case 115:
			setSpeed(10);                                     //速降   S,s对应的ASIC码
		default:
			break;
		}

		//防止碰壁的代码如下:
		bool flag = 0;
		for (int i = 0; i < 4; ++i)
		{
			if (arr[i].getX() <= LEFT || arr[i].getX() >= RIGHT)//方块越左右界
				flag = true;
		}
		if (flag == true)     //如果相撞,用arr2初始化arr                                      
		{
			arr.clear();
			for (int i = 0; i < 4; ++i)
			{
				arr.push_back(arr2[i]);
			}
		}
		for (int i = 0; i < 4; ++i)
		{
			isoccupied[arr[i].getX() - 1 - LEFT][arr[i].getY() - 1 - TOP] = true;
		}
		return;
	}
}


void Block::play() {
	while (isDead() == false)
	{//如果还没输
		create();//产生随机方块
		printBlock();//显示方块
		while (!stop())
		{//方块没到底
			shift();//左右速降
			fall();//降落一格
			printBlock();//显示降落后的方块
			Sleep(speed);//延时speed时间,进入下一循环
		}
		//方块落到地后更新分数,等级,判断是否达到最大速度
		score += eliminate();
		level = score / 3;
		if (level == LEVEL)
		{
			break;
		}
		speed = Speed[level];
		cout << endl << endl;
		printLevel(level + 1);
		printScore(score);
		Sleep(speed); 
	}
}



int main() {
	Framework f;
	Position p;
	char choice;
	f.printFrame();//打印游戏界面
	bool flag = true;
	while (flag) {
		Block b;
		b.play();
		if (1)
		{
			p.locateXy(0, 0);
			cout << "你这盘达到的等级是" << b.getLevel()+1 << endl;
			cout << "是否重新开始?,如果重新开始,请输入Y" << endl;
			cin >> choice;
			if (choice == 'Y')
			{
				flag = true;
			}
			else flag = false;
		}
	}
	return 0;
}
s

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值