c/c++實現簡單的貪吃蛇視覺化遊戲

說舊發表於2020-12-24

前言

在Visual Studio 2019開發環境上以C/C++為程式語言,運用easyx庫實現貪吃蛇遊戲邏輯的編寫與視覺化。


實驗要求與目標

實現貪吃蛇遊戲基本功能,螢幕上隨機出現一個“食物”,稱為豆子,上下左右控制“蛇”的移動,吃到“豆子”以後“蛇”的身體加長一點,得分增加,“蛇”碰到邊界或,蛇頭與蛇身相撞,蛇死亡,遊戲結束。為遊戲設計初始歡迎介面,遊戲介面,遊戲結束介面;

進行互動介面的設計,要有開始鍵、暫停鍵和停止退出的選項。對蛇吃到豆子進行分值計算,可以設定遊戲速度,遊戲音樂等擴充元素。


實驗思路

很簡單的思路:

  • 上下左右鍵控制蛇的移動;
  • 吃到豆子分數增加,前移動的速度也線性增加。
  • 空格鍵暫停遊戲。
  • 撞到牆或者咬到自己,遊戲結束

在這裡插入圖片描述


實驗過程與部分程式碼

實驗主要分為以下步驟:
1、蛇,豆子以及相關屬性的定義。
2、程式與鍵盤按鍵互動邏輯的實現。
3、移動蛇函式邏輯實現。
4、撞到牆或者咬到自己game over以及輔助功能的實現。
5、視覺化的實現。

相關核心程式碼

首先是蛇,豆子以及相關屬性的定義以及初始化:

這裡運用了結構體來存放相關變數,初始點設為負值是因為不知到為什麼每次豆子重新整理時(1,1)總會有豆子一閃而逝(應該是重新整理的問題)
typedef struct Point
{
	int x = -10;
	int y = -10;
}MYPOINT;

//蛇屬性
struct mySnake
{
	int num;	//蛇節
	MYPOINT xy[MAX];		//記錄蛇每一節座標
	char position;		//方向
}snake;

//食物
struct myFood
{
	MYPOINT foodCoord;		//食物座標
	int flag;			//食物是否存在的標記
	int eatGrade;		//獲取分數
}food;
//列舉
enum movPosition
{
	right_g,
	left_g,
	down_g,
	up_g
};

//過程
void initSnake();			//初始化
void drawSnake();		//畫蛇
void moveSnake();		//移動蛇
void keyDown();			//控制蛇移動
void initFood();			//初始化食物
void drawFood();			//畫食物
void eatFood();			//吃食物
void showGrade();		//顯示分數
int snakeDead();			//蛇死亡
int snakeSpeed();		//蛇速度

void initFood() {
	food.foodCoord.x = rand() % 80 * 10;
	food.foodCoord.y = rand() % 60 * 10;
	//cout << food.foodCoord.x << " " << food.foodCoord.y << endl;
	food.flag = 1;

	//不出現在蛇
	for (int i = 0; i < snake.num; i++) {
		if (food.foodCoord.x == snake.xy[i].x && food.foodCoord.y == snake.xy[i].y) {
			food.foodCoord.x = rand() % 80 * 10;
			food.foodCoord.y = rand() % 60 * 10;
		}
	}
}

void initSnake()		//初始化
{
	snake.xy[2].x = 0;
	snake.xy[2].y = 0;

	snake.xy[1].x = 10;
	snake.xy[1].y = 0;

	snake.xy[0].x = 20;
	snake.xy[0].y = 0;

	snake.num = 3;			//初始化蛇的節數
	snake.position = right_g;		//初始化蛇的方向

}


程式與鍵盤按鍵互動邏輯的實現:

enum movPosition
{
	right_g,
	left_g,
	down_g,
	up_g
};
void keyDown()		//控制蛇移動
{
	char key = _getch();
	if (key == 32) {
		while (_getch() != 32);
	}
	switch (key)
	{
	case 'w':
	case 'W':
	case 72:
		if (snake.position != down_g) {
			snake.position = up_g;
		}
		break;
	case 's':
	case 'S':
	case 80:
		if (snake.position != up_g) {
			snake.position = down_g;
		}
		break;
	case 'a':
	case 'A':
	case 75:
		if (snake.position != right_g) {
			snake.position = left_g;
		}
		break;
		break;
	case 'd':
	case 'D':
	case 77:
		if (snake.position != left_g) {
			snake.position = right_g;
		}
		break;
		break;
	}
}

移動蛇,吃到豆子函式邏輯實現:

void moveSnake()		//移動蛇;
{
	//移動
	for (int i = snake.num - 1; i > 0; i--) {
		snake.xy[i].x = snake.xy[i - 1].x;
		snake.xy[i].y = snake.xy[i - 1].y;
	}
	//蛇頭移動
	switch (snake.position)
	{
	case up_g:
		snake.xy[0].y -= 10;
		break;
	case down_g:
		snake.xy[0].y += 10;
		break;
	case left_g:
		snake.xy[0].x -= 10;
		break;
	case right_g:
		snake.xy[0].x += 10;
		break;
	default:
		break;
	}
}

void eatFood() {
	if (snake.xy[0].x == food.foodCoord.x && snake.xy[0].y == food.foodCoord.y) {
		food.flag = 0;
		snake.num++;
		food.eatGrade += 10;
	}
}


撞到牆或者咬到自己game over以及輔助功能的實現
int snakeDead() {
	if (snake.xy[0].x < 0 || snake.xy[0].x>800 || snake.xy[0].y < 0 || snake.xy[0].y>600) {
		MessageBox(hwnd, "game over", "撞牆", 0);
		return 1;
	}
	for (int i = 1; i < snake.num; i++) {
		if (snake.xy[0].x == snake.xy[i].x && snake.xy[0].y == snake.xy[i].y) {
			MessageBox(hwnd, "game over", "自殺", 0);
			return 1;
		}
	}
	return 0;
}

int snakeSpeed() {
	return 100 - (snake.num - 3) * 5;
}

easyx庫視覺化

EasyX Library for C++ 是針對 VC 的一套繪相簿,介面簡單易用,用起來很像 TC 的 graphics.h 繪圖。

畫蛇,畫豆子,以及出現相關提示的實現:

void drawSnake() {	//畫蛇
	for (int i = 0; i < snake.num; i++) {
		setlinecolor(WHITE);
		setfillcolor(BLACK);
		fillrectangle(snake.xy[i].x, snake.xy[i].y, snake.xy[i].x + 10, snake.xy[i].y + 10);
	}
}

void drawFood() {
	setfillcolor(BLACK);
	setlinecolor(WHITE);
	cout << food.foodCoord.x << " " << food.foodCoord.y << endl;
	fillrectangle(food.foodCoord.x, food.foodCoord.y, food.foodCoord.x + 10, food.foodCoord.y + 10);
}

void showGrade() {
	char grade[MAX] = "";
	sprintf(grade, "分數: %d", food.eatGrade);
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	outtextxy(650, 30, grade);

	char tip[MAX] = "";
	sprintf(tip,"暫停:按g空格鍵");
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	outtextxy(630, 100, tip);

	char tip1[MAX] = "";
	sprintf(tip1, "操控:w,a,s,d或上下左右鍵");
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	outtextxy(580, 170, tip1);
}


主函式方法

int main() {
	srand(((unsigned int)time(NULL)));
	hwnd = initgraph(800, 600);		初始化介面
	setbkcolor(WHITE);		//設定背景顏色
	cleardevice();			//重新整理
	initSnake();
	LOGFONT f;//字型樣式指標
	gettextstyle(&f);					//獲取字型樣式
	_tcscpy(f.lfFaceName, _T("宋體"));	//設定字型為宋體
	f.lfQuality = ANTIALIASED_QUALITY;    // 設定輸出效果為抗鋸齒  
	settextstyle(&f);                     // 設定字型樣式
	settextcolor(BLACK);


	while (1) {
		cleardevice();
		if (food.flag == 0) {
			initFood();			//初始化食物
		}
		drawFood();			//畫食物
		drawSnake();		//畫蛇
		moveSnake();		//移動蛇
		eatFood();			//吃食物
		showGrade();		//顯示分數
		if (snakeDead()) {
			break;
		}
		if (_kbhit()) {
			keyDown();
		}
		Sleep(snakeSpeed());		//蛇的速度
	}
	_getch();
	closegraph();
	system("pause");
	return 0;
}


實驗結果

總體介面:
在這裡插入圖片描述


動態演示:

實際
實際運動不會有痕跡,應該是gif格式的問題。


謝謝觀看~

相關文章