最近使用 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;
}
就到這裏結束了,寫的很亂,大家湊合着看吧。如果有什麼問題的話,大佬們多提意見吧!!!感激!!!