最近使用 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;
}
就到这里结束了,写的很乱,大家凑合着看吧。如果有什么问题的话,大佬们多提意见吧!!!感激!!!