练习:写一个贪吃蛇
使用指针链表写一个贪吃蛇游戏,启动添加背景音乐,键盘上下左右箭头控制移动防线,每次随机出现食物,吃食物后可以增长一节,并记录分值,碰撞边界和碰撞自身会导致游戏结束。
代码:
#include <stdio.h>
#include <windows.h>
#include <time.h>
#include <conio.h>
struct Node {
int x;
int y;
struct Node * prev;
struct Node * next;
};
int WIDTH, HEIGHT;
int speedInterval;
int flushMs;
int gameOver, score;
enum Direct dir;
struct Node *snake = NULL;
struct Node *food = NULL;
enum Direct {
up,
down,
left,
right
};
void initSetup(){
dir = up;
WIDTH = 15;
HEIGHT = 30;
flushMs = 200;
score = 0;
gameOver = 0;
speedInterval = 2;
}
short isSnake(int x, int y){
struct Node * temp = NULL;
temp = snake;
while (temp!=NULL){
// printf("x:%d, y:%d, node->x:%d, node->y:%d\n", x, y, temp->x, temp->y);
if (temp->x == x && temp->y == y){
// Sleep(20000);
return (short)1;
}
temp = temp->next;
}
return (short)0;
}
void genFood(){
if (food!=NULL){
free(food);
food = NULL;
}
int x = (rand() % WIDTH)+1;
int y = (rand() % HEIGHT)+1;
while(isSnake(x, y)){
x = (rand() % WIDTH)+1;
y = (rand() % HEIGHT)+1;
}
food = (struct Node *)malloc(sizeof(struct Node));
food->x = x;
food->y = y;
}
short isFood(int x, int y){
if (food!=NULL && food->x == x && food->y == y){
return (short)1;
}
return (short)0;
}
void draw(){
for(int i=0; i<=WIDTH+1; i++){
for (int j=0; j<=HEIGHT+1; j++){
if (i==0 || j==0 || i==WIDTH+1 || j==HEIGHT+1){
printf("#");
} else if(isSnake(i, j)){
printf("O");
} else if(isFood(i, j)){
printf("F");
} else {
printf(" ");
}
}
if (i==0){
printf(" 分数:%d", score);
}
if (i == 5 && gameOver){
printf(" GAMEOVER");
}
printf("\n");
}
}
// 初始化
void snakeInit(){
if (snake == NULL){
struct Node * node = (struct Node*)malloc(sizeof(struct Node));
snake = node;
snake->x = 10;
snake->y = 10;
snake->prev = NULL;
snake->next = NULL;
}
}
// 运动
void snakeRun(){
int start_x = snake->x;
int start_y = snake->y;
switch (dir)
{
case up:
start_x -= 1;
break;
case down:
start_x += 1;
break;
case left:
start_y -= 1;
break;
case right:
start_y += 1;
break;
default:
break;
}
if (isSnake(start_x, start_y)){
gameOver = 1;
return;
}
// 吃食物会长一段
if (isFood(start_x, start_y)){
// 保持原身体不变,加一个新的头
struct Node * node = (struct Node*)malloc(sizeof(struct Node));
node->x = start_x;
node->y = start_y;
node->next = snake;
node->prev = NULL;
snake->prev = node;
snake = node;
score += 10;
genFood();
} else {
// 运动时将尾部变成头即可
if (snake->next == NULL){
snake->x = start_x;
snake->y = start_y;
} else {
struct Node *last = NULL;
last = snake;
while (last->next != NULL){
last = last->next;
}
last->prev->next = NULL;
last->x = start_x;
last->y = start_y;
last->prev = NULL;
last->next = snake;
snake->prev = last;
snake = last;
}
if (start_x < 1 || start_x > WIDTH || start_y <1 || start_y > HEIGHT){
gameOver = 1;
}
}
}
// 添加一节
void snakeAppend(int x, int y){
if (snake == NULL){
snakeInit();
}
struct Node *node = (struct Node*)malloc(sizeof(struct Node));
node->x = x;
node->y = y;
node->prev = NULL;
node->next = snake;
snake->prev = node;
snake = node;
}
// 监控键盘输入,上下左右
void kbInput(){
if(_kbhit()){
int ch = _getch();
// printf("输入了按键:%c, %d\n", ch, ch);
// Sleep(2000);
if (ch == 224){
ch = _getch();
switch (ch) {
case 72:
if (dir!=down){
dir = up;
}
break;
case 80:
if (dir!=up){
dir = down;
}
break;
case 75:
if (dir!=right){
dir = left;
}
break;
case 77:
if (dir!=left){
dir = right;
}
break;
default:
break;
}
// printf("%d", ch);
// Sleep(2000);
}
}
}
void clearMem(){
struct Node * temp = NULL;
while (snake!=NULL){
temp = snake->next;
free(snake);
snake = temp;
}
snake = NULL;
if (food!=NULL){
free(food);
food = NULL;
}
}
int main(){
srand(time(NULL));
initSetup();
snakeInit();
genFood();
PlaySound(".\\fancuo.wav", NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);
int flagCount = 0;
while(!gameOver){
kbInput();
Sleep(flushMs);
system("cls");
flagCount += 1;
if (flagCount >= speedInterval){
snakeRun();
flagCount = 0;
}
draw();
}
clearMem();
return 0;
}
打包:
gcc .\snake.c -o .\snake.exe -lwinmm
运行结果:
################################ 分数:230
# O F #
# O #
# O #
# O #
# O O # GAMEOVER
# O O #
# O O #
# O O #
# O O #
# O O #
# O O #
# OOOOO #
# #
# #
# #
################################