运用c++与easyx图形库实现消灭星星最基本的消除功能、掉落功能以及判断死锁的方式

运用c++与easyx图形库实现消灭星星最基本的消除功能、掉落功能以及判断死锁的方式

写在前面的话

此程序只实现了游戏的小部分内容,没有华丽的外观与消除特效

消灭星星是一款前些年十分流行的手机游戏,玩法简单却非常容易让人上瘾。

《消灭星星》是由Brian Baek公司开发的一款消除类休闲娱乐手机游戏,于2014年发行,游戏大小为3.8M。本作特点是易上手,点击两个或两个以上颜色相同的方块即可消除,没有时间限制。
                                                                                                                       ----百度百科

  1. 实现游戏的初始状态:

游戏的初始状态如图:
运用c++与easyx图形库实现消灭星星最基本的消除功能、掉落功能以及判断死锁的方式_第1张图片
游戏关卡结束
运用c++与easyx图形库实现消灭星星最基本的消除功能、掉落功能以及判断死锁的方式_第2张图片

再附上我们程序最终实现的效果

游戏的初始状态
运用c++与easyx图形库实现消灭星星最基本的消除功能、掉落功能以及判断死锁的方式_第3张图片
游戏的关卡结束状态:
运用c++与easyx图形库实现消灭星星最基本的消除功能、掉落功能以及判断死锁的方式_第4张图片

由图可知:游戏区域为一个10*10的正方形区域,区域中分布着红,紫,蓝,绿,黄5中颜色的方块。
我们可以简单的使用一个二维数组来存储每个不同颜色的方块,在初始化游戏是用以下代码来生成游戏的初始状态:

//准备工作
#define pointWidth 30  //每个方块的宽度

//为了是二维数组和游戏界面上的小方块对应起来定义一个point结构体
typedef struct point {
	int x;  //点的横坐标
	int y; //点的纵坐标
	point() {};
	point(int _x, int _y) {
		x = _x;
		y = _y;
	}
}point;

//绘制出方块,80和120是整个10*10区域在窗口中的位置,可视情况而改之
void drawPoint(point p, int color = GREEN) {
	setlinecolor(BLACK);
	setfillcolor(color);
	//+1,-1是的实际小正方形的边长为pointWidth-2
	int sx, sy, ex, ey;
	sx = 80 + pointWidth * p.x + 1;
	sy = 120 + pointWidth * p.y + 1;
	ex = sx + pointWidth - 1;
	ey = sy + pointWidth - 1;
	fillroundrect(sx, sy, ex, ey, 5, 5);
}

//定义二维数组
int item[10][10] = {0};
//方块的颜色,colors[0]是黑色(背景色),代表该处无方块(已被消除)
int colors[] = {BLACK,RED,YELLOW,BLUE,GREEN,RGB(128,0,128)};
srand(unsigned(clock()));
for (int i = 0; i < 10; i++) {
	for (int j = 0; j < 10; j++) {
		item[i][j] = rand() % 5+ 1;
	}
}
//绘制游戏界面
void gameinterface() {
	point p;
	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
				p.x = i;
				p.y = j;
				drawPoint(p, colors[item[i][j]]);
		}
	}
}
  1. 方块的消除;
    我们可以通过下面代码获取鼠标点击的位置坐标,通过简单的计算得到对应二维数组中对应位置的存储的数字(颜色),从而进一步判断其能否被删除。
//将鼠标点击的坐标转换为二维数组的下标
m = GetMouseMsg();
		if (m.mkLButton&&m.x >= 80 && m.x < (80 + pointWidth * 10) && m.y >= 120 && m.y <= (120 + pointWidth * 10)) {
			cnt = 0;
			p.x = (m.x - 80) / pointWidth;
			p.y = (m.y - 120) / pointWidth;
//判断其能否被消除,当与被点击方块相邻(上、下、左、右,不包括对角)的方块中有与之相同颜色的方块时,该被点击方块可被消除
bool ifCanPop(point p) {
	for (int i = p.x - 1; i <= p.x + 1; i++) {
		for (int j = p.y - 1; j <= p.y + 1; j++) {
			if (item[i][j]!=0&&item[i][j] == item[p.x][p.y] && ((p.x == i && p.y != j) || (p.x != i && p.y == j))) {
				return true;
			}
		}
	}
	return false;
}
//方块的消除,将二维数组对应位置的值设为0;
void popstar(point p) {
	drawPoint(p, BLACK);
	item[p.x][p.y] = 0;
}

由于消除方块不单单是消除被点击的方块,连同与其相邻的同色方块都需要一并消除,我们可以使用队列,类似与图的广度优先搜索,先将第一个可以被消除的点入队列,再将队头的方块相邻且同色的方块压入队列,再pop对头的方块,直到队列为空时,说明消除完毕


if (item[p.x][p.y] != 0 && ifCanPop(p)) {
				a.push(p);//放入第一个可消除的方块
				while (!a.empty()) {
					point temp = a.front();//取的队头元素,下面的两层循环就是找与之相邻且同色的方块,并入队列
					for (int i = temp.x - 1; i <= (temp.x + 1) && i < 10; i++) {
						for (int j = temp.y - 1; j <= (temp.y + 1) && j < 10; j++) {
						//判断item[i][j]!=0避免重复访问
							if (item[i][j] != 0 && item[i][j] == item[temp.x][temp.y] && ((temp.x == i && temp.y != j) || (temp.x != i && temp.y == j))) {
								point pp(i, j);
								a.push(pp);
							}
						}
					}
					a.pop();弹出队头元素
					popstar(temp);//消除对头对应位置的方块
					cnt++;//记录消除的个数,方便计算得分
				}
  1. 方块的掉落与左移;
//当方块下方为空时,方块位置下移
void down() {
	for (int i = 0; i < 10; i++) {
		int d = 0;
		for (int j = 9; j >= 0; j--) {
			if (item[i][j] == 0)
				d++;
			else
				item[i][j + d] = item[i][j];
		}
		for (int k = 0; k < d; k++) {
			item[i][k] = 0;
		}
	}
}

//当有一列中的小方块均为空时,右边不为空的方块左移
void left() {
	bool isBlankCol;
	int count = 0;
	for (int i = 0; i < 10; i++) {
		isBlankCol = true;
		for (int j = 0; j < 10; j++) {
			if (item[i][j] != 0)
				isBlankCol = false;
		}
		if (isBlankCol) { count++; }
		else {
			for (int jj = 0; jj < 10; jj++) {
				item[i - count][jj] = item[i][jj];
			}
		}
	}
	for (int k = 10 - count; k < 10; k++) {
		for (int j = 0; j < 10; j++) {
			item[k][j] = 0;
		}
	}
}
  1. 判断死锁(没有可以消除的方块了);

简单思考可知,我们只需间隔的判断小方格是否可以被消除就可以判断所有的方块是否存在可以被消除的方块。

bool isDeadlock() {
	for (int i = 0; i < 10; i++) {
		for (int j = i % 2; j < 10; j += 2) {
			point p(i, j);
			if (ifCanPop(p)) return false;
		}
	}
	return true;
}

6.所有代码(包括一些没有说明的代码)

#include
#include
#include
#include
#include
using namespace std;

#define pointWidth 30


int item[10][10] = {0};
int colors[] = {BLACK,RED,YELLOW,BLUE,GREEN,RGB(128,0,128)};
int score;
IMAGE startbkimage;
//定义结构体点   这个点为游戏地图上的点,并非像素点
typedef struct point {
	int x;  //点的横坐标
	int y; //点的纵坐标
	point() {};
	point(int _x, int _y) {
		x = _x;
		y = _y;
	}
}point;

void drawPoint(point p, int color = GREEN) {
	setlinecolor(BLACK);
	setfillcolor(color);
	int sx, sy, ex, ey;
	sx = 80 + pointWidth * p.x + 1;
	sy = 120 + pointWidth * p.y + 1;
	ex = sx + pointWidth - 1;
	ey = sy + pointWidth - 1;
	fillroundrect(sx, sy, ex, ey, 5, 5);
}

void initgame() {

	score = 0;
	srand(unsigned(clock()));
	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			item[i][j] = rand() % 5+ 1;
		}
	}
}

void startinterface(){
	putimage(0, 0, &startbkimage);
	MOUSEMSG m;
	while (1) {
		m = GetMouseMsg();
		if (m.mkLButton)
			break;
	}

}

void gameinterface() {
	point p;
	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
				p.x = i;
				p.y = j;
				drawPoint(p, colors[item[i][j]]);
		}
	}
}

bool ifCanPop(point p) {
	for (int i = p.x - 1; i <= p.x + 1; i++) {
		for (int j = p.y - 1; j <= p.y + 1; j++) {
			if (item[i][j]!=0&&item[i][j] == item[p.x][p.y] && ((p.x == i && p.y != j) || (p.x != i && p.y == j))) {
				return true;
			}
		}
	}
	return false;
}

//更新分数,cnt为每次消除的个数
void updateScore(int cnt) {
	score += (cnt*cnt * 5);
	_TCHAR S[20];
	_stprintf_s(S,L"%d",score);
	settextstyle(40, 0, 0);
	outtextxy(400,600,S);
}
bool isDeadlock() {
	for (int i = 0; i < 10; i++) {
		for (int j = i % 2; j < 10; j += 2) {
			point p(i, j);
			if (ifCanPop(p)) return false;
		}
	}
	return true;
}
void game(){
	initgraph(480, 720);
	startinterface();
}

void popstar(point p) {
	drawPoint(p, BLACK);
	item[p.x][p.y] = 0;
}

void left() {
	bool isBlankCol;
	int count = 0;
	for (int i = 0; i < 10; i++) {
		isBlankCol = true;
		for (int j = 0; j < 10; j++) {
			if (item[i][j] != 0)
				isBlankCol = false;
		}
		if (isBlankCol) { count++; }
		else {
			for (int jj = 0; jj < 10; jj++) {
				item[i - count][jj] = item[i][jj];
			}
		}
	}
	for (int k = 10 - count; k < 10; k++) {
		for (int j = 0; j < 10; j++) {
			item[k][j] = 0;
		}
	}
}
void down() {
	for (int i = 0; i < 10; i++) {
		int d = 0;
		for (int j = 9; j >= 0; j--) {
			if (item[i][j] == 0)
				d++;
			else
				item[i][j + d] = item[i][j];
		}
		for (int k = 0; k < d; k++) {
			item[i][k] = 0;
		}
	}
}

void play() {
	MOUSEMSG m;
	queue<point> a;
	point p;
	int cnt;              //用于记录每次消除方块的个数,由此计算得分
	while (true){
		m = GetMouseMsg();
		if (m.mkLButton&&m.x >= 80 && m.x < (80 + pointWidth * 10) && m.y >= 120 && m.y <= (120 + pointWidth * 10)) {
			cnt = 0;
			p.x = (m.x - 80) / pointWidth;
			p.y = (m.y - 120) / pointWidth;
			if (item[p.x][p.y] != 0 && ifCanPop(p)) {
				a.push(p);
				while (!a.empty()) {
					point temp = a.front();
					for (int i = temp.x - 1; i <= (temp.x + 1) && i < 10; i++) {
						for (int j = temp.y - 1; j <= (temp.y + 1) && j < 10; j++) {
							if (item[i][j] != 0 && item[i][j] == item[temp.x][temp.y] && ((temp.x == i && temp.y != j) || (temp.x != i && temp.y == j))) {
								point pp(i, j);
								a.push(pp);
							}
						}
					}
					a.pop();
					popstar(temp);
					cnt++;
				}
				updateScore(cnt);
				down();
				left();
				gameinterface();
				if (isDeadlock()) {
					int leftStar = 0;
					for (int i = 0; i < 10; i++) {
						for (int j = 0; j < 10; j++) {
							if (item[i][j] != 0) leftStar++;
						}
					}
					if (leftStar <= 10)
						score = 2000 - leftStar * 5;
					updateScore(0);
					outtextxy(400, 700, _T("死锁"));
				}
			}
		}
	}
}

int main(){
	initgame();
	initgraph(480, 720);
	startinterface();
	gameinterface();
	play();
	_getch();
}

相关推荐

  • 用c++和easyx图形库做一个低配版扫雷游戏
  • Easyx图形库+C++做一个贪吃蛇小游戏 数据结构课程设计

符加说明:本程序使用了简单好用的easyx图形库:可以Easyx官网中下载安装,且Easyx官网提供的文档详细的介绍了各种函数的用法,很容易上手。

你可能感兴趣的:(小游戏)