9.C语言指针练习贪吃蛇

3 阅读3分钟

练习:写一个贪吃蛇

使用指针链表写一个贪吃蛇游戏,启动添加背景音乐,键盘上下左右箭头控制移动防线,每次随机出现食物,吃食物后可以增长一节,并记录分值,碰撞边界和碰撞自身会导致游戏结束。

代码:

#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                      #
#                              #
#                              #
#                              #
################################