C++做俄罗斯方块

概要

利用C++面向对象,逐步完善逻辑完成代码架构

游戏类的定义、地图类的定义

整体架构流程

定义游戏类:

        游戏类的属性有:分数、时间、地图尺寸

                        行为:画地图,地图右侧信息,行满消除行,碰撞测试等

定义图形类:

        属性有:横纵坐标,图形颜色,图形样式,图形类型,存储所有图形

        行为:设置图形初始坐标,对所有图形初始化,显示图形样式,绘制图形,移动图形等

技术细节

        不仅各类有属性和行为,还需要利用单例模式来针对单一对象。利用单例模式,那就需要添加接口来访问类的私有域

        游戏类做单例模式,在私有域中先定义一个构造函数并设置一个接口,用以访问私有域的数据,并且在public中设置一个静态指针函数用来接受接口数据,最后在类外初始化静态变态,开空间,存储地址名。

        先写入项目所需要的头文件以及你所需要的宏定义

#include <iostream>
#include <easyx.h>
#include <windows.h> 
#include <WinUser.h>
#include <ctime>
#include <cstdlib>
using namespace std;

//宏定义地图方块尺寸 
#define MAP_WIDTH 10
#define MAP_HEIGH 20
#define BLOK_WIDTH 20
//所有颜色的数组
int colorAll[] = {BLUE,GREEN,CYAN,RED,MAGENTA,BROWN,LIGHTCYAN};

        图形类

class block
{
private:
	int x;//横坐标 
	int y;//纵坐标 
	COLORREF color;//图形颜色 
	bool blocks[4][4] = {{0}};	//图形样式
	int type;//图形类型
	static bool Allblock[7][4][4];//左右所有图形 
public:
	//设置图形初始坐标 
	block(const int &x = MAP_WIDTH/2 - 4/2,const int &y=0 ):x(x),y(y)
	{
		randtype();
	}
	
	//对所有图形的初始化存储  
	static void intallblock(void);
	
	//随机选取图形操作
	void randtype(void); 
	
	//显示图形样式
	void show();
	
	//绘制图形 x,y  BLOK_WIDTH 游戏区域(20*20)
	void drewblock(); 
	
	//清除图形
	void clear(); 
	
	//移动函数
	bool move (int direction = 0);
	 
	//检测碰撞函数
	bool checkCollision(); 
	
	//设置位移的接口函数
	void setPos(const int &x = MAP_WIDTH/2 - 4/2,const int &y=0 );
	
	//添加到地图
	void addmap(); 
	
	//设置按键
	void key(int x);
	
	//图形旋转
	void rotate(void); 
}; 

        图形类的行为,先声明放在类内,再将定义写在类外,规范写法

        

//静态成员初始化
bool block::Allblock[7][4][4] = {{{0}}};

//随机产生图形的类型 
void block::randtype(void)
{
	//产生随机数 0 ~ 6 
	type = rand()%7;
 	//选取颜色 
 	color = colorAll[type];
 	//将Allblock[type]数据赋值给block 
 	int i,j;
	for(i=0;i<4;i++)
	{
		for(j=0;j<4;j++)
		{
			blocks[i][j] = Allblock[type][i][j];
		}	
	} 
}

//存储所有图形的类型 
 void block::intallblock(void)
 {
 		//长条 
	Allblock[0][0][1] = Allblock[0][1][1] = Allblock[0][2][1] = Allblock[0][3][1] = true;
	//正七字 
	Allblock[1][0][0] = Allblock[1][1][0] = Allblock[1][1][2] = Allblock[1][1][1] = true;
	//反七字 
	Allblock[2][1][0] = Allblock[2][1][1] = Allblock[2][1][2] = Allblock[2][2][0] = true; 
	//T字 
	Allblock[3][0][1] = Allblock[3][1][0] = Allblock[3][1][1] = Allblock[3][1][2] = true;
	//田字 
	Allblock[4][0][0] = Allblock[4][0][1] = Allblock[4][1][0] = Allblock[4][1][1] = true;
	//正Z 
	Allblock[5][0][0] = Allblock[5][0][1] = Allblock[5][1][1] = Allblock[5][1][2] = true;
	//竖Z 
	Allblock[6][0][1] = Allblock[6][1][0] = Allblock[6][1][1] = Allblock[6][2][0] = true;	
 }
 
//用控制台验证代码可行性 
 void block::show()

 {
 	int i,j;
	for(i=0;i<4;i++)
	{
		for(j=0;j<4;j++)
		{
			cout << blocks[i][j] << " ";
		}
		cout <<endl;	
	} 
 }

//画出方块的图形 
void block::drewblock()
{
	setfillcolor(color);
	int i,j;
	for(i=0;i<4;i++)
	{
		for(j=0;j<4;j++)
		{
			//判断block是否有值
			if(blocks[i][j])
			{
				//计算像素点
				int left = 20 + (x+j)*BLOK_WIDTH;
				int top = 20 + (y+i)*BLOK_WIDTH;
				fillrectangle(left,top,left+BLOK_WIDTH,top+BLOK_WIDTH);
			} 
		}	
	} 
}

void block::clear()
{
	int i,j;
	for(i=0;i<4;i++)
	{
		for(j=0;j<4;j++)
		{
			//判断block是否有值
			if(blocks[i][j])
			{
				//计算像素点
				int left = 20 + (x+j)*BLOK_WIDTH;
				int top = 20 + (y+i)*BLOK_WIDTH;
				clearrectangle(left,top,left+BLOK_WIDTH,top+BLOK_WIDTH);
			} 
		}	
	} 
}

//图形移动
bool block::move(int direction)
{
	if(direction == 0)
	{
		y++;
		//进行碰撞检测
		if(checkCollision())
		{
			y--;//重复方块,得会退一个格子 
			return true;	
		} 
		else 
		{
			return false;
		}
	}
	else if(direction ==1)//向左移动
	{
		x--;
		if(checkCollision())
		{
			x++;
		}
		else
		{
			return false;
		}
	}
	 else if(direction ==2)//向右移动 
	 {
	 	x++;
	 	if(checkCollision())
		{
			x--; 	
		}	
		else
		{
		 	return false;
		}
	 }
}

//图形旋转
void block::rotate(void)
{
	if(type==0||type==1||type==2||type==3||type==5||type==6)
		{
			//四角 
			int  temp1 = 0;
			temp1 =blocks[0][0];
			blocks[0][0] = blocks [0][2];
			blocks[0][2] = blocks [2][2];
			blocks[2][2] = blocks [2][0];
			blocks[2][0] = temp1;
			//十字 
			int temp2 = 0;
			temp2 = blocks[0][1];
			blocks[0][1] = blocks[1][2];
			blocks[1][2] = blocks[2][1];
			blocks[2][1] = blocks[1][0];
			blocks[1][0] = temp2;
			if(type == 0)
			{	
				int temp = blocks[1][3];
				blocks[1][3] = blocks[3][1];
				blocks[3][1] = temp;
			}
			if(checkCollision()) 
			{
				int temp = blocks[0][0];
				blocks[0][0] = blocks[2][0];
				blocks[2][0] = blocks[2][2];
				blocks[2][2] = blocks[0][2];
				blocks[0][2] = temp;
				temp = blocks[0][1];
				blocks[0][1] = blocks[1][0];
				blocks[1][0] = blocks[2][1];
				blocks[2][1] = blocks[1][2];
				blocks[1][2] = temp;
				if(type == 0)
				{
					int temp = blocks[1][3];
					blocks[1][3] = blocks[3][1];
					blocks[3][1] = temp;
				}
			
			}
		}		
}

//设置x,y
void block::setPos(const int &x,const int &y)
{
	this->x = x;
	this->y = y;
} 

        游戏类

class Game
{
private:
	int score =0;//分数 
	int game_time = 0;//时间 
	bool map[MAP_HEIGH][MAP_WIDTH] = {{0}};//地图尺寸 
	
	//单例模式,构造函数私有 
	Game(){}
	Game(const Game &p){}
	
	// 设置一个接口 
	static Game *p;
	
	//设置析构函数
	~Game()
	{
		delete p;
		p = NULL;
	}
	
public:	
	void play();//开始游戏
	static Game *getInstance();//设置一个静态指针函数,接收获得接口的数据 

	//画地图 
	void drewmap();
	
	//画右侧信息
	void drewprompt();
	
	//设置一个接口,给碰撞测试使用
	bool getmap(const int &x = 0,const int &y = 0);
	
	//设置map里面的方块数据函数 -----给block里面的addmap使用
	void setmap(const int &x = 0,const int &y = 0,const int &value=0);	
		
	//消除行
	void clearline(); 
};
    类外定义游戏类的行为
//返回p的地址 
Game* Game::getInstance()
{
	return p;	
}

//画地图尺寸 
void Game::drewmap()
{
	//绘制外圈圆角矩形---- 10,10,340,430,10,10
	roundrect(10,10,340,430,10,10);
	
	//绘制内层直角矩形---- 20,20,220,420
	rectangle(20,20,220,420);
	
	
	//设置一个填充色 
	setfillcolor(YELLOW);
	
	//根据 map[MAP_WIDTH][MAP_HEIGH] 绘制地图  如果为1则填充矩形
	int i,j;
	for(i=0;i<MAP_HEIGH;i++)
	{
		for (j=0;j<MAP_WIDTH;j++)
		{
			if(map[i][j] == true)
			{
				int left = 20 + j*20;
				int top = 20 + i*20;
				//画格子 
				fillrectangle(left,top,left+BLOK_WIDTH,top+BLOK_WIDTH);
			}
		}	
	} 
}

//画右侧信息 
void Game::drewprompt() 
{
	//easyX的字体
	//创建一个字体对象
	LOGFONT f;
	settextcolor(BLACK);
	
	//可以让字体在默认的样式上进行修改----- 先获取一下默认值
	gettextstyle(&f);
	
	//可以设置自定义样式 ------235,20,_T("下一方块"); 
	f.lfHeight = 30;
	f.lfQuality = PROOF_QUALITY;
	settextstyle(&f);
	outtextxy(235,20,_T("下一方块")); 
	
	//显示分数----- 235,180,str
	f.lfHeight = 15;
	settextstyle(&f);
	
	//将其他基本数据类型的数据一某种方式转成字符串---  
	char str[20] = {0};
	sprintf(str,_T("分数:%d"),score);
	outtextxy(235,180,str);
	
	//显示时间 ---- 235,220,str 
	char str1[20] = {0};
	sprintf(str1,_T("时间:%d秒"),game_time/1000);
	outtextxy(235,220,str1);
}

//接口函数 
bool Game::getmap(const int &x,const int &y)
{
	return map[x][y];	
}

//碰撞检测
bool block::checkCollision()
{
	//获取Game对象
	Game *game = Game::getInstance();
	 
	int i,j;
	for(i=0;i<4;i++)
	{
		for(j=0;j<4;j++)
		{
			//计算相对位移 x+i y+j
			if(blocks[i][j])
			{
				int left = 20 + (x+j)*BLOK_WIDTH;
				int top =  20 + (y+i)*BLOK_WIDTH;
				//map[x+j],[y+i]是私有的---需要用到一个接口来调用game 
				if(game->getmap(y+i,x+j) == 1 || left < 20 || left+BLOK_WIDTH>220 ||top+BLOK_WIDTH>420)
				{
					return true;	
				}	
			} 
		}	
	} 
	return false;
}

//设置map里面的方块数据函数 -----给block里面的addmap使用
void Game::setmap(const int &x,const int &y,const int &value)
{ 
	map[x][y] = value;	
}

//将block[4][4] 放入map 
void block::addmap()
{
	Game *game = Game::getInstance();
	int i,j;
	for(i=0;i<4;i++)
	{
		for(j=0;j<4;j++)
		{
			if(blocks[i][j])
			{
				//找坐标 y+i x+j
				game->setmap(y+i,x+j,blocks[i][j]); 
			} 
		}	
	} 
}

//消除行
void Game::clearline()
{
	bool flag;
	//每次消除一行即可 
	for(int i=0;i<20;i++)
	{
		flag = false;
		//扫行
		for(int j=0;j<10;j++)
		{
			if(map[i][j] == 0)	
			{
				flag = true;
				break;
			}
		}
		if(flag == false)
		{
			//满行 将行从i-1开始依次向下移动
			for(int line =i;line>0;line--)
			{
				for(int x=0;x<10;x++)
				{
					map[line][x] = map[line-1][x];	
				}	
			}
			score+=10;
			break;//每次清除一行		
		} 	
	}	
} 
//在静态区开空间,将地址名存入p 
Game* Game::p = new Game;
将所有的行为定义完成,需要用game写一个执行程序
//执行游戏 
void Game::play()
{
	cout << "开始游戏" << endl;	

	//创建画布返回一个窗口句柄 
	HWND a = initgraph(350,440,EX_SHOWCONSOLE);
 
 	// windos opi SetWindowText--设置窗口标题
	//_T(字符串) 可以将字符串转换成 LPCTSTR类型
	SetWindowText(a,_T("俄罗斯方块"));
	
 	//设置背景色
	setbkcolor(WHITE);
	cleardevice();
	
	//设置线条颜色
	setlinecolor(BLACK);
	
	Game::drewmap(); // 调用绘制地图 
	
	Game::drewprompt();// 调用绘制右侧信息
	
	//初始化所有图形
	block::intallblock();
	
	//刷新种子
	srand(time(NULL)); 
	
	block b;
	b.show();

	//画出图形初始位置 
	b.drewblock();
	
	//画出下一个方块
	block nextblock(11,2);
	nextblock.drewblock();
	
	//定义时间用于控制下降的速度 
	clock_t start = 0;
	clock_t end;
	
	BeginBatchDraw();
	
	ExMessage mes;
	
	while(1)
	{
		//4*4擦除
		b.clear();
		//清空地图 --- 20,20  220,420
		clearrectangle(20,20,220,420);
		//重新绘制
		drewmap(); 
		
		//按键操作
		bool res1 = peekmessage(&mes,EX_KEY);
		if(res1&&mes.message == WM_KEYDOWN)
		{	
			if(mes.vkcode == VK_DOWN||mes.vkcode =='s'||mes.vkcode =='S')
			{
				bool res = b.move(0);//检测本次移动是否结束
				if(res)
				{
					b.addmap();					
					b = nextblock;
					b.setPos();
					nextblock.randtype();
					clearrectangle(240,60,320,140);
					nextblock.drewblock();
					if(b.checkCollision())
					{
						b.drewblock();	
						MessageBox(GetHWnd(),_T("游戏结束"),_T("haha"),MB_OKCANCEL);
						goto exit;		
					} 
				}	
			}
			else if(mes.vkcode == VK_UP)
			{
				b.rotate();
			}
			else if(mes.vkcode == VK_LEFT||mes.vkcode =='A'||mes.vkcode =='a')
			{
				b.move (1); 
			}
			else if(mes.vkcode == VK_RIGHT||mes.vkcode =='D'||mes.vkcode =='d')
			{
				b.move (2); 
			}
			else if(mes.vkcode == VK_ESCAPE)
			{
				goto exit; 
			}			
		}
		  
		end = clock();//获取系统时间 
		if(end-start >=500)
		{
			bool res = b.move();//检测本次移动是否结束
			
			if(res)
			{
				b.addmap();
				//b = nextblock
				b = nextblock;
				//b修改x,y ---- 私有的 ----block
				b.setPos();
				//生成新的nextblock
				nextblock.randtype();
				clearrectangle(240,60,320,140);//清除已经画出来的xext方块
				//绘制新的nextblock
				nextblock.drewblock();
				
				if(b.checkCollision())
				{
					// 检测到碰撞绘制一下 
					b.drewblock();
					//提示用户游戏结束--弹窗口-- windows MessageBox
					MessageBox(GetHWnd(),_T("游戏结束"),_T("haha"),MB_OKCANCEL);
					goto exit;		
				} 
			}
			start = clock();
			game_time +=500;
			drewprompt();	 
		} 
		
		b.drewblock();
		
		//清除行 
		clearline();
		drewprompt();
		
		FlushBatchDraw();
		Sleep(50);		
	}
	exit:
	EndBatchDraw();
} 

主函数

int main(int argc, char** argv) {
	
	Game *p = Game::getInstance();
	p->play();
	
	return 0;
}

小结

        以上代码完整放入devc++,即可做出俄罗斯方块,但是需要下载easyx(链接为EasyX Graphics Library for C++),下载好后将devc++这个文件打开

easyx文档解压完是这样,将easyx下载后的文件名一一对应放入:

不要直接拖文件夹,要将easyx中的文件逐一放入

devc++软件(链接:https://pan.baidu.com/s/1qL_m4MJOijTvbT2LrvOl-w 
提取码:4pb0)

这样就可以调用easyx的库

最后在devc++中点击  项目 --- 项目属性 --- 参数 ----加入以上参数就可以完成俄罗斯方块项目

  • 28
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是用C++实现俄罗斯方块游戏的基本步骤: 1.定义方块的形状和颜色,可以使用二维数组来表示方块的形状,使用枚举类型来表示颜色。 2.定义游戏区域,可以使用二维数组来表示游戏区域,其中0表示该位置为空,1表示该位置有方块。 3.定义方块的移动和旋转,可以使用函数来实现方块的移动和旋转,例如moveLeft()、moveRight()、moveDown()、rotate()等函数。 4.定义方块的下落,可以使用定时器来实现方块的下落,例如每隔一定时间调用一次moveDown()函数。 5.定义方块的消除,可以使用函数来实现方块的消除,例如checkFullLine()函数,该函数用于检查游戏区域中是否有满行,如果有,则将该行消除,并将上面的方块下落。 6.定义游戏结束条件,例如当方块无法下落时,游戏结束。 以下是一个简单的C++俄罗斯方块游戏的代码示例: ```c++ #include <iostream> #include <cstdlib> #include <ctime> using namespace std; const int ROWS = 20; const int COLS = 10; enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; int board[ROWS][COLS] = { 0 }; int shapes[7][4][4] = { { { 0, 0, 0, 0 }, { 1, 1, 1, 1 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }, { { 0, 0, 0, 0 }, { 0, 2, 2, 0 }, { 0, 2, 2, 0 }, { 0, 0, 0, 0 } }, { { 0, 0, 0, 0 }, { 0, 3, 3, 0 }, { 3, 3, 0, 0 }, { 0, 0, 0, 0 } }, { { 0, 0, 0, 0 }, { 4, 4, 0, 0 }, { 0, 4, 4, 0 }, { 0, 0, 0, 0 } }, { { 0, 0, 0, 0 }, { 0, 5, 0, 0 }, { 5, 5, 5, 0 }, { 0, 0, 0, 0 } }, { { 0, 0, 0, 0 }, { 0, 6, 0, 0 }, { 0, 6, 6, 0 }, { 0, 6, 0, 0 } }, { { 0, 0, 0, 0 }, { 0, 7, 0, 0 }, { 0, 7, 7, 0 }, { 0, 0, 7, 0 } } }; Color colors[8] = { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; struct Point { int x; int y; }; class Tetromino { public: Tetromino() { srand(time(NULL)); shape = shapes[rand() % 7]; color = colors[rand() % 8]; pos.x = 0; pos.y = 3; } void moveLeft() { pos.y--; } void moveRight() { pos.y++; } void moveDown() { pos.x++; } void rotate() { int temp[4][4]; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { temp[i][j] = shape[i][j]; } } for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { shape[i][j] = temp[3 - j][i]; } } } bool canMoveLeft() { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (shape[i][j] != 0 && (board[pos.x + i][pos.y + j - 1] != 0 || pos.y + j - 1 < 0)) { return false; } } } return true; } bool canMoveRight() { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (shape[i][j] != 0 && (board[pos.x + i][pos.y + j + 1] != 0 || pos.y + j + 1 >= COLS)) { return false; } } } return true; } bool canMoveDown() { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (shape[i][j] != 0 && (board[pos.x + i + 1][pos.y + j] != 0 || pos.x + i + 1 >= ROWS)) { return false; } } } return true; } bool canRotate() { int temp[4][4]; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { temp[i][j] = shape[i][j]; } } for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { shape[i][j] = temp[3 - j][i]; } } bool result = true; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (shape[i][j] != 0 && (board[pos.x + i][pos.y + j] != 0 || pos.x + i >= ROWS || pos.y + j < 0 || pos.y + j >= COLS)) { result = false; } } } for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { shape[i][j] = temp[i][j]; } } return result; } void draw() { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (shape[i][j] != 0) { board[pos.x + i][pos.y + j] = color; } } } } void undraw() { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (shape[i][j] != 0) { board[pos.x + i][pos.y + j] = 0; } } } } void print() { for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { if (board[i][j] == 0) { cout << " "; } else { cout << "*"; } } cout << endl; } } private: int shape[4][4]; Color color; Point pos; }; int main() { Tetromino t; while (true) { t.draw(); t.print(); t.undraw(); if (t.canMoveDown()) { t.moveDown(); } else { break; } } return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值