贪吃蛇C语言代码实现

一个头文件snake.h两个源文件一个是test.c,一个是snake.c,这里使用的软件是vs2022。

//test.c

#define _CRT_SECURE_NO_WARNINGS

#include"snake.h"

void test()
{
    //创建我们的贪吃蛇 
    int ch = 0;
    do
    {
        Snake snake = { 0 };
        GameStart(&snake);//游戏开始前的初始化
        GameRun(&snake);//玩的过程
        GameEnd(&snake);//善后的工作//链表的空间释放
        SetPos(20, 15);
        printf("再来一局吗?(Y/N)");
        ch = getchar();
        getchar();//清理\n
    } while (ch == 'Y' || ch == 'y');
}


int main()
{
    //修改适配本地中文环境
    setlocale(LC_ALL,"");

    test();//贪吃蛇游戏的测试
    SetPos(0,27);
    return 0;
}

//snake.h

#pragma once


#include<locale.h>
#include<stdlib.h>
#include<stdio.h>
#include<windows.h>
#include<stdbool.h>

#define WALL L'□'
#define BODY L'●'
#define FOOD L'★'


//蛇默认的起始坐标
#define POS_X 24
#define POS_Y 5

#define KEY_PRESS(vk) (GetAsyncKeyState(vk)&0x1?1:0)

//游戏的状态
enum GAME_STATUS
{
    OK = 1,//正常运行
    ESC,//按了esc键退出,正常退出
    KILL_BY_WALL,//撞墙了
    KILL_BY_SELF//撞到自身了
};

//蛇行走的方向
enum DIRECTION
{
    UP = 1,
    DOWN,
    LEFT,
    RIGHT
};

//蛇身的结构体,构建链表
//贪吃蛇蛇身结点的定义
typedef struct SnakeNode
{
    int x;
    int y;
    struct SnakeNode* next;
}SnakeNode,*pSnakeNode;

//*pSnakeNode == typedef struct SnakeNode *pSnakeNode;
//用来指向蛇身pSnakeNode

//贪吃蛇-整个游戏的维护,用来维护状态
typedef struct Snake
{
    pSnakeNode pSnake;//维护整条蛇的指针
    pSnakeNode pFood;//指向食物的指针
    int Score;//当前累积的分数
    int FoodWeight;//一个食物的分数
    int SleepTime;//休眠的时间越短,蛇速度越快,休眠的时间越长,速度越慢。
    enum GAME_STATUS status;//游戏当前的状态
    enum DIRECTION dir;//蛇当前的走的方向
    //...
}Snake,*pSnake;

//定位控制台的光标位置
void SetPos(int x, int y);

//游戏开始前的准备
void GameStart(pSnake ps);

//欢迎界面
void WelcomeToGame();

//绘制地图
void CreateMap();

//初始化贪吃蛇
void InitSnake(pSnake ps);

//创建食物
void CreateFood(pSnake ps);

//游戏运行的整个逻辑
void GameRun(pSnake ps);

//打印帮助信息
void PrintHelpInfo();

//蛇移动的函数-每次走一步
void SnakeMove(pSnake ps);

//蛇头下一步要走的位置出是否是食物
int NextIsFood(pSnake ps,pSnakeNode pNext);

//下一步要走的位置处就是食物,就吃掉食物
void EatFood(pSnake ps, pSnakeNode pNext);

//下一步要走的位置处不是食物,就不吃吃掉食物
void NotEatFood(pSnake ps, pSnakeNode pNext);

//检测是否会撞墙
void killByWall(pSnake ps);

//检测是否撞自己
void killBySelf(pSnake ps);

//游戏结束的资源释放
void GameEnd(pSnake ps);

snake.c

#define _CRT_SECURE_NO_WARNINGS

#include"snake.h"


void SetPos(int x, int y)
{
    //获得设备句柄
    HANDLE hanlde = GetStdHandle(STD_OUTPUT_HANDLE);
    //根据句柄设置光标的位置
    COORD pos = { x,y };
    SetConsoleCursorPosition(hanlde, pos);
}


void WelcomeToGame()
{
    //欢迎信息
    SetPos(35, 10);
    printf("欢迎来到贪吃蛇小游戏");
    SetPos(37, 20);
    system("pause");
    system("cls");

    //功能介绍信息
    SetPos(15, 10);
    printf("用↑.↓.←.→ 分别控制蛇的移动, F3为加速,F4为减速\n");
    SetPos(15, 11);
    printf("加速得到更多的分数");
    SetPos(37, 20);
    system("pause");
    system("cls");
}

void CreateMap()
{
    int i = 0;
    //上
    SetPos(0, 0);
    for (i = 0; i <= 56; i += 2)
    {
        //wprintf(L"%lc",L'□');//宽字符要用单引号,包起来,占两个位置
        wprintf(L"%lc", WALL);//用#define进行宏定义。它允许用一个标识符来表示一个字符
    }
    //下
    SetPos(0, 26);
    //int i = 0;//不要重复定义
    for (i = 0; i <= 56; i += 2)
    {
        wprintf(L"%lc", WALL);
    }
    //左 
    for (i = 1; i <= 25; i++)
    {
        SetPos(0, i);//SetPos()括号中可以用到变量
        wprintf(L"%lc", WALL);
    }
    //右
    for (i = 1; i <= 25; i++)
    {
        SetPos(56, i);
        wprintf(L"%lc", WALL);
    }
    //getchar();//让程序停到这
}

void InitSnake(pSnake ps)
{
    //创建五个蛇身的结点
    pSnakeNode cur = NULL;
    int i = 0;
    for (i = 0;i < 5;i++)
    {
        cur = (pSnakeNode)malloc(sizeof(SnakeNode));
        if (cur == NULL)
        {
            perror("InitSnake():malloc()");
            return;
        }
        cur->x = POS_X + 2 * i;
        cur->y = POS_Y;
        cur->next = NULL;

        //头插法
        if (ps->pSnake == NULL)
        {
            ps->pSnake = cur;
        }
        else
        {
            cur->next = ps->pSnake;
            ps->pSnake = cur;
        }
    }

    //打印蛇身
    cur = ps->pSnake;
    while (cur)
    {
        SetPos(cur->x, cur->y);
        wprintf(L"%lc",BODY);
        cur = cur->next;
    }

    //贪吃蛇其他信息初始化
    ps->FoodWeight = 10;

    ps->dir = RIGHT;
    ps->pFood = NULL;
    ps->Score = 0;
    ps->SleepTime = 200;//200ms
    ps->status = OK;
    //getchar();
}

void CreateFood(pSnake ps)
{
    int x = 0;
    int y = 0;

again:
    do
    {
        x = rand() % 53 + 2;
        y = rand() % 24 + 1;
    } while (x % 2 != 0);

    //坐标和蛇的身体的每个坐标比较
    pSnakeNode cur = ps->pSnake;
    while (cur)
    {
        if (x == cur->x && y == cur->y )
        {
            goto again;
        }
        cur = cur->next;
    }

    //创建食物
    pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));
    if (pFood == NULL)
    {
        perror("CreateFood()::malloc()");
        return;
    }

    pFood->x = x;
    pFood->y = y;

    ps->pFood = pFood;
    SetPos(x,y);
    wprintf(L"%lc", FOOD);

}


void GameStart(pSnake ps)
{
    //设置控制台的信息,窗口大小,窗口名
    system("mode con cols=100 lines=30");
    system("title 贪吃蛇");

    //设置光标隐藏
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO CursorInfo;
    GetConsoleCursorInfo(handle, &CursorInfo);
    CursorInfo.bVisible = false;
    SetConsoleCursorInfo(handle, &CursorInfo);

    //打印欢迎信息
    WelcomeToGame();
    //绘制地图
    CreateMap();
    //初始化蛇
    InitSnake(ps);
    //创建食物
    CreateFood(ps);

    //getchar();//起到一个截止的作用,不然运行完没有title 贪吃蛇
}

void PrintHelpInfo()
{
    SetPos(64, 15);
    printf("1.不能穿墙,不能咬到自己");
    SetPos(64, 16);
    printf("⽤↑.↓.←.→分别控制蛇的移动.");
    SetPos(64, 17);
    printf("F3 为加速,F4 为减速\n");
    SetPos(64, 18);
    printf("ESC :退出游戏.space:暂停游戏.");
    SetPos(64, 20);
    printf("伯伦希尔科技有限公司@版权");

}

void pause()
{
    while (1)
    {
        Sleep(100);
        if (KEY_PRESS(VK_SPACE))
        {
            break;
        }
    }
}

int NextIsFood(pSnake ps, pSnakeNode pNext)
{
    if (ps->pFood->x == pNext->x && ps->pFood->y == pNext->y)
        return 1;//下一个坐标处是食物
    else
        return 0;

}

void EatFood(pSnake ps, pSnakeNode pNext)
{
    pNext->next = ps->pSnake;
    ps->pSnake = pNext;

    pSnakeNode cur = ps->pSnake;
    //打印蛇身
    while (cur)
    {
        SetPos(cur->x, cur->y);
        wprintf(L"%lc",BODY);
        cur = cur->next;
    }

    ps->Score += ps->FoodWeight;

    //释放旧的食物
    free(ps->pFood);
    //新建食物
    CreateFood(ps);
}

void NotEatFood(pSnake ps, pSnakeNode pNext)
{
    //头插法
    pNext->next = ps->pSnake;
    ps->pSnake = pNext;

    //释放尾结点
    pSnakeNode cur = ps->pSnake;
    while (cur->next->next != NULL)//不写NULL
    {
        SetPos(cur->x, cur->y);
        wprintf(L"%lc",BODY);
        cur = cur->next;
    }
    //将尾结点打印成空白字符 
    SetPos(cur->next->x, cur->next->y);
    printf("  ");

    free(cur->next);
    cur->next = NULL;
    
}

//检测是否会撞墙
void killByWall(pSnake ps)
{
    if (ps->pSnake->x == 0 ||
        ps->pSnake->x == 56 ||
        ps->pSnake->y == 0 ||
        ps->pSnake->y == 26)
    {
        ps->status = KILL_BY_WALL;
    }
}

//检测是否撞自己
void killBySelf(pSnake ps)
{
    pSnakeNode cur = ps->pSnake->next;//从第二个结点开始
    while (cur)
    {
        if (cur->x == ps->pSnake->x && cur->y == ps->pSnake->y)
        {
            ps->status = KILL_BY_SELF;
            return;
        }
        cur = cur->next;//说到底还是遍历链表
    }
}

void SnakeMove(pSnake ps)
{
    pSnakeNode pNext = (pSnakeNode)malloc(sizeof(SnakeNode));
    if (pNext == NULL)
    {
        perror("SnakeMove()::malloc()");
        return;
    }
    pNext->next = NULL;

    switch (ps->dir)
    {
    case UP:
        pNext->x = ps->pSnake->x;
        pNext->y = ps->pSnake->y - 1;
        break;
    case DOWN:
        pNext->x = ps->pSnake->x;
        pNext->y = ps->pSnake->y + 1;
        break;
    case LEFT:
        pNext->x = ps->pSnake->x - 2;
        pNext->y = ps->pSnake->y;
        break;
    case RIGHT:
        pNext->x = ps->pSnake->x + 2;//横的两个大小位宽的一个
        pNext->y = ps->pSnake->y;
        break;

    }

    //下一个坐标处是否是食物
    if (NextIsFood(ps, pNext))
    {
        //是食物就吃掉
        EatFood(ps,pNext);
    }
    else
    {
        //不是食物就正常走一步
        NotEatFood(ps, pNext);
    }

    //检测撞墙
    killByWall(ps);
    //检测撞自己
    killBySelf(ps);
    
}


void GameRun(pSnake ps)
{
    //打印帮助信息
    PrintHelpInfo();

    //检测按键
    do
    {
        //当前的分数情况
        SetPos(65,10);
        printf("总分:%5d\n", ps->Score);
        SetPos(65,11);
        printf("每个食物得分:%02d分\n", ps->FoodWeight);
        //检测按键
        //上、下、左、右、ESC、F3、F4
        if (KEY_PRESS(VK_UP) && ps->dir != DOWN)
        {
            ps->dir = UP;
        }
        else if (KEY_PRESS(VK_DOWN) && ps->dir != UP)
        {
            ps->dir = DOWN;
        }
        else if (KEY_PRESS(VK_LEFT) && ps->dir != RIGHT)
        {
            ps->dir = LEFT;
        }
        else if (KEY_PRESS(VK_RIGHT) && ps->dir != LEFT)
        {
            ps->dir = RIGHT;
        }
        else if (KEY_PRESS(VK_ESCAPE))
        {
            ps->status = ESC;
            break;
        }
        else if (KEY_PRESS(VK_SPACE))
        {
            //游戏要暂停
            pause();//暂停和恢复暂停
        }
        else if (KEY_PRESS(VK_F3))
        {
            //也不能一直加那会成负数
            if (ps->SleepTime >= 80)
            {
                ps->SleepTime -= 30;
                ps->FoodWeight += 2;
            }
        }
        else if (KEY_PRESS(VK_F4))
        {
            if (ps->FoodWeight > 2)
            {
                ps->SleepTime += 30;
                ps->FoodWeight -= 2;
            }
        }
        //睡眠一下
        Sleep(ps->SleepTime);
        //走一步
        SnakeMove(ps);//待完成
    } while (ps->status == OK);
}

void GameEnd(pSnake ps)
{
    SetPos(20,12);
    switch (ps->status)
    {
    case ESC:
        printf("主动退出游戏,正常退出\n");
        break;
    case KILL_BY_WALL:
        printf("哈↗哈↘哈↗,真是太菜啦!!!");
        SetPos(20, 16);
        printf("撞墙死亡,游戏结束");
        break;
    case KILL_BY_SELF:
        printf("哈↗哈↘哈↗,真是太菜啦!!!");
        SetPos(20, 16);
        printf("咬到自己,游戏结束");
        break;
    }
    //释放贪吃蛇的链表资源
    pSnakeNode cur = ps->pSnake;
    pSnakeNode del = NULL;

    while (cur)
    {
        del = cur;
        cur = cur->next;
        free(del);
    }
    free(ps->pFood);
    ps = NULL;
}

  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然,这是一个简单的C语言贪吃小游戏的源代码示例: ```c #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <windows.h> int width = 20, height = 20; int gameover; int x, y, fruitX, fruitY, score; int tailX[100], tailY[100]; int nTail; enum eDirection { STOP = 0, LEFT, RIGHT, UP, DOWN }; enum eDirection dir; void Setup() { gameover = 0; dir = STOP; x = width / 2; y = height / 2; fruitX = rand() % width; fruitY = rand() % height; score = 0; } void Draw() { system("cls"); for (int i = 0; i < width + 2; i++) printf("#"); printf("\n"); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if (j == 0) printf("#"); if (i == y && j == x) printf("O"); else if (i == fruitY && j == fruitX) printf("F"); else { int printTail = 0; for (int k = 0; k < nTail; k++) { if (tailX[k] == j && tailY[k] == i) { printf("o"); printTail = 1; } } if (!printTail) printf(" "); } if (j == width - 1) printf("#"); } printf("\n"); } for (int i = 0; i < width + 2; i++) printf("#"); printf("\n"); printf("Score:%d\n", score); } void Input() { if (_kbhit()) { switch (_getch()) { case 'a': dir = LEFT; break; case 'd': dir = RIGHT; break; case 'w': dir = UP; break; case 's': dir = DOWN; break; case 'x': gameover = 1; break; } } } void Logic() { int prevX = tailX[0]; int prevY = tailY[0]; int prev2X, prev2Y; tailX[0] = x; tailY[0] = y; for (int i = 1; i < nTail; i++) { prev2X = tailX[i]; prev2Y = tailY[i]; tailX[i] = prevX; tailY[i] = prevY; prevX = prev2X; prevY = prev2Y; } switch (dir) { case LEFT: x--; break; case RIGHT: x++; break; case UP: y--; break; case DOWN: y++; break; default: break; } if (x >= width) x = 0; else if (x < 0) x = width - 1; if (y >= height) y = 0; else if (y < 0) y = height - 1; for (int i = 0; i < nTail; i++) { if (tailX[i] == x && tailY[i] == y) gameover = 1; } if (x == fruitX && y == fruitY) { score += 10; fruitX = rand() % width; fruitY = rand() % height; nTail++; } } int main() { Setup(); while (!gameover) { Draw(); Input(); Logic(); Sleep(10); // 控制游戏速度 } return 0; } ``` 这个代码示例实现了一个基本的贪吃小游戏,使用了C语言的基本语法和控制台输入输出函数。你可以将代码复制到一个C语言编译器中(如Dev-C++、Code::Blocks等)进行编译和运行。希望这能帮到你!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值