教你实现简单的贪吃蛇------C语言版

前言

贪吃蛇相信大家小时候都玩过,那么你有没有想过有一天你也能自己编程实现它呢?今天我就在这里教大家用C语言,通过自顶向下逐步求精的方法,实现一个简易的贪吃蛇。

准备工作

(首先心里要有点X数)既然是简易的,那么没有高大上的画面,我们实现的一定是字符版。为了方便我们之后的思考,我们先把最基础的几个参数和初始参数定下来。

#include<stdio.h>
#include<conio.h>

#define SNAKE_MAX_LENGTH 20
#define SNAKE_HEAD 'H'
#define SNAKE_BODY 'X'
#define BLANK_CELL ' '
#define WALL_CELL '*'
#define SNAKE_FOOD '$'
#define stay 'S'

char map[12][12] =
{ "************",
"*XXXXH     *",
"*          *",
"*          *",
"*          *",
"*          *",
"*          *",
"*          *",
"*          *",
"*          *",
"*          *",
"************"
};
int snakeX[SNAKE_MAX_LENGTH] = { 5,4,3,2,1 };
int snakeY[SNAKE_MAX_LENGTH] = { 1,1,1,1,1 };
int snake_length = 5;

对没错,那个二元字符组就是游戏界面,第二行那一条就是我们的蛇了。

一条会动、会死的蛇

秉着由简入繁的原则,我们先来实现最基本的功能,就是一条能够接受我们命令(WASD)动起来,而且撞到墙或者自己会死的蛇。让我们先敲下伪代码。

输出字符矩阵
    WHILE not 游戏结束 DO
        ch=输入的字符
        move(ch);
        输出字符矩阵
    END WHILE
    输出 Game Over!!! 

然后按照伪代码敲下main函数,以及我们秉着“自顶向下、逐步求精”的原则自己写的move函数以及判断死亡的函数。这里用到了两个小技巧,一个是getch()这个函数,可以让程序不需要每次输入后再敲个回车;另一个是p这个值(其实就是布尔值)来帮助记录蛇的死活。

void print(char map[12][12]) {

    int i;
    for (i = 0; i < 12; i++) {
        int j;
        for (j = 0; j < 12; j++) {
            printf("%c", map[i][j]);
        }
        printf("\n");
    }
}

int hit_it_self(int X[], int Y[]) {
    int i;
    for(i = 2; i < snake_length; i++)
        if (X[0] == X[i] && Y[0] == Y[i]) return 0;
    return 1;
}

int hit_the_wall(int X[], int Y[]) {
    if (X[0] == 0 || X[0] == 11) return 0;
    if (Y[0] == 0 || Y[0] == 11) return 0;
    return 1;
}

void move(int x) {

    map[snakeY[snake_length - 1]][snakeX[snake_length - 1]] = ' ';
    map[snakeY[0]][snakeX[0]] = 'X';
    int i;
    tempX = snakeX[snake_length - 1];
    tempY = snakeY[snake_length - 1];
    for (i = 1; i < snake_length; i++) {
        snakeX[snake_length - i] = snakeX[snake_length - i - 1];
        snakeY[snake_length - i] = snakeY[snake_length - i - 1];
    }
    switch (x) {
    case 'A':
        snakeX[0] = snakeX[0] - 1;
        break;
    case 'W':
        snakeY[0] = snakeY[0] - 1;
        break;
    case 'D':
        snakeX[0] = snakeX[0] + 1;
        break;
    case 'S':
        snakeY[0] = snakeY[0] + 1;
        break;
    }
    map[snakeY[0]][snakeX[0]] = 'H';
}

int main() {
    print(map);
    int p = 1;
    char movement;
    while (p>0) {
        movement = getch();
        int x = movement;
        move(x);
        int p1 = hit_it_self(snakeX, snakeY);
        int p2 = hit_the_wall(snakeX, snakeY);
        if (p1 == 0 || p2 == 0) p = 0;
        else {
            system("cls");//清屏
            print(map);
        }
    }
    printf("GAME OVER");
}

放食物,吃食物

贪吃蛇的另一功能就是吃食物,然后变长。这里有两个难点:一个就是放置食物需要随机,而C语言的随机是随机数表法生成的伪随机,所以我们这里就需要一点小技巧,根据启动程序的时间来决定随机的seed;另一个则是吃食物后我要实现立刻再生成一个食物,以及蛇的身体长度加一。下面就是相关的函数。

int food = 0;
int foodX, foodY;
int tempX, tempY;

void set_food(char map[12][12]){
     srand((int)time(0));
     foodX = (int)(rand()%10) + 1;
     foodY = (int)(rand()%10) + 1;
     int judge = 1;
     int i;
     for(i =0; i < snake_length; i++){
        if(snakeX[i] == foodX && snakeY[i] == foodY){
            judge = 0;
            break;
        }
     }
     if(judge == 1){
        map[foodY][foodX] = '$';
        food  = 1;
        //return;
     }
     //if(judge == 0) set_food(map);如果迭代就会偶尔导致程序崩溃。
}

void eat(char map[12][12]){
    snake_length++;
    snakeX[snake_length - 1] = tempX;
    snakeY[snake_length - 1] = tempY;
    map[tempY][tempX] = 'X';
    food = 0;
}

自己会动

接下来就是最后的部分,我需要蛇能够自己动起来。就是说,当我没有输入的时候,蛇要自己沿着原方向继续走。这里我们用了两个函数,一个是kbhit()来解决输入的问题,另一个则是clock()或者sleep()来解决自己动的问题,我这里选择的是前者。其中kbhit的功能是有输入则返回输入值,没有则返回0;clock()则是返回程序执行的时间。
具体代码如下:(这里笔者就将整个main函数再重新敲一遍了。)

char my_kbhit(char movement){
    if(kbhit()){
        movement = getch();
        return movement;
    }
    else return movement;
}

int main() {
    int game_time;
    print(map);
    int p = 1;
    char movement = stay;

    while (p>0) {
        game_time = clock();
        if(game_time % (1000 - 50 * snake_length)  == 0) {
            movement = my_kbhit(movement);

        while(food == 0){
            if(snake_length <= 20){
            set_food(map);
            }
        }

        int x = movement;
        move(x);
        int p1 = hit_it_self(snakeX, snakeY);
        int p2 = hit_the_wall(snakeX, snakeY);
        if (p1 == 0 || p2 == 0) p = 0;
        else {
            if(snakeX[0] == foodX && snakeY[0] == foodY) eat(map);
            system("cls");
            print(map);
        }
    }}
    if(snake_length == 20){
        system("cls");
        printf("YOU WIN");
        return;
    }
    printf("GAME OVER");
}

这里为了增加难度,我让被模的数随蛇的长度增加而减少,从而实现了蛇越长动得越快来给游戏增加乐趣。

后记

学会了贪吃蛇,其实很多小游戏的字符版就都可以实现了,比如 flappy bird、 或者一个简单的“雷电”。当然读者也可以自如发挥来美化这个程序,比如利用 system 的种种函数来设计边框,背景颜色,亦或者想个办法让打印的时候不那么闪,这些就留给读者进一步自由发挥了。
总之目前的效果就是这样啦。
这里写图片描述

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