運用c++與easyx圖形庫實現消滅星星最基本的消除功能、掉落功能以及判斷死鎖的方式

運用c++與easyx圖形庫實現消滅星星最基本的消除功能、掉落功能以及判斷死鎖的方式

寫在前面的話

此程序只實現了遊戲的小部分內容,沒有華麗的外觀與消除特效

消滅星星是一款前些年十分流行的手機遊戲,玩法簡單卻非常容易讓人上癮。

《消滅星星》是由Brian Baek公司開發的一款消除類休閒娛樂手機遊戲,於2014年發行,遊戲大小爲3.8M。本作特點是易上手,點擊兩個或兩個以上顏色相同的方塊即可消除,沒有時間限制。
                                                                                                                       ----百度百科

  1. 實現遊戲的初始狀態:

遊戲的初始狀態如圖:
遊戲的初始狀態
遊戲關卡結束
遊戲關卡結束

再附上我們程序最終實現的效果

遊戲的初始狀態
遊戲的初始狀態
遊戲的關卡結束狀態:
遊戲關卡結束

由圖可知:遊戲區域爲一個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<iostream>
#include<graphics.h>
#include<conio.h>
#include<time.h>
#include<queue>
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();
}

相關推薦

符加說明:本程序使用了簡單好用的easyx圖形庫:可以Easyx官網中下載安裝,且Easyx官網提供的文檔詳細的介紹了各種函數的用法,很容易上手。

發佈了17 篇原創文章 · 獲贊 27 · 訪問量 2627
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章