貪喫蛇遊戲簡化版


最近使用 EasyX 圖形庫在寫貪喫蛇,由於是第一次使用加之時間太緊,成品極爲簡陋,望各路大神輕噴。

基本思路

貪喫蛇問題作爲計算機編程的熱門問題,大部分人應該都有所接觸。基本的思路其實就在於模塊化蛇的各種執行步驟,還有就是注意邊界情況的判斷。由於在很多資料中都有詳細說明,不再贅述。

具體實現

下面是代碼的具體實現,編譯環境爲 Visual Studio 2017 Community

建立基本框架

typedef struct node
{
   int x;
   int y;
   struct node *next;
}snake;
struct Position
{
   int x;
   int y;
}position;//用於確定方向是否相反
snake *head,*q,*food;

void init();//初始化
void draw_wall();//生成牆
void move();//移動
void buy();//生成食物
void end_game();//結束函數
int check_game();
void snake_dir();//確定下一步的方向
int eat_self();

int main()
{
   init();
   while (check_game())
   {
   	move();
   }
   end_game();
   return 0;
}

地圖與蛇身的初始化

初始化蛇身的時候要注意到不要將尾節點與頭節點混淆,以免在以後的操作中出現不便。

void init()
{
	initgraph(640, 480);
	draw_wall();
	snake *tail;
	tail = (snake*)malloc(sizeof(snake));				//申請動態內存並初始化tail節點
	tail->x = 5;
	tail->y = 5;
	position.x = 1;
	position.y = 0;
	tail->next = NULL;
	for (int i = 1; i <= 4; i++)			//此處初始化蛇身
	{
		head = (snake*)malloc(sizeof(snake));
		head->next = tail;
		head->x = 5 + i;
		head->y = 5;
		tail = head;
	}
	while (tail != NULL)			//完善鏈表
	{
		setcolor(BLUE);
		rectangle(tail->x * 10 - 4, tail->y * 10 - 4, tail->x * 10 + 4, tail->y * 10 + 4);
		tail = tail->next;
	}
	buy();
}

鍵盤讀入與方向確定

void snake_dir()
{
	if (_kbhit())			//讀入鍵盤輸入
		switch (_getch())			//在每次的輸入都要檢查輸入的方向與捨得方向是否相反
		{							//如果相反的話則方向不變
		case 'a':
			if (position.x != 1 && position.y != 0)
			{
				position.x = -1;
				position.y = 0;
			}
			break;
		case 'd':
			if (position.x != -1 && position.y != 0)
			{
				position.x = 1;
				position.y = 0;
			}
			break;
		case 'w':
			if (position.x != 0 && position.y != 1)
			{
				position.x = 0;
				position.y = -1;
			}
			break;
		case 's':
			if (position.x != 0 && position.y != -1)
			{
				position.x = 0;
				position.y = 1;
			}
			break;
		}
}

食物生成

void buy()
{
	snake *temp_food;
	temp_food = (snake*)malloc(sizeof(snake));
	srand((unsigned)time(NULL));
	temp_food->x = rand() % 62 + 2;		//注意避免生成在牆上
	temp_food->y = rand() % 46 + 2;
	q = head;
	while (q->next != NULL)			//判斷是否與蛇身重疊
	{
		if (q->x == temp_food->x&&q->y == temp_food->y)
		{
			buy();
		}
		q = q->next;
	}
	setcolor(WHITE);
	circle(temp_food->x * 10, temp_food->y * 10, 4);
	food = temp_food;
}

判斷是否撞牆

int check_game()			//是否撞牆
{
	if (getpixel(head->x * 10, head->y * 10) == RED)
		return 0;
	else
		return 1;
}

蛇的移動

因爲牆,蛇與食物的顏色不盡相同,所以可以通過檢查每個位置的點的顏色來判斷是否碰觸東西。

void move()
{
	Sleep(100);
	snake_dir();			//判斷目前前進的方向
	if (getpixel((head->x + position.x) * 10 + 4, (head->y + position.y) * 10 + 4) == BLUE)
		end_game();		//是否咬到自己
	snake * nexthead;
	nexthead = (snake*)malloc(sizeof(snake));
	nexthead->x = head -> x + position.x;
	nexthead->y = head -> y + position.y;
	if (nexthead->x == food->x && nexthead->y == food->y)		//判斷是否喫到了食物
	{
		nexthead->next = head;
		head = nexthead;
		q = head;
		setcolor(BLACK);
		circle(food->x * 10, food->y * 10, 4);
		while (q->next != NULL)		//此處是尋找尾節點。實測會有卡頓,
			q = q->next;			//如果使用雙向鏈表則不會有此問題(但是我懶)
		rectangle(q->x * 10 - 5, q->y * 10 - 5, q->x * 10 + 5, q->y * 10 + 5);	//將尾變成黑色
		buy();			//放食物函數
	}
	else
	{
		nexthead->next = head;
		head = nexthead;
		q = head;
		while (q->next->next != NULL)			//後邊沒什麼可說的,正常畫蛇
		{
			setcolor(BLUE);
			rectangle(q->x * 10 - 4, q->y * 10 - 4, q->x * 10 + 4, q->y * 10 + 4);
			q = q->next;
		}
		setcolor(BLACK);
		rectangle(q->next->x * 10 - 4, q->next->y * 10 - 4, q->next->x * 10 + 4, q->next->y * 10 + 4);
		free(q->next);
		q->next = NULL;
	}
}

結束遊戲

這個部分存在 bug ,博主並不能成功輸出 drawtext 函數,希望有大神可以幫忙解釋一下。

void end_game()
{
	RECT r = { 0, 0, 640, 480 };
	drawtext(_T("Game Over"), &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	_getch();
	closegraph();
}

完整代碼

#include<graphics.h>
#include<conio.h>
#include<time.h>
#include<math.h>

typedef struct node
{
	int x;
	int y;
	struct node *next;
}snake;
struct Position
{
	int x;
	int y;
}position;//用於確定方向是否相反
snake *head,*q,*food;

void init();//初始化
void draw_wall();//生成牆
void move();//移動
void buy();//生成食物
void end_game();//結束函數
int check_game();
void snake_dir();//確定下一步的方向

void init()
{
	initgraph(640, 480);
	draw_wall();
	snake *tail;
	tail = (snake*)malloc(sizeof(snake));
	tail->x = 5;
	tail->y = 5;
	position.x = 1;
	position.y = 0;
	tail->next = NULL;
	for (int i = 1; i <= 4; i++)//初始長度爲4
	{
		head = (snake*)malloc(sizeof(snake));
		head->next = tail;
		head->x = 5 + i;
		head->y = 5;
		tail = head;
	}
	while (tail != NULL)
	{
		setcolor(BLUE);
		rectangle(tail->x * 10 - 4, tail->y * 10 - 4, tail->x * 10 + 4, tail->y * 10 + 4);
		tail = tail->next;
	}
	buy();
}

void draw_wall()
{
	for (int i = 1; i <= 64; i++)
	{
		setcolor(RED);
		rectangle(i * 10 - 10, 0, i * 10, 10);
		rectangle(i * 10 - 10, 470, i * 10, 480);
	}
	for (int i = 1; i <= 48; i++)
	{
		setcolor(RED);
		rectangle(0 , i * 10 - 10, 10, i * 10);
		rectangle(630, i * 10 - 10, 640, i * 10);
	}
}

void snake_dir()
{
	if (_kbhit())
		switch (_getch())
		{
		case 'a':
			if (position.x != 1 && position.y != 0)
			{
				position.x = -1;
				position.y = 0;
			}
			break;
		case 'd':
			if (position.x != -1 && position.y != 0)
			{
				position.x = 1;
				position.y = 0;
			}
			break;
		case 'w':
			if (position.x != 0 && position.y != 1)
			{
				position.x = 0;
				position.y = -1;
			}
			break;
		case 's':
			if (position.x != 0 && position.y != -1)
			{
				position.x = 0;
				position.y = 1;
			}
			break;
		}
}

void move()
{
	Sleep(100);
	snake_dir();
	if (getpixel((head->x + position.x) * 10 + 4, (head->y + position.y) * 10 + 4) == BLUE)
		end_game();
	snake * nexthead;
	nexthead = (snake*)malloc(sizeof(snake));
	nexthead->x = head -> x + position.x;
	nexthead->y = head -> y + position.y;
	if (nexthead->x == food->x && nexthead->y == food->y)
	{
		nexthead->next = head;
		head = nexthead;
		q = head;
		setcolor(BLACK);
		circle(food->x * 10, food->y * 10, 4);
		while (q->next != NULL)
		{
			/*setcolor(BLUE);
			rectangle(q->x * 10 - 5, q->y * 10 - 5, q->x * 10 + 5, q->y * 10 + 5);*/
			q = q->next;
		}
		rectangle(q->x * 10 - 5, q->y * 10 - 5, q->x * 10 + 5, q->y * 10 + 5);
		buy();
	}
	else
	{
		nexthead->next = head;
		head = nexthead;
		q = head;
		while (q->next->next != NULL)
		{
			setcolor(BLUE);
			rectangle(q->x * 10 - 4, q->y * 10 - 4, q->x * 10 + 4, q->y * 10 + 4);
			q = q->next;
		}
		setcolor(BLACK);
		rectangle(q->next->x * 10 - 4, q->next->y * 10 - 4, q->next->x * 10 + 4, q->next->y * 10 + 4);
		free(q->next);
		q->next = NULL;
	}
}

void buy()
{
	snake *temp_food;
	temp_food = (snake*)malloc(sizeof(snake));
	srand((unsigned)time(NULL));
	temp_food->x = rand() % 62 + 2;
	temp_food->y = rand() % 46 + 2;
	q = head;
	while (q->next != NULL)
	{
		if (q->x == temp_food->x&&q->y == temp_food->y)
		{
			buy();
		}
		q = q->next;
	}
	setcolor(WHITE);
	circle(temp_food->x * 10, temp_food->y * 10, 4);
	food = temp_food;
}

int check_game()
{
	if (getpixel(head->x * 10, head->y * 10) == RED)
		return 0;
	else
		return 1;
}

void end_game()
{
	RECT r = { 0, 0, 640, 480 };
	drawtext(_T("Game Over"), &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	_getch();
	closegraph();
}
int main()
{
	init();
	while (check_game())
	{
		move();
	}
	end_game();
	return 0;
}

就到這裏結束了,寫的很亂,大家湊合着看吧。如果有什麼問題的話,大佬們多提意見吧!!!感激!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章