贪吃蛇小游戏(C语言版)

贪吃蛇是一款经典的小游戏。玩家可以使用设置好的键操控蛇吞下食物使身体变长。当蛇头撞到蛇身或者障壁时游戏结束。

1、对整个源代码加注释,对每个函数和变量分析注释,明确标识出二维数组canvas中每个取值的意义游戏操作的键及对应的功能等,初始代码如下:

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

#define High 20       //二维数组的行最大值
#define Width 30      //二维数组的列最大值


int moveDirection;     //不同的值表示蛇的不同的移动方向
int food_x = 3, food_y = 5;           //食物的初始行坐标,列坐标
int canvas[High][Width] = { 0 };      //定义了一个High行Width列的二维数组用于贪吃蛇游戏的图像建立,初始值均赋值为0
void gotoxy(int x, int y)              //声明于<conio.h> 中的一个函数,将光标移到(x,y)的位置,横向为 X 轴,纵向为 Y 轴
{
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);    //结构体指针变量,这个指针赋值变成一个windows输出的句柄
    COORD pos;                     //结构体变量位置,其中包含x,y
    pos.X = x;                   //光标在命令行中即将偏移的水平单位
    pos.Y = y;                   //光标在命令行中即将偏移的竖直单位
    SetConsoleCursorPosition(handle, pos);   //来源于<windows.h>的头文件,偏移的光标位置
}

void moveSnakeByDirection()        //控制蛇的移动
{
    int i, j;         //i用于行的自增,j用于列的自增
    for (i = 1; i < High - 1; i++)    //行自增
        for (j = 1; j < Width - 1; j++) //列自增
            if (canvas[i][j] > 0)    //用于寻找蛇的位置
                canvas[i][j]++;       //蛇的二维数组值自增,即让蛇身前进一步

    int oldTail_i, oldTail_j, oldHead_i, oldHead_j;  //四个整型变量,旧的身体行位置,旧的身体列位置,旧的头行位置,旧的头列位置
    int max = 0;        //int型变量max,赋值为0,用于寻找蛇尾

    for (i = 1; i < High - 1; i++)           //行自增
        for (j = 1; j < Width - 1; j++)    //列自增
            if (canvas[i][j] > 0)          //判断二维数组值是否大于0,若是,说明为蛇身,蛇体,执行if语句
            {
                if (max < canvas[i][j])    //选出二维数组中值最大的位置,即为蛇尾的位置,并确定行,列的位置
                {
                    max = canvas[i][j];     //将max赋值为二维数组中的最大值,即蛇尾的值
                    oldTail_i = i;           //确定旧蛇尾的行标
                    oldTail_j = j;           //确定旧蛇尾的列标
                }
                if (canvas[i][j] == 2)   //判断二维数组值是否为2,确定旧蛇头的位置
                {
                    oldHead_i = i;        //确定旧蛇头的行标
                    oldHead_j = j;        //确定旧蛇头的列标
                }
            }

    int newHead_i, newHead_j;    //两个int型变量,表示新蛇头位置的行标,新蛇头位置的列标

    if (moveDirection == 1)      //向上转时,蛇头位置的改变
    {
        newHead_i = oldHead_i - 1;    //新蛇头的行标=旧蛇头行标-1
        newHead_j = oldHead_j;        //新蛇头列标=旧蛇头列标
    }
    if (moveDirection == 2)       //向下转时,蛇头位置的改变
    {
        newHead_i = oldHead_i + 1;   //新蛇头的行标=旧蛇头行标+1
        newHead_j = oldHead_j;        //新蛇头列标=旧蛇头列标
    }
    if (moveDirection == 3)       //向左转时,蛇头位置的改变
    {
        newHead_i = oldHead_i;    //新蛇头行标=旧蛇头行标
        newHead_j = oldHead_j - 1; //新蛇头的列标=旧蛇头列标-1
    }
    if (moveDirection == 4)        //向右转时,蛇头位置的改变
    {
        newHead_i = oldHead_i; //新蛇头行标=旧蛇头行标
        newHead_j = oldHead_j + 1;//新蛇头的列标=旧蛇头列标+1
    }

    if (canvas[newHead_i][newHead_j] == -2)    //判断二维数组值是否为2,即判断是否吃到食物,若吃到该位置二维数组的值变为0,蛇变长
    {
        canvas[food_x][food_y] = 0;
    }
    else                                      //否则,旧尾巴的位置值变为0,蛇长度不变
        canvas[oldTail_i][oldTail_j] = 0;


    if (canvas[newHead_i][newHead_j] > 0 || canvas[newHead_i][newHead_j] == -1)   //判定是否撞到边界或者身体
    {
        printf("游戏失败!\n");     //打印游戏失败
        Sleep(2000);                //程序休眠2s
        system("pause");           //包含于<stdlib.h>的头文件中,执行暂停批处理文件的处理并显示消息的命令
        exit(0);                   //正常退出
    }
    else
        canvas[newHead_i][newHead_j] = 1;  //未撞到边界时和身体时的头的新数组位置赋值为1,蛇正常向新位置移动
}

void startup()               //设定游戏开始时的场景
{
    int i, j;                 //i用于行的自增,j用于列的自增    


    for (i = 0; i < High; i++)         //设置边界:垂直的边界,将边界位置的值定为-1
    {
        canvas[i][0] = -1;             //设置左边界,将边界位置值赋为-1
        canvas[i][Width - 1] = -1;    //设置右边界,将边界位置值赋为-1
    }
    for (j = 0; j < Width; j++)         //设置边界:水平的边界,将边界位置的值定为-1
    {
        canvas[0][j] = -1;               //设置上边界,将边界位置值赋为-1
        canvas[High - 1][j] = -1;          //设置下边界,将边界位置值赋为-1
    }


    canvas[High / 2][Width / 2] = 1;      //将边界框内的中心位置赋值为1,定为蛇头出现的位置

    for (i = 1; i <= 4; i++)              //将蛇头左边的四个坐标赋值为i+1,定为蛇身出现的位置
        canvas[High / 2][Width / 2 - i] = i + 1;

    moveDirection = 4;               //将移动方向赋值为4,表示蛇初始移动方向为向右移动
    canvas[food_x][food_y] = -2;      //将食物出现的位置的二维数组值赋值为-2,定为食物出现的位置
}

void show()      //将蛇头蛇身和边界可视化
{
    gotoxy(0, 0);                          //将光标移到左上角(0,0)的位置,横向为 X 轴,纵向为 Y 轴
    int i, j;                              //i用于行的自增,j用于列的自增
    for (i = 0; i < High; i++)             //行循环
    {
        for (j = 0; j < Width; j++)          //列循环
        {
            if (canvas[i][j] == 0)          //二维数组值为0的位置打印空格
                printf(" ");
            else if (canvas[i][j] == -1)      //二位数组值为-1的位置打印边界
                printf("#");
            else if (canvas[i][j] == 1)        //二位数组值为1的位置打印蛇头
                printf("@");
            else if (canvas[i][j] > 1)         //二维数组值大于一的位置打印蛇身
                printf("*");
            else if (canvas[i][j] == -2)       //二位数组值为-2的位置打印食物
                printf("$");
        }
        printf("\n");          //每行打印一个回车用于换行
    }
    Sleep(500);        //程序暂停休眠500ms
}

void updateWithoutInput()                //未输入转向时的自动偏移,沿着蛇头的方向移动
{
    moveSnakeByDirection();
}

void updateWithInput()               //根据输入的按键进行转向
{
    char input;     //字符型变量,赋值为读取到的键盘输入值,用于转向的判定
    if (_kbhit())   //_kbhit()是<conio.h>中的函数,判定检查当前是否有键盘输入,若有则返回一个非0值,执行if语句;否则返回0,不执行if语句
    {
        input = _getch();    //将input赋值为_getch()从控制台中获取的字符

        if (input == 'a')              //若input=a,将蛇偏移方向变量赋值为3,执行偏移蛇函数,即蛇向左转,直行
        {
            moveDirection = 3;
            moveSnakeByDirection();
        }
        else if (input == 'd')          //若input=d,将蛇偏移方向变量赋值为4,执行偏移蛇函数,即蛇向右转,直行
        {
            moveDirection = 4;
            moveSnakeByDirection();
        }
        else if (input == 'w')           //input=w,将蛇偏移方向变量赋值为1,执行偏移蛇函数,即蛇向上转,直行
        {
            moveDirection = 1;
            moveSnakeByDirection();
        }
        else if (input == 's')            //input=s,将蛇偏移方向变量赋值为2,执行偏移蛇函数,即蛇向下转,直行
        {
            moveDirection = 2;
            moveSnakeByDirection();
        }
    }
}

int main()  //主函数
{
    startup();      //设定游戏开始时的场景
    while (1)       //死循环
    {
        show();      //将蛇头蛇身和边界可视化
        updateWithoutInput(); //未输入偏转方向时蛇的移动方向
        updateWithInput();    //人为输入偏转方向时的蛇的移动方向
    }
    return 0;   //程序正常退出,返回值为0;

2、修改程序,蛇的表示以姓首字母为头,名的首字母为身,初始长度为5;食物表示:用学号最后一位表示。对应代码区修改如下:

void show()
{
    gotoxy(0, 0);
    int i, j;
    for (i = 0; i < High; i++)
    {
        for (j = 0; j < Width+12; j++)
        {    if (i == 1 && j == Width+2)
                printf("Score:%3d", score);
                if (i == 2 && j == Width+2)
                    printf("Min:%5d", min);
            if (canvas[i][j] == 0&&j<Width+1)
                printf(" ");
            else if (canvas[i][j] == -1)
                printf("#");
            else if (canvas[i][j] == 1)
                printf("Z");
            else if (canvas[i][j] > 1)
                printf("T");
            else if (canvas[i][j] == -2)
                printf("6");
            else if (canvas[i][j] == -3)
                printf("m");
            else if (canvas[i][j] == -4)
            printf("s");
           
        }
        printf("\n");
    }
  
    Sleep(500);
}

3、初始小蛇移动方向改为向下移动。修改对应代码区,修改moveDirection参数如下:

void startup()
{
    int i, j;

   
    for (i = 13; i < 18; i++)
        canvas[3][i] = -1;
    for (i = 20; i < 25; i++)
        canvas[3][i] = -1;
    for (i = 4; i < 9; i++)
    {
        canvas[i][15] = -1;
        canvas[i][22] = -1;
    }
    for (i = 0; i < High; i++)
    {
        canvas[i][0] = -1;
        canvas[i][Width - 1] = -1;
        
    }
    for (j = 0; j < Width; j++)
    {
        canvas[0][j] = -1;
        canvas[High - 1][j] = -1;
    }
    for (j = Width+1; j < Width + 12; j++)
    {
        canvas[0][j] = -1;
        canvas[3][j] = -1;
    }
    for (i = 1; i < 3; i++)
    {
        canvas[i][Width+1] = -1;
        canvas[i][Width + 11] = -1;
    }

    canvas[High / 2][Width / 2] = 1;

    for (i = 1; i <= 4; i++)
        canvas[High / 2-i][Width / 2 ] = i + 1;

    moveDirection = 2;      //设置初始移动方向
    canvas[food_x][food_y] = -2;
    canvas[slow_x][slow_y] = -4;
    canvas[min_x][min_y] = -3;
}

4.修改程序每次吃完食物,蛇身长度加1,食物随机再一次出现。

修改void moveSnakeByDirection()部分代码,对应代码修改后对应如下:

    if (canvas[newHead_i][newHead_j] == -2)
    {
        srand((unsigned)time(NULL));
        canvas[food_x][food_y] = 0;
        score++;
        food_x = rand() % 18 + 1;
        food_y = rand()%38+1;
        canvas[food_x][food_y] = -2;

    }
    else
        canvas[oldTail_i][oldTail_j] = 0;

5、增加道具,吃完可以加命。

(1)在void moveSnakeByDirection()部分增加代码,代码如下所示:

    if (canvas[newHead_i][newHead_j] == -3)
    {
        srand((unsigned)time(NULL));
        canvas[min_x][min_y] = 0;
        min += 1;
        min_x = rand() % 18 + 1;
        min_y = rand() % 38 + 1;
        canvas[min_x][min_y] = -3;
    }

(2)在void moveSnakeByDirection()部分修改部分代码,修改代码如下所示:

    if (canvas[newHead_i][newHead_j] > 0 || canvas[newHead_i][newHead_j] == -1)
    {
        if (min >= 1)
        {
            min--;
            for (i = 0; i < High; i++)
                for (j = 0; j < Width; j++)
                {
                    if (canvas[i][j] > 0)
                        canvas[i][j] = 0;
                }
           canvas[oldHead_i][oldHead_j] = 0;
            canvas[High / 2][Width / 2] = 1;
           for (i = 1; i <= 4; i++)
                canvas[High / 2 - i][Width / 2] = i + 1;
               moveDirection = 2;
               show();
        }
        else
        {
            printf("游戏失败!\n");
            Sleep(2000);
            system("pause");
            exit(0);
        }
    }
    else
        canvas[newHead_i][newHead_j] = 1;

6、增加道具,吃完可以减速。

(1)在全局函数部分添加slow变量,初始为0,并设置道具的初始横纵坐标;

int slow = 0;
int slow_x = 10, slow_y = 17;

(2)在void moveSnakeByDirection()部分增加代码,代码如下所示:

    if (canvas[newHead_i][newHead_j] == -4)
    {
        canvas[slow_x][slow_y] = 0;
        srand((unsigned)time(NULL));
        slow_x = rand() % 18 + 1;
        slow_y = rand() % 38 + 1;
        canvas[slow_x][slow_y] = -4;
        slow+=3;
    }
    canvas[slow_x][slow_y] = -4;   //将事物所出现的坐标赋值
   

(3)修改main()函数部分,如下图所示

int main()
{
    startup();
    while (1)
    {
        show();
        if (slow > 0) {
            slow--;
            Sleep(1000);
           
        }
       updateWithoutInput();
        updateWithInput();
       
    }
    return 0;
}

7.游戏界面美化

修改startup部分的画布,根据需要自行调整。

整个小游戏的完整代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include <time.h>

#define High 20
#define Width 40

int newHead_i, newHead_j;
int moveDirection;
int slow = 0;
int slow_x = 10, slow_y = 17;
int food_x = 9, food_y = 10;
int min_x = 7, min_y = 9;
int min = 0,score=0;
int canvas[High][Width+12] = { 0 };
void gotoxy(int x, int y)
{
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD pos;
    pos.X = x;
    pos.Y = y;
    SetConsoleCursorPosition(handle, pos);
}


void moveSnakeByDirection()
{
    void show();
    int i, j;
    for (i = 1; i < High - 1; i++)
        for (j = 1; j < Width - 1; j++)
            if (canvas[i][j] > 0)
                canvas[i][j]++;

    int oldTail_i, oldTail_j, oldHead_i, oldHead_j;
    int max = 0;

    for (i = 1; i < High - 1; i++)
        for (j = 1; j < Width - 1; j++)
            if (canvas[i][j] > 0)
            {
                if (max < canvas[i][j])
                {
                    max = canvas[i][j];
                    oldTail_i = i;
                    oldTail_j = j;
                }
                if (canvas[i][j] == 2)
                {
                    oldHead_i = i;
                    oldHead_j = j;
                }
            }

   

    if (moveDirection == 1)
    {
        newHead_i = oldHead_i - 1;
        newHead_j = oldHead_j;
    }
    if (moveDirection == 2)
    {
        newHead_i = oldHead_i + 1;
        newHead_j = oldHead_j;
    }
    if (moveDirection == 3)
    {
        newHead_i = oldHead_i;
        newHead_j = oldHead_j - 1;
    }
    if (moveDirection == 4)
    {
        newHead_i = oldHead_i;
        newHead_j = oldHead_j + 1;
    }

    if (canvas[newHead_i][newHead_j] == -2)
    {
        srand((unsigned)time(NULL));
        canvas[food_x][food_y] = 0;
        score++;
        food_x = rand() % 18 + 1;
        food_y = rand()%38+1;
        canvas[food_x][food_y] = -2;

    }
    else
        canvas[oldTail_i][oldTail_j] = 0;
    if (canvas[newHead_i][newHead_j] == -3)
    {
        srand((unsigned)time(NULL));
        canvas[min_x][min_y] = 0;
        min += 1;
        min_x = rand() % 18 + 1;
        min_y = rand() % 38 + 1;
        canvas[min_x][min_y] = -3;
    }
    if (canvas[newHead_i][newHead_j] == -4)
    {
        canvas[slow_x][slow_y] = 0;
        srand((unsigned)time(NULL));
        slow_x = rand() % 18 + 1;
        slow_y = rand() % 38 + 1;
        canvas[slow_x][slow_y] = -4;
        slow+=3;
    }
   
    
    if (canvas[newHead_i][newHead_j] > 0 || canvas[newHead_i][newHead_j] == -1)
    {
        if (min >= 1)
        {
            min--;
            for (i = 0; i < High; i++)
                for (j = 0; j < Width; j++)
                {
                    if (canvas[i][j] > 0)
                        canvas[i][j] = 0;
                }
           canvas[oldHead_i][oldHead_j] = 0;
            canvas[High / 2][Width / 2] = 1;
           for (i = 1; i <= 4; i++)
                canvas[High / 2 - i][Width / 2] = i + 1;
               moveDirection = 2;
               show();
        }
        else
        {
            printf("游戏失败!\n");
            Sleep(2000);
            system("pause");
            exit(0);
        }
    }
    else
        canvas[newHead_i][newHead_j] = 1;
    
}

void startup()
{
    int i, j;

   
    for (i = 13; i < 18; i++)
        canvas[3][i] = -1;
    for (i = 20; i < 25; i++)
        canvas[3][i] = -1;
    for (i = 4; i < 9; i++)
    {
        canvas[i][15] = -1;
        canvas[i][22] = -1;
    }
    for (i = 0; i < High; i++)
    {
        canvas[i][0] = -1;
        canvas[i][Width - 1] = -1;
        
    }
    for (j = 0; j < Width; j++)
    {
        canvas[0][j] = -1;
        canvas[High - 1][j] = -1;
    }
    for (j = Width+1; j < Width + 12; j++)
    {
        canvas[0][j] = -1;
        canvas[3][j] = -1;
    }
    for (i = 1; i < 3; i++)
    {
        canvas[i][Width+1] = -1;
        canvas[i][Width + 11] = -1;
    }

    canvas[High / 2][Width / 2] = 1;

    for (i = 1; i <= 4; i++)
        canvas[High / 2-i][Width / 2 ] = i + 1;

    moveDirection = 2;
    canvas[food_x][food_y] = -2;
    canvas[slow_x][slow_y] = -4;
    canvas[min_x][min_y] = -3;
}

void show()
{
    gotoxy(0, 0);
    int i, j;
    for (i = 0; i < High; i++)
    {
        for (j = 0; j < Width+12; j++)
        {    if (i == 1 && j == Width+2)
                printf("Score:%3d", score);
                if (i == 2 && j == Width+2)
                    printf("Min:%5d", min);
            if (canvas[i][j] == 0&&j<Width+1)
                printf(" ");
            else if (canvas[i][j] == -1)
                printf("#");
            else if (canvas[i][j] == 1)
                printf("Z");
            else if (canvas[i][j] > 1)
                printf("T");
            else if (canvas[i][j] == -2)
                printf("6");
            else if (canvas[i][j] == -3)
                printf("m");
            else if (canvas[i][j] == -4)
            printf("s");
           
        }
        printf("\n");
    }
  
    Sleep(500);
}

void updateWithoutInput()
{
    moveSnakeByDirection();
}

void updateWithInput()
{
    char input;
    if (_kbhit())
    {
        input = _getch();

        if (input == 'a')
        {
            moveDirection = 3;
            moveSnakeByDirection();
        }
        else if (input == 'd')
        {
            moveDirection = 4;
            moveSnakeByDirection();
        }
        else if (input == 'w')
        {
            moveDirection = 1;
            moveSnakeByDirection();
        }
        else if (input == 's')
        {
            moveDirection = 2;
            moveSnakeByDirection();
        }
    }
}

int main()
{
    startup();
    while (1)
    {
        show();
        if (slow > 0) {
            slow--;
            Sleep(1000);
           
        }
       updateWithoutInput();
        updateWithInput();
       
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值