c语言实现贪吃蛇——人生的第一个小项目

前几天闲得无聊,依然决定写个这个贪吃蛇小游戏练练手。经过几天夜战,调试了n次(终于体会到了程序员的崩溃)。特地感谢几位师兄学长的帮助,很幸运地完成了这个人生首作。

应用知识:c语言,easyx,数据结构中的链表

游戏界面展示

界面一

界面二

源代码:(一共在一个文件中,共四百多行)

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <memory.h>
#include <string.h>
#include<graphics.h>
#include<conio.h>
#include<easyx.h>
#include<time.h>

#define WALL "■"
#define FOOD  "█"
#define INIT_X 20
#define INIT_Y 18
typedef struct node {
    int x;
    int y;
    struct node* next;//储存每一个结点下一个结点的地址,构成一条链表
}SnakeNode, * pSnakeNode;
// 蛇的行走方向
enum DIRECTION
{
    UP = 1, DOWN, LEFT, RIGHT
};
//蛇的状态

enum GameState
{
    OK,
    NORMAL_END,
    KILL_BY_WALL,
    KILL_BY_SELF
};

// 蛇本身
typedef struct Snake
{
    pSnakeNode _psnake;//维护蛇身的指针
    pSnakeNode _pFood;//维护食物的位置
    int _TotalScore;//总分数
    int _AddScore;//增加的分数
    int _SleepTime;//休眠时间
    DIRECTION _Dir;
    GameState _Status;
}Snake, * pSnake;
void Welcome()
{
    initgraph(840, 800, EW_SHOWCONSOLE);
    setbkcolor(RED);
    cleardevice();
    //要在设置的字体前面加L
    settextstyle(15, 0, "楷体");//设置文字样式,大小,字体
    fillrectangle(200, 100, 600, 200);
    settextcolor(RGB(173, 0, 13));
    setbkmode(TRANSPARENT);
    char arr[] = "欢迎来到贪吃蛇游戏,按q开始游戏哦";
    int width = 400 / 2 - textwidth(arr) / 2;
    int height = 100 / 2 - textheight(arr) / 2;
    outtextxy(width + 200, height + 100, arr);
    settextstyle(15, 0, "楷体");//设置文字样式,大小,字体
    fillrectangle(200, 400, 600, 600);
    settextcolor(RGB(173, 0, 13));
    setbkmode(TRANSPARENT);
    char arr1[] = "方向盘移动,F1加速,F2减速";
    int width1 = 50 / 2 - textwidth(arr1) / 2;
    int height1 = 200 / 2 - textheight(arr1) / 2;
    outtextxy(width1 + 400, height1 + 400, arr1);

}
void SetPos(int x, int y)
{
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);//把标准输出的句柄得到,并交给变量handle,
    COORD pos = { 0 };
    pos.X = x;
    pos.Y = y;
    SetConsoleCursorPosition(handle, pos);//设置handle的输出位置,
}
void DrawMap(void)
{

    int i;
    for (i = 0; i < 58; i += 2)//画出地图的上边界,在控制界面每一个汉字,占两位,所以每次i+2
    {
        SetPos(i, 0);
        printf(WALL);
    }
    for (i = 0; i < 58; i += 2)//画出地图的下边界
    {
        SetPos(i, 26);
        printf(WALL);
    }
    for (i = 0; i < 26; i++)//画出地图的左边界
    {
        SetPos(0, i);
        printf(WALL);
    }
    for (i = 0; i <= 26; i++)//画出地图的右边界
    {
        SetPos(58, i);
        printf(WALL);
    }
}
pSnakeNode BuyNode()
{
    pSnakeNode pRet = (pSnakeNode)malloc(sizeof(SnakeNode));
    if (pRet == NULL)
    {
        perror("BuyNode::malloc()");
        exit(EXIT_FAILURE);
    }
    pRet->x = 0;
    pRet->y = 0;
    pRet->next = NULL;
    return pRet;
}
void InitSnake(pSnake ps)
{
    pSnakeNode first = BuyNode();//创建蛇头
    pSnakeNode cur = NULL;
    first->x = INIT_X;
    first->y = INIT_Y;
    int i = 0;
    for (i = 1; i <= 4; i++)
    {
        cur = BuyNode();//创建蛇身
        cur->x = first->x + 2;
        cur->y = first->y;
        cur->next = first;
        first = cur;
    }
    //打印蛇
    while (cur)
    {
        SetPos(cur->x, cur->y);
        printf(FOOD);
        cur = cur->next;
    }
    ps->_psnake = first;
}
void CreateFood(pSnake ps)
{
    pSnakeNode pfood = BuyNode();
    pSnakeNode cur = ps->_psnake;
    pfood->y = rand() % 26 + 1;
    do
    {
        pfood->x = rand() % 55 + 2;//0-54,+2产生2-56
    } while (pfood->x % 2 != 0);
    while (cur)
    {
        if (cur->x == pfood->x && cur->y == pfood->y)
        {
            CreateFood(ps);
        }
        cur = cur->next;
    }
    ps->_pFood = pfood;
    SetPos(pfood->x, pfood->y);
    printf(FOOD);
}
void KillBYWALL(pSnake ps)
{
    if ((ps->_psnake->x == 0) || (ps->_psnake->x == 58) || (ps->_psnake->y == 0) || (ps->_psnake->y == 27))
    {
        ps->_Status == KILL_BY_WALL;
    }
}
void KillBySelf(pSnake ps)
{
    pSnakeNode tnext = ps->_psnake->next;
    while (tnext)
    {
        if ((tnext->x == ps->_psnake->x) && (tnext->y == ps->_psnake->y))
        {
            ps->_Status == KILL_BY_SELF;
            return;
        }
        tnext = tnext->next;
    }

}
int NextHasFood(pSnakeNode pn, pSnakeNode pf)
{
    return (pn->x == pf->x) && (pn->y == pf->y);
}
void EatFood(pSnake ps, pSnakeNode pn)//吃食物
{
    pSnakeNode cur = NULL;
    pn->next = ps->_psnake;//头插
    ps->_psnake = pn;
    cur = ps->_psnake;
    ps->_TotalScore += ps->_AddScore;
    while (cur)
    {
        SetPos(cur->x, cur->y);
        printf(FOOD);
        cur = cur->next;
    }
    CreateFood(ps);
}
void NoFood(pSnake ps, pSnakeNode pn)//没有食物
{
    pSnakeNode cur = NULL;
    pn->next = ps->_psnake;//头插
    ps->_psnake = pn;
    cur = ps->_psnake;
    while (cur->next->next)
    {
        SetPos(cur->x, cur->y);
        printf(FOOD);
        cur = cur->next;
    }
    SetPos(cur->x, cur->y);
    printf(FOOD);
    SetPos(cur->next->x, cur->next->y);
    printf(" ");
    free(cur->next);
    cur->next = NULL;
}
void RUN(pSnake ps)
{
    InitSnake(ps);
    CreateFood(ps);
    ps->_AddScore = 10;//每次增加的分数
    ps->_TotalScore = 0;//总分
    ps->_Dir == RIGHT;//方向
    ps->_SleepTime = 200;//0.2秒
    ps->_Status == OK;//状态

}
void snakmove(pSnake ps)//蛇的移动
{
    pSnakeNode pNextNode = BuyNode();
    SetPos(65, 8);
    printf("总分:%d", ps->_TotalScore);
    SetPos(65, 9);
    printf("每个食物的得分:%d ", ps->_AddScore);
    //上
    switch (ps->_Dir)
    {
    case UP:
    {
        pNextNode->x = ps->_psnake->x;
        pNextNode->y = ps->_psnake->y - 1;
        if (NextHasFood(pNextNode, ps->_pFood))
        {
            //下一个节点是食物
            EatFood(ps, pNextNode);
        }
        else
        {
            NoFood(ps, pNextNode);
        }
        break;
    }
    case DOWN:
    {
        pNextNode->x = ps->_psnake->x;
        pNextNode->y = ps->_psnake->y + 1;
        if (NextHasFood(pNextNode, ps->_pFood))
        {
            //下一个节点是食物
            EatFood(ps, pNextNode);
        }
        else
        {
            NoFood(ps, pNextNode);
        }
        break;
    }
    case LEFT:
    {
        pNextNode->x = ps->_psnake->x - 2;
        pNextNode->y = ps->_psnake->y;
        if (NextHasFood(pNextNode, ps->_pFood))
        {
            //下一个节点是食物
            EatFood(ps, pNextNode);
        }
        else
        {
            NoFood(ps, pNextNode);
        }
        break;
    }
    case RIGHT:
    {
        pNextNode->x = ps->_psnake->x + 2;
        pNextNode->y = ps->_psnake->y;
        if (NextHasFood(pNextNode, ps->_pFood))
        {
            //下一个节点是食物
            EatFood(ps, pNextNode);
        }
        else
        {
            NoFood(ps, pNextNode);
        }
        break;
    }
    default:
    {
        break;
    }
    }
}
void PrintHelpInfo()
{
    SetPos(65, 11);
    printf("用↑,↓,←,→来控制蛇的移动");
    SetPos(65, 12);
    printf("F1为加速,F2为减速\n");
    SetPos(65, 13);
    printf("加速获得分数更多\n");
    SetPos(65, 14);
    printf("按空格暂停游戏\n");

}
void GameRun(pSnake ps)
{
    PrintHelpInfo();
    do {
        //确定方向
        if (GetAsyncKeyState(VK_UP) && (ps->_Dir != DOWN))
        {
            ps->_Dir = UP;
        }
        else if (GetAsyncKeyState(VK_DOWN) && ps->_Dir != UP)
        {
            ps->_Dir = DOWN;
        }
        else if (GetAsyncKeyState(VK_LEFT) && ps->_Dir != RIGHT)
        {
            ps->_Dir = LEFT;
        }
        else if (GetAsyncKeyState(VK_RIGHT) && ps->_Dir != LEFT)
        {
            ps->_Dir = RIGHT;
        }
        else if (GetAsyncKeyState(VK_SPACE))
        {
            //暂停游戏
            system("pause");//令目前的进程暂停(进入睡眠状态), 直到被信号(signal)所中断.
        }
        else if (GetAsyncKeyState(VK_ESCAPE))
        {
            //结束游戏
            ps->_Status == NORMAL_END;
            break;
        }
        else if (GetAsyncKeyState(VK_F1))
        {
            //加速
            if (ps->_SleepTime >= 40)
            {
                ps->_SleepTime -= 20;
                ps->_AddScore += 2;
            }
        }
        else if (GetAsyncKeyState(VK_F2))
        {
            //减速
            if (ps->_SleepTime <= 300)
            {
                ps->_SleepTime += 20;
                ps->_AddScore -= 2;
            }
            if (ps->_SleepTime > 300)
            {
                ps->_AddScore = 1;//不能一直减
            }
        }
        Sleep(ps->_SleepTime);//睡眠
          //蛇的移动
        snakmove(ps);
        KillBYWALL(ps);
        KillBySelf(ps);

    } while (ps->_Status == OK);
}
void GameEnd(pSnake ps)
{
    pSnakeNode cur = ps->_psnake;
    SetPos(25, 14);
    if (ps->_Status == NORMAL_END)
    {
        SetPos(70, 20);
        printf("游戏正常接结束\n");
        SetPos(70, 21);
    }
    else if (ps->_Status == KILL_BY_SELF)
    {
        SetPos(70, 20);
        printf("蛇撞到自己了\n");
        SetPos(70, 21);
    }
    else if (ps->_Status == KILL_BY_WALL)
    {
        SetPos(70, 20);
        printf("撞到墙了\n");
        SetPos(70, 21);
    }
    while (cur)
    {
        pSnakeNode del = cur;
        cur = cur->next;
        free(del);
        del = NULL;
    }
    ps->_psnake = NULL;
    free(ps->_pFood);
    ps->_pFood = NULL;
}
int main()
{
    srand((unsigned)time(NULL));
    Snake snake = { 0 };//创建贪吃蛇
    Welcome();
    char key = _getch();
    if (key == 'q')
    {
        closegraph();

    }
    
        DrawMap();
        RUN(&snake);
        GameRun(&snake);
        GameEnd(&snake);

    system("pause");
    return 0;

}

本贴为博主亲手整理。如有错误,请评论区指出,一起进步。谢谢大家的浏览。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值