C--贪吃蛇

目录

前言

简单的准备工作

蛇的节点

开始前 void GameStart(pSnake ps)

void WelcomeToGame()

void CreateMap()

  void InitSnake(pSnake ps)

 void CreateFood(pSnake ps)

游戏进行 void GameRun(pSnake ps)

  int NextIsFood(pSnakeNode psn, pSnake ps)

 void NoFood(pSnakeNode psn, pSnake ps)

void SnakeMove(pSnake ps)

游戏结束 void GameEnd(pSnake ps)

源码

test.c

snake.h

snake.cpp

总结


前言

贪吃蛇游戏是一个耳熟能详的小游戏,本次我们讲解他的简单的实现,需要掌握基本的API知识(http://t.csdnimg.cn/uHH6y),简单的C语言知识和基本的数据结构链表

简单的准备工作

蛇的节点

在游戏运⾏的过程中,蛇每次吃⼀个⻝物,蛇的⾝体就会变⻓⼀节,如果我们使⽤链表存储蛇的信 息,那么蛇的每⼀节其实就是链表的每个节点。每个节点只要记录好蛇⾝节点在地图上的坐标就⾏, 所以蛇节点结构如下:

 typedef struct SnakeNode
 {
 int x;
 int y;
 struct SnakeNode* next;
 }SnakeNode, * pSnakeNode;

但是这样不好维护这一条蛇,要管理整条贪吃蛇,我们再封装⼀个Snake的结构来维护整条贪吃蛇

typedef struct Snake
 {
 pSnakeNode _pSnake;维护整条蛇的指针 
pSnakeNode _pFood;维护⻝物的指针 
enum DIRECTION _Dir;头的⽅向默认是向右 
enum GAME_STATUS _Status;游戏状态 
int _Socre;当前获得分数 
int _Add;默认每个⻝物10分 
int _SleepTime;每⾛⼀步休眠时间
}Snake, * pSnake;

开始前 void GameStart(pSnake ps)

游戏开始,先打印蛇的身体和地图,以及一些帮助的提示语句,先完成一些准备工作

void GameStart(pSnake ps)
 {
 
设置控制台窗⼝的⼤⼩,30⾏,100列 
//mode 为DOS命令
 system("mode con cols=100 lines=30");
 //设置cmd窗⼝名称
 system("title 贪吃蛇"); 
//获取标准输出的句柄(⽤来标识不同设备的数值) 
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE); //影藏光标操作 
CONSOLE_CURSOR_INFO CursorInfo; //打印欢迎界⾯ 
WelcomeToGame(); //打印地图 
CreateMap(); //初始化蛇 
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息 
CursorInfo.bVisible = false; //隐藏控制台光标 
SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态 
InitSnake(ps);
 //创造第⼀个⻝物 
CreateFood(ps);
 }
 

void WelcomeToGame()

在游戏正式开始之前,做⼀些功能提醒,来让玩家了解游戏方法与规则,其中SetPos是一个已经封装后的函数,可以把这个字体打在这个坐标

 void WelcomeToGame()
 {
 SetPos(40, 15);
 printf("欢迎来到贪吃蛇⼩游戏");
 SetPos(40, 25);//让按任意键继续的出现的位置好看点 
system("pause");
 system("cls");
 SetPos(25, 12);
 printf("⽤ ↑ . ↓ . ← . → 分别控制蛇的移动, F3为加速,F4为减速\n");
 SetPos(25, 13);
 printf("加速将能得到更⾼的分数。\n");
 SetPos(40, 25);//让按任意键继续的出现的位置好看点 
system("pause");
 system("cls");
 }

void CreateMap()

创建地图就是将强打印出来,因为是宽字符打印,所有使⽤wprintf函数,打印格式串前使⽤L 打印地图的关键是要算好坐标,才能在想要的位置打印墙体。

 void CreateMap()
 {
 int i = 0;
 //上(0,0)-(56, 0) 
SetPos(0, 0);
 for (i = 0; i < 58; i += 2)
 {
 wprintf(L"%c", WALL);
 } //下(0,26)-(56, 26)  
 SetPos(0, 26); for (i = 0; i < 58; i += 2)
 { wprintf(L"%c", WALL);
 } //左//x是0,y从1开始增⻓ 
for (i = 1; i < 26; i++)
 {
 SetPos(0, i);
 wprintf(L"%c", WALL);}  //是56y从1开始增⻓ 
for (i = 1; i < 26; i++)
 {
 SetPos(56, i);
 wprintf(L"%c", WALL);
 }
 } 

  void InitSnake(pSnake ps)

蛇最开始⻓度为5节,每节对应链表的⼀个节点,蛇⾝的每⼀个节点都有⾃⼰的坐标。 创建5个节点,然后将每个节点存放在链表中进⾏管理。创建完蛇⾝后,将蛇的每⼀节打印在屏幕上。 再设置当前游戏的状态,蛇移动的速度,默认的⽅向,初始成绩,蛇的状态,每个⻝物的分数。

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->next = NULL;
        cur->x = POS_X + i * 2;
        cur->y = POS_Y;
        //头插法 
        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"%c", BODY);
 cur = cur->next;
 }
 //
初始化贪吃蛇数据 
ps->_SleepTime = 200;
 ps->_Socre = 0;
 ps->_Status = OK;
 ps->_Dir = RIGHT;
 ps->_Add = 10;
 }

 void CreateFood(pSnake ps)

先随机⽣成⻝物的坐标 ◦

  • x坐标必须是2的倍数 ◦
  • ⻝物的坐标不能和蛇⾝每个节点的坐标重复 
  • 创建⻝物节点,打印⻝物
 void CreateFood(pSnake ps)
 {
    int x = 0;
    int y = 0;
 again:
    //产⽣的x坐标应该是2倍数,这样才可能和蛇头坐标对⻬。 
    do
    {
        x = rand() % 53 + 2;
        y = rand() % 25 + 1;
    } while (x % 2 != 0);
    pSnakeNode cur = ps->_pSnake;//获取指向蛇头的指针
     //⻝物不能和蛇⾝冲突
    while (cur)
    {
        if (cur->x == x && cur->y == y)
        {
            goto again;
        }
        cur = cur->next;
    }
    pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode)); //创建⻝物
    if (pFood == NULL)
    {
        perror("CreateFood::malloc()");
        return;
    }
    else
    {
        pFood->x = x;
        pFood->y = y;
        SetPos(pFood->x, pFood->y);
        wprintf(L"%c", FOOD);
        ps->_pFood = pFood;
    }
 }

游戏进行 void GameRun(pSnake ps)

游戏运⾏期间,右侧打印帮助信息,提⽰玩家 根据游戏状态检查游戏是否继续,如果是状态是OK,游戏继续,否则游戏结束。 如果游戏继续,就是检测按键情况,确定蛇下⼀步的⽅向,或者是否加速减速,是否暂停或者退出游 戏。 确定了蛇的⽅向和速度,蛇就可以移动了。

 void GameRun(pSnake ps)
 {
 //打印右侧帮助信息
PrintHelpInfo();
 do
 {
 SetPos(64, 10); printf("得分:%d ", ps->_Socre);
 printf("每个⻝物得分:%d分", ps->_Add);
 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_SPACE))
        {
            pause();
        }
        else if (KEY_PRESS(VK_ESCAPE))
        {
            ps->_Status = END_NOMAL;
            break;
        }
        else if (KEY_PRESS(VK_F3))
        {
            if (ps->_SleepTime >= 50)
            {
                ps->_SleepTime -= 30;
                ps->_Add += 2;
            }
        }
        else if (KEY_PRESS(VK_F4))
        {
            if (ps->_SleepTime < 350)
            {
                ps->_SleepTime += 30;
                ps->_Add -= 2;
                if (ps->_SleepTime == 350)
                {
                    ps->_Add = 1;
                }
            }
        }
        //蛇每次⼀定之间要休眠的时间,时间短,蛇移动速度就快
         Sleep(ps->_SleepTime);
        SnakeMove(ps);
    } while (ps->_Status == OK);
 }
 

  int NextIsFood(pSnakeNode psn, pSnake ps)

是一个判断下一个位置是食物的函数,会在下面SnakeMove起到作用,是食物的话将吃掉,不是的话将继续按按键运动

 
int NextIsFood(pSnakeNode psn, pSnake ps)
 {
    return (psn->x == ps->_pFood->x) && (psn->y == ps->_pFood->y);
 }
 

 void NoFood(pSnakeNode psn, pSnake ps)

将下⼀个节点头插⼊蛇的⾝体,并将之前蛇⾝最后⼀个节点打印为空格,放弃掉蛇⾝的最后⼀个节点,在时间是毫米的瞬间完成,造成移动的效果

void NoFood(pSnakeNode psn, pSnake ps)
 {
 //头插法 
psn->next = ps->_pSnake;
 ps->_pSnake = psn;
 pSnakeNode cur = ps->_pSnake;
 //打印蛇 
while (cur->next->next)
 {
 SetPos(cur->x, cur->y);
 wprintf(L"%c", BODY);
 }
 //最后⼀个位置打印空格,然后释放节点 
SetPos(cur->next->x, cur->next->y);
 printf("  ");
 free(cur->next);
 cur->next = NULL;
 }

void SnakeMove(pSnake ps)

蛇⾝移动先创建下⼀个节点,根据移动⽅向和蛇头的坐标,蛇移动到下⼀个位置的坐标。 确定了下⼀个位置后,看下⼀个位置是否是⻝物(NextIsFood),是⻝物就做吃⻝物处理 (EatFood),如果不是⻝物则做前进⼀步的处理(NoFood)。 蛇⾝移动后,判断此次移动是否会造成撞墙(KillByWall)或者撞上⾃⼰蛇⾝(KillBySelf),从⽽影 响游戏的状态

 void SnakeMove(pSnake ps)
 {
 //创建下⼀个节点 
pSnakeNode pNextNode = (pSnakeNode)malloc(sizeof(SnakeNode));
 if (pNextNode == NULL)
 {
 perror("SnakeMove()::malloc()");
 return;
 } //确定下⼀个节点的坐标,下⼀个节点的坐标根据,蛇头的坐标和⽅向确定 
switch (ps->_Dir)
 {
 case UP:
 {
 pNextNode->x = ps->_pSnake->x;
 pNextNode->y = ps->_pSnake->y - 1;

        }
        break;
        case DOWN:
        {
            pNextNode->x = ps->_pSnake->x;
            pNextNode->y = ps->_pSnake->y + 1;
        }
        break;
        case LEFT:
        {
            pNextNode->x = ps->_pSnake->x - 2;
            pNextNode->y = ps->_pSnake->y;
        }
        break;
        case RIGHT:
        {
            pNextNode->x = ps->_pSnake->x + 2;
            pNextNode->y = ps->_pSnake->y;
        }
        break;
    }
    //如果下⼀个位置就是⻝物
 
    if (NextIsFood(pNextNode, ps))
    {
        EatFood(pNextNode, ps);
    }
    else//如果没有⻝物 
    {
        NoFood(pNextNode, ps);
    }
    KillByWall(ps);
    KillBySelf(ps);
 }

游戏结束 void GameEnd(pSnake ps)

游戏结束 游戏状态不再是OK(游戏继续)的时候,要告知游戏技术的原因,并且释放蛇⾝节点。

 void GameEnd(pSnake ps)
 {
 pSnakeNode cur = ps->_pSnake;
 SetPos(24, 12);
 switch (ps->_Status)
 {
 case END_NOMAL:
 printf("您主动退出游戏\n");
 break;
 case KILL_BY_SELF: printf("您撞上⾃⼰了 ,游戏结束!\n");
 break;
 case KILL_BY_WALL:
printf("您撞墙了,游戏结束!\n"); } //释放蛇⾝的节点 
while (cur)
 {
 pSnakeNode del = cur;
 cur = cur->next;
 free(del);
 }
 }

源码

test.c

 #include "Snake.h"
 #include <locale.h>
 void test()
 {
 int ch = 0;
 srand((unsigned int)time(NULL));
 do
 {
 Snake snake = { 0 };
 GameStart(&snake);
 GameRun(&snake);
 GameEnd(&snake);
 SetPos(20, 15);
 printf("再来⼀局吗?(Y/N):");
 ch = getchar();
 getchar();//清理\n } while (ch == 'Y');
 SetPos(0, 27);
 }
 int main()
 {
 //修改当前地区为本地模式,为了⽀持中⽂宽字符的打印
 setlocale(LC_ALL, ""); 
test();
 return 0;
 }

snake.h

 #pragma once
 #include <windows.h>
 #include <time.h>
 #include <stdio.h>
 #define KEY_PRESS(VK)  ((GetAsyncKeyState(VK)&0x1) ? 1 : 0)
 //⽅向
enum DIRECTION
 {
 UP = 1,
 DOWN,
 LEFT,
 RIGHT
 };
 //游戏状态 
enum GAME_STATUS
 {
 OK,//正常运⾏ 
KILL_BY_WALL,//撞墙 
KILL_BY_SELF,//咬到⾃⼰ 
END_NOMAL//正常结束 
};
 #define WALL L'□' 
#define BODY L'●'  // ★ ○● ◇◆ □■ 
#define FOOD L' ★ '  // ★ ○● ◇◆ □■ //蛇的初始位置 
#define POS_X 24
 #define POS_Y 5 //蛇⾝节点
 typedef struct SnakeNode
 {
 int x;
 int y;
 struct SnakeNode* next;
 }SnakeNode, * pSnakeNode;
 typedef struct Snake
 {
 pSnakeNode _pSnake;//整条蛇的指针 
pSnakeNode _pFood;//维护⻝物的指针 
enum DIRECTION _Dir;//蛇头的⽅向默认是向右 
enum GAME_STATUS _Status;//游戏状态 
int _Socre;//当前获得分数 
int _Add;//默认每个⻝物 
int _SleepTime;//每⾛⼀步休眠时间 
}Snake, * pSnake;
 //游戏开始前的初始化 
void GameStart(pSnake ps); //游戏运⾏过程 
void GameRun(pSnake ps); //结束 
void GameEnd(pSnake ps); //设置光标的坐标 
void SetPos(short x, short y); //欢迎界⾯ 
void WelcomeToGame(); //打印帮助信息 
void PrintHelpInfo(); //创建地图 
void CreateMap();//初始化蛇 
void InitSnake(pSnake ps); //⻝物 
void CreateFood(pSnake ps);暂停响应 
void pause(); //下⼀个节点是⻝物
 int NextIsFood(pSnakeNode psn, pSnake ps); //吃⻝物 
void EatFood(pSnakeNode psn, pSnake ps); //不吃⻝物 
void NoFood(pSnakeNode psn, pSnake ps); //撞墙检测 
int KillByWall(pSnake ps); //撞⾃⾝检测 
int KillBySelf(pSnake ps); //蛇的移动 
void SnakeMove(pSnake ps); //游戏初始化 
void GameStart(pSnake ps); //游戏运⾏ 
void GameRun(pSnake ps); //游戏结束
 void GameEnd(pSnake ps);

snake.cpp

 #include "Snake.h"
 //设置光标的坐标 
void SetPos(short x, short y)
 {
 COORD pos = { x, y };
 HANDLE hOutput = NULL;//获取标准输出的句柄(⽤来标识不同设备的数值) 
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//设置标准输出上光标的位置为
pos SetConsoleCursorPosition(hOutput, pos);
 }
 void WelcomeToGame()
 {
 SetPos(40, 15);
 printf("欢迎来到贪吃蛇⼩游戏");
 SetPos(40, 25);//让按任意键继续的出现的位置好看点 
system("pause");
 system("cls");
 SetPos(25, 12);
 printf("⽤ ↑ . ↓ . ← . → 控制蛇的移动, F3为加速,F4为减速\n");
 SetPos(25, 13);
 printf("加速将能得到更⾼的分数。\n");
 SetPos(40, 25);//让按任意键继续的出现的位置好看点 
system("pause");
 system("cls"); } void CreateMap()
 {
 int i = 0;
 //上(0,0)-(56, 0) 
SetPos(0, 0);
 for (i = 0; i < 58; i += 2)
 {
 wprintf(L"%c", WALL);
 }
 //
下(0,26)-(56, 26) 
SetPos(0, 26);
 for (i = 0; i < 58; i += 2)
 {
 wprintf(L"%c", WALL);
 }
 //左 
//x0,y从1开始增⻓ 
for (i = 1; i < 26; i++)
 {
 SetPos(0, i);
 wprintf(L"%c", WALL);
 }
 //56,从开始增⻓ 
for (i = 1; i < 26; i++)
 {
 SetPos(56, i);
 wprintf(L"%c", WALL);
 }
 }
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->next = NULL;
        cur->x = POS_X + i * 2;
        cur->y = POS_Y;
        //头插法
        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"%c", BODY);
        cur = cur->next;
    }
    //初始化贪吃蛇数据
    ps->_SleepTime = 200;
    ps->_Socre = 0;
    ps->_Status = OK;
    ps->_Dir = RIGHT;
    ps->_Add = 10;
 }
 void CreateFood(pSnake ps)
 {
    int x = 0;
    int y = 0;
 again:
    //产⽣的x坐标应该是2的倍数,这样才可能和蛇头坐标对⻬。
    do
    {
        x = rand() % 53 + 2;
        y = rand() % 25 + 1;
    } while (x % 2 != 0);
    pSnakeNode cur = ps->_pSnake;//指向蛇头的指针     //⻝物不能和蛇⾝冲突
    while (cur)
    {
        if (cur->x == x && cur->y == y)
        {
            goto again;
        }
        cur = cur->next;
    }
    pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode)); //
创建⻝物
 
    if (pFood == NULL)
    {
        perror("CreateFood::malloc()");
        return;
    }
    else
    {
        pFood->x = x;
        pFood->y = y;
        SetPos(pFood->x, pFood->y);
        wprintf(L"%c", FOOD);
        ps->_pFood = pFood;
    }
 }
 void PrintHelpInfo()
 {
 }
 void pause()//暂停 
{打印提⽰信息 
SetPos(64, 15);
 printf("不能穿墙,不能咬到⾃⼰\n");
 SetPos(64, 16);
 printf("⽤↑.↓.←.→分别控制蛇的移动.");
 SetPos(64, 17);
 printf("F1 为加速,F2 为减速\n");
 SetPos(64, 18);
 printf("ESC :退出游戏.space:暂停游戏.");
 SetPos(64, 20);
 while (1)
 {
 Sleep(300);
 if (KEY_PRESS(VK_SPACE))
 {
 break;
 }
 }
 }
 //pSnakeNode psn 是下⼀个节点的地址 
//pSnake ps 维护蛇的指针 
int NextIsFood(pSnakeNode psn, pSnake ps)
 {
 return (psn->x == ps->_pFood->x) && (psn->y == ps->_pFood->y);
 }
 //pSnakeNode psn 是下⼀个节点的地址 
//pSnake ps 维护蛇的指针 
void EatFood(pSnakeNode psn, pSnake ps)
 {
 //头插法 
psn->next = ps->_pSnake;
 ps->_pSnake = psn;
 pSnakeNode cur = ps->_pSnake;
 //打印蛇 
while (cur)
 {
 SetPos(cur->x, cur->y);
 wprintf(L"%c", BODY);
 cur = cur->next;

 }
 ps->_Socre += ps->_Add;
 free(ps->_pFood);
 CreateFood(ps);
 }
 //pSnakeNode psn 
是下⼀个节点的地址
 
//pSnake ps 
维护蛇的指针
 
void NoFood(pSnakeNode psn, pSnake ps)
 {
 //头插法
 psn->next = ps->_pSnake;
 ps->_pSnake = psn;
 pSnakeNode cur = ps->_pSnake; //打印蛇 
while (cur->next->next)
 {
 SetPos(cur->x, cur->y);
 wprintf(L"%c", BODY);
 cur = cur->next;
 }
 //最后⼀个位置打印空格,然后释放节点 
SetPos(cur->next->x, cur->next->y);
 printf("  ");
 free(cur->next);
 cur->next = NULL;
 }
 //pSnake ps 
维护蛇的指针
int 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;
 return 1;
 }
 return 0;
 }
 //pSnake ps 
维护蛇的指针 
int KillBySelf(pSnake ps)
 {
    pSnakeNode cur = ps->_pSnake->next;
    while (cur)
    {
        if ((ps->_pSnake->x == cur->x)
            && (ps->_pSnake->y == cur->y))
        {
            ps->_Status = KILL_BY_SELF;
            return 1;
        }
        cur = cur->next;
    }
    return 0;
 }
 void SnakeMove(pSnake ps)
 {
    //创建下⼀个节点 
    pSnakeNode pNextNode = (pSnakeNode)malloc(sizeof(SnakeNode));
    if (pNextNode == NULL)
    {
        perror("SnakeMove()::malloc()");
        return;
    }
    //
确定下⼀个节点的坐标,下⼀个节点的坐标根据,蛇头的坐标和⽅向确定
 
    switch (ps->_Dir)
    {
        case UP:
        {
            pNextNode->x = ps->_pSnake->x;
            pNextNode->y = ps->_pSnake->y - 1;
        }
        break;
        case DOWN:
        {
            pNextNode->x = ps->_pSnake->x;
            pNextNode->y = ps->_pSnake->y + 1;
        }
        break;
        case LEFT:
        {
            pNextNode->x = ps->_pSnake->x - 2;
            pNextNode->y = ps->_pSnake->y;
        }
        break;
        case RIGHT:
        {
            pNextNode->x = ps->_pSnake->x + 2;
            pNextNode->y = ps->_pSnake->y;
        }
        break;
    }
    //如果下⼀个位置就是⻝物
 
    if (NextIsFood(pNextNode, ps))
    {
        EatFood(pNextNode, ps);
    }
    else//如果没有⻝物

    {
        NoFood(pNextNode, ps);
    }
    KillByWall(ps);
    KillBySelf(ps);
 }
 void GameStart(pSnake ps)
 {
    //设置控制台窗⼝的⼤⼩,30⾏,100 
    //mode 为DOS命令 
    system("mode con cols=100 lines=30");
    //设置cmd窗⼝名称 
    system("title 贪吃蛇"); 
    //获取标准输出的句柄(来标识不同设备的数值) 
    HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);  //影藏光标操作
    CONSOLE_CURSOR_INFO CursorInfo;
    GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
    CursorInfo.bVisible = false; //隐藏控制台光标 
    SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态 //打印欢迎界⾯ 
    WelcomeToGame();   //打印地图 
   CreateMap();   //初始化蛇
    InitSnake(ps);  /创造第⼀个⻝物
    CreateFood(ps);
 
}
 void GameRun(pSnake ps)
 {    //打印右侧帮助信息
 
    PrintHelpInfo();
    do
    {
        SetPos(64, 10);
        printf("得分:%d ", ps->_Socre);        printf("每个⻝物得分:%d分", ps->_Add);
        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_SPACE))
        {
            pause();
        }
        else if (KEY_PRESS(VK_ESCAPE))
        {
            ps->_Status = END_NOMAL;
            break;
        }
        else if (KEY_PRESS(VK_F3))
        {
            if (ps->_SleepTime >= 50)
            {
                ps->_SleepTime -= 30;
                ps->_Add += 2;
            }
        }
        else if (KEY_PRESS(VK_F4))
        {

            if (ps->_SleepTime < 350)
            {
                ps->_SleepTime += 30;
                ps->_Add -= 2;
                if (ps->_SleepTime == 350)
                {
                    ps->_Add = 1;
                }
            }
        }
        //蛇每次⼀定之间要休眠的时间,时间短,蛇移动速度就快
 
        Sleep(ps->_SleepTime);
        SnakeMove(ps);
    } while (ps->_Status == OK);
 }
 void GameEnd(pSnake ps)
 {
    pSnakeNode cur = ps->_pSnake;
    SetPos(24, 12);
    switch (ps->_Status)
    {
    case END_NOMAL:        printf("您主动退出游戏\n");
        break;
    case KILL_BY_SELF:
        printf("您撞上⾃⼰了 ,游戏结束!\n");        break;
    case KILL_BY_WALL:
        printf("您撞墙了,游戏结束!\n");
        break;
    }
    //释放蛇⾝的节点 
    while (cur)
    {
        pSnakeNode del = cur;
        cur = cur->next;
        free(del);
    }
 }

总结

贪吃蛇小游戏是一个有趣的小游戏,也让我学到了很多,希望大家多多支持!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/622606.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入学习指针5,与数组和指针相关的笔试题1(C语言)

前言 Hello,亲爱的小伙伴们&#xff0c;我又来了&#xff0c;&#xff0c;今天呢我们一起来学习一下C语言关于数组和指针的部分经典题目。如果觉得不错的话不要忘了点赞&#xff0c;收藏、关注&#xff0c;你的支持就是我更新的最大动力&#xff01;&#xff01; 好&#xff0…

深度求索推出DeepSeek-V2:经济高效的多专家语言模型

AI苏妲己 深度求索发布了DeepSeek-V2混合专家&#xff08;MoE&#xff09;语言模型&#xff0c;每百万tokens&#xff0c;2元人民币价格&#xff0c;简直便宜到令人发指&#xff08;而且不是活动价格噢&#xff09;&#xff0c;可以说是继Groq以后&#xff0c;AI领域最惊艳的新…

[力扣题解] 96. 不同的二叉搜索树

题目&#xff1a;96. 不同的二叉搜索树 思路 动态规划 f[i]&#xff1a;有i个结点有多少种二叉搜索树 状态转移方程&#xff1a; 以n3为例&#xff1a; 以1为头节点&#xff0c;左子树有0个结点&#xff0c;右子树有2个结点&#xff1b; 以2为头节点&#xff0c;左子树有1个…

【计算机网络】数据链路层 组帧 习题4

组帧 发送方根据一定的规则将网络层递交的分组封装成帧(也称为组帧)。 组帧时&#xff0c;既要加首部&#xff0c;也要加尾部&#xff0c;原因是&#xff0c;在网络信息中&#xff0c;帧是以最小单位传输的。所以接收方要正确地接收帧&#xff0c;就必须清楚该帧在一串比特串中…

【iOS】架构模式

文章目录 前言一、MVC二、MVP三、MVVM 前言 之前写项目一直用的是MVC架构&#xff0c;现在来学一下MVP与MVVM两种架构&#xff0c;当然还有VIPER架构&#xff0c;如果有时间后面会单独学习 一、MVC MVC架构先前已经详细讲述&#xff0c;这里不再赘述&#xff0c;我们主要讲一…

打造清洁宜居家园保护自然生态环境,基于YOLOv7【tiny/l/x】参数系列模型开发构建自然生态场景下违规违法垃圾倾倒检测识别系统

自然生态环境&#xff0c;作为我们人类赖以生存的家园&#xff0c;其健康与否直接关系到我们的生活质量。然而&#xff0c;近年来&#xff0c;一些不法分子为了个人私利&#xff0c;在河边、路边等公共区域肆意倾倒垃圾&#xff0c;严重破坏了环境的健康与平衡。这种行为不仅损…

语音识别-paddlespeech-流程梳理

上一次研究语音识别是21年年底的事情了&#xff0c;记得当时是先进行了语音识别的应用&#xff0c;然后操作了模型的再次训练&#xff1b;两年过去&#xff0c;关于ASR相关流程忘得差不多了&#xff0c;这次基于paddlespeech的代码&#xff0c;进行了流程的梳理&#xff0c;关于…

【cpp】并发多线程 Unique

1. unique_lock 何时锁定资源。 unique_lock lock1 时候&#xff0c;还没有锁住资源。 实际是后面&#xff0c;显式的出发&#xff1a; 比如&#xff0c; lock.lock, 或 std::lock(lk1,lk2), 或者条件变量CV.wait(mtx, []{!re})。 #include <iostream> #include <mu…

HIVE大数据平台SQL优化分享

相信很多小伙伴在面试的时候,必然跳不过去的一个问题就是SQL脚本的优化,这是很多面试官爱问的问题,也是可以证明你实力进阶的一个重要的能力。 下面给大家分享一个重量级的大数据行业sql技能---hive大数据平台SQL优化。 此文章是大数据平台运维组从多维度参数(CPU,内存,…

vwmare虚拟机迁移磁盘方法

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文整理 虚拟机迁移磁盘的方法 简单方便快上手 当前目标 当前迁移文件: 当前位置&#xff1a; 目的地: e盘虚拟机文件夹 迁移到当前目录。 实际操作 先打开虚拟机的设置&#xff0c;找到这个虚拟机当前的位置…

苹果cms:伪静态设置教程

官方默认的网站模式是动态模式&#xff0c;动态模式下链接中自带有“index.php”想要去除网站链接中的index.php&#xff0c;首先需要开启网站的模式为伪静态模式。这样比动态模式那一长串的链接看着也舒服一些&#xff0c;最重要的是迎合搜索引擎的喜好加快收录提高排名。 1、…

HIVE解决连续登录问题

HIVE解决连续登录问题 目录 HIVE解决连续登录问题 1.解决连续登录问题 如何去分析数据&#xff1a; 2.需求&#xff1a; 3.-- 间隔天数 1.解决连续登录问题 如何去分析数据&#xff1a; 1&#xff09;查看数据的字段信息 …

Java进阶-SpringCloud设计模式-工厂模式的设计与详解

一、设计模式介绍 设计模式是我们开发中常常需要面对的核心概念&#xff0c;它们是解决特定问题的模板或者说是经验的总结。这些模式被设计出来是为了让软件设计更加清晰、代码更加可维护且能应对未来的变化。良好的设计模式不仅能解决重复代码的问题&#xff0c;还能使团队中…

计算机毕业设计 | SpringBoot健身房管理系统(附源码)

1&#xff0c;项目背景 随着人们生活水平的提高和健康意识的增强&#xff0c;健身行业逐渐兴起并迅速发展。而现代化的健身房管理系统已经成为健身房发展的必备工具之一。传统的健身房管理方式已经无法满足现代化健身房的需求&#xff0c;需要一种更加高效、智能、安全的管理系…

在云计算与人工智能中,7ECloud扮演着什么样的角色

数据驱动的时代&#xff0c;云计算和人工智能已成为推动现代科技进步的两大引擎。作为一家专注于云计算的公司&#xff0c;7ECloud正是在这个领域发挥自己的力量&#xff0c;力图为企业提供一站式解决方案&#xff0c;并拥有来自厂家的源头支持&#xff0c;用极其低的价格助力企…

【51】Camunda8-Zeebe核心引擎-Zeebe Gateway

概述 Zeebe网关是Zeebe集群的一个组件,它可以被视为Zeebe集群的联系点,它允许Zeebe客户端与Zeebe集群内的Zeebe代理进行通信。有关Zeebe broker的更多信息,请访问我们的附加文档。 总而言之,Zeebe broker是Zeebe集群的主要部分,它完成所有繁重的工作,如处理、复制、导出…

消息中间件是什么?有什么用?常见的消息中间件有哪些?

1.什么是消息中间件&#xff1f; 消息中间件基于队列模型在网络环境中为应用系统提供同步或异步、可靠的消息传输的支撑性软件系统。 2.现实中的痛点&#xff1a; 1.Http请求基于请求与响应的模型&#xff0c;在高并发的情况下&#xff0c;客户端发送大量的请求达到服务器端…

[华为OD]BFS C卷 200 智能驾驶

题目&#xff1a; 有一辆汽车需要从m*n的地图的左上角(起点)开往地图的右下角(终点)&#xff0c;去往每一个地区都需 要消耗一定的油量&#xff0c;加油站可进行加油 请你计算汽车确保从起点到达终点时所需的最少初始油量说明&#xff1a; (1)智能汽车可以上下左右四个方向…

PyQt5中的QGraphicsView()

文章目录 1. 简介2. 一个简单的示例2. 加载一幅图片3. 常用方法示例 1. 简介 QGraphicsView是PyQt5中用于显示图形场景的小部件&#xff0c;它提供了许多常用的方法来控制视图的行为和属性。下面是一些常用的QGraphicsView方法&#xff1a; setScene(scene): 设置要显示的场景…

GCP谷歌云有什么数据库类型,该怎么选择

GCP谷歌云提供的数据库类型主要包括&#xff1a; 关系型数据库&#xff1a;这类数据库适用于结构化数据&#xff0c;通常用于数据结构不经常发生变化的场合。在GCP中&#xff0c;关系型数据库选项包括Cloud SQL和Cloud Spanner。Cloud SQL提供托管的MySQL、PostgreSQL和SQL Se…