实现贪吃蛇小游戏【简单版】
1. 贪吃蛇游戏设计与分析
1.1 地图
我们最终的贪吃蛇大纲要是这个样子,那我们的地图如何布置呢?




1.1.1 <locale.h>本地化
1.1.2 类项
1.1.3 setlocale函数
char* setlocale (int category, const char* locale); setlocale(LC_ALL, "C"); setlocale(LC_ALL, "");//切换到本地环境 #include <locale.h>
int main()
{char* loc;loc = setlocale(LC_ALL, NULL);printf("默认的本地信息:%s\n", loc);loc = setlocale(LC_ALL, "");printf("设置后的本地信息: %s\n", loc);return 0;
} 1.1.4 宽字符的打印
#include <stdio.h>
#include<locale.h>
int main()
{setlocale(LC_ALL, "");wchar_t ch1 = L'●';wchar_t ch2 = L'⽐';wchar_t ch3 = L'特';wchar_t ch4 = L'★';printf("%c%c\n", 'a', 'b');wprintf(L"%lc\n", ch1);wprintf(L"%lc\n", ch2);wprintf(L"%lc\n", ch3);wprintf(L"%lc\n", ch4);return 0;
} 

1.1.5 地图坐标

1.2 蛇身和食物

1.3 数据结构设计
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 _foodWeight;//默认每个⻝物10分int _SleepTime;//每⾛⼀步休眠时间
}Snake, * pSnake; //⽅向
enum DIRECTION
{UP = 1,DOWN,LEFT,RIGHT
}; //游戏状态
enum GAME_STATUS
{OK,//正常运⾏KILL_BY_WALL,//撞墙KILL_BY_SELF,//咬到⾃⼰END_NOMAL//正常结束
}; 1.4 游戏流程设计

2. 核心逻辑实现分析
2.1 游戏主逻辑
#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;
} 2.2 游戏开始(GameStart)
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);
} 2.2.1 打印欢迎界面
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");
} 2.2.2 创建地图
#define WALL 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);}//x是56,y从1开始增⻓for (i = 1; i < 26; i++){SetPos(56, i);wprintf(L"%c", WALL);}
} 
2.2.3 初始化蛇身
#define BODY L'●' 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"%lc", BODY);cur = cur->next;}//初始化贪吃蛇数据ps->_SleepTime = 200;ps->_Socre = 0;ps->_Status = OK;ps->_Dir = RIGHT;ps->_foodWeight = 10;
} 
2.2.4 创建第⼀个食物
#define FOOD L'★' 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;}
} 
2.3 游戏运行(GameRun)
void GameRun(pSnake ps)
{//打印右侧帮助信息PrintHelpInfo();do{SetPos(64, 10);printf("得分:%d ", ps->_Socre);printf("每个⻝物得分:%d分", ps->_foodWeight);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 >= 80){ps->_SleepTime -= 30;ps->_foodWeight += 2;//⼀个⻝物分数最⾼是20分}}else if (KEY_PRESS(VK_F4)){if (ps->_SleepTime < 320){ps->_SleepTime += 30;ps->_foodWeight -= 2;//⼀个⻝物分数最低是2分}}//蛇每次⼀定之间要休眠的时间,时间短,蛇移动速度就快Sleep(ps->_SleepTime);SnakeMove(ps);} while (ps->_Status == OK);
} 2.3.1 KEY_PRESS
#define KEY_PRESS(VK) ((GetAsyncKeyState(VK)&0x1) ? 1 : 0) 2.3.2 PrintHelpInfo
void PrintHelpInfo()
{//打印提⽰信息SetPos(64, 15);printf("不能穿墙,不能咬到⾃⼰\n");SetPos(64, 16);printf("⽤↑.↓.←.→分别控制蛇的移动.");SetPos(64, 17);printf("F3 为加速,F4 为减速\n");SetPos(64, 18);printf("ESC :退出游戏.space:暂停游戏.");SetPos(64, 20);printf("⽐特就业课@版权");
} 
2.3.3 蛇身移动(SnakeMove)
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);
} 2.3.3.1 NextIsFood
//pSnakeNode psn 是下⼀个节点的地址
//pSnake ps 维护蛇的指针
int NextIsFood(pSnakeNode psn, pSnake ps)
{return (psn->x == ps->_pFood->x) && (psn->y == ps->_pFood->y);
} 2.3.3.2 EatFood
//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->_foodWeight;//释放⻝物节点free(ps->_pFood);//创建新的⻝物CreateFood(ps);
} 
2.3.3.3 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);cur = cur->next;}//最后⼀个位置打印空格,然后释放节点SetPos(cur->next->x, cur->next->y);printf(" ");free(cur->next);cur->next = NULL;} 
2.3.3.4 KillByWall
//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;} 
2.3.3.5 KillBySelf
//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;} 
2.4 游戏结束
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);}
}
3. 参考代码
#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' || ch == 'y');SetPos(0, 27);
}int main()
{//修改当前地区为本地模式,为了⽀持中⽂宽字符的打印setlocale(LC_ALL, "");//测试逻辑test();return 0;
} #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 _foodWeight;//默认每个⻝物10分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); #include "Snake.h"
//设置光标的坐标
void SetPos(short x, short y)
{COORD pos = { x, y };HANDLE hOutput = NULL;//获取标准输出的句柄(⽤来标识不同设备的数值)hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//设置标准输出上光标的位置为posSetConsoleCursorPosition(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);}//左//x是0,y从1开始增⻓for (i = 1; i < 26; i++){SetPos(0, i);wprintf(L"%c", WALL);}//x是56,y从1开始增⻓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->_foodWeight = 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()
{//打印提⽰信息SetPos(64, 15);printf("不能穿墙,不能咬到⾃⼰\n");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(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->_foodWeight;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->_foodWeight);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->_foodWeight += 2;}}else if (KEY_PRESS(VK_F4)){if (ps->_SleepTime < 350){ps->_SleepTime += 30;ps->_foodWeight -= 2;if (ps->_SleepTime == 350){ps->_foodWeight = 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);}
} 今天我们将学会实现贪吃蛇小游戏,如果本篇有不理解的地方,欢迎私信我或在评论区指出,期待与你们共同进步。创作不易,望各位大佬一键三连!
相关文章:
实现贪吃蛇小游戏【简单版】
1. 贪吃蛇游戏设计与分析 1.1 地图 我们最终的贪吃蛇大纲要是这个样子,那我们的地图如何布置呢? 这里不得不讲⼀下控制台窗口的⼀些知识,如果想在控制台的窗口中指定位置输出信息,我们得知道该位置的坐标,所以首先介…...
uniapp实现内嵌其他网页的功能
一、用到的知识点 页面跳转页面间跳转,参数传递web-view使用 二、使用navigator 页面跳转。 navigator 组件类似HTML中的<a>组件,但只能跳转本地页面。目标页面必须在pages.json中注册。所以这么写是不行的: <navigator url&quo…...
【Ruby简单脚本01】查看wifi密码
脚本 # 使用io库 def get_cmd_result(cmd) IO.popen(cmd,:external_encoding>GBK).read.encode("utf-8") end def list_wifi wifi_pwds Hash.new # 获取所有wifi文件 o1 get_cmd_result("netsh wlan show profiles") # 获取所有匹配结果 …...
VSG/VSA 矢量信号模拟/分析软件
_Ceyear思仪 _ VSG/VSA 矢量信号模拟/分析软件 苏州新利通仪器仪表 在现代无线通信中,IQ调制属于标准配置,经常应用于通信系统的信号调制和解调环节。IQ调制的应用简化了通信设备的硬件结构,同时提高了频谱资源的利用效率,提…...
C++使用GDAL库完成tiff图像的合并
全色图 完整代码: #include "gdal_priv.h" #include "cpl_string.h" #include <vector> #include <algorithm> #include <iostream> #include <filesystem>using namespace std; namespace fs std::filesystem; vec…...
深入理解AQS:Java并发编程中的核心组件
目录 AQS简介AQS的设计思路AQS的核心组成部分 状态(State)同步队列(Sync Queue)条件队列(Condition Queue) AQS的内部实现 节点(Node)锁的获取与释放 独占锁共享锁 条件变量 AQS的应…...
集合进阶:List集合
一.List集合的特有方法 1.Collection的方法List都继承了 2.List集合因为有索引,所以多了很多索引操作的方法。 3.add // 1.创建一个集合List<String> list new ArrayList<>(); // 2.添加元素list.add("aaa");list.add("bbb"…...
el-table表头修改文字或者背景颜色,通过header-row-style设置样式
方式一 <el-table :header-cell-style"{text-align: center}" />方式二 <template><el-table :header-cell-style"tableHeaderColor" /> </template> <script> export default {methods: {tableHeaderColor ({row, column…...
web前端-CSS
CSS CSS概述: CSS是Cascading Style Sheets(级联样式表),是一种样式表语言,用于控制网页布局,外观(比如背景图片,图片高度,文本颜色,文本字体,高级定位等等) 可将页面的内容与样式分离开,样式放于单独的.css文件或者HTML某处 CSS是网页样式,HTML是网页…...
u8g2 使用IIC驱动uc1617 lcd 字符显示只显示上半部分,不显示下半部
使用u8g2 使用硬件iic驱动某些page为4个字节 带灰度的lcd显示屏幕的时候有时候只显示上半部,下半部不显示,例如uc1617等。 原因: 以uc1617为例,链接https://github.com/olikraus/u8g2/blob/master/csrc/u8x8_d_uc1617.c 在u8x8_d_uc1617_common方法中的case U8X8_MSG_DI…...
单片机第五季-第八课:STM32CubeMx和FreeRTOS
1,FreeRTOS背景介绍 RTOS简介: 实时操作系统,本用于追求实时性的嵌入式系统,典型:ucos/uclinux/vxworks; 特点:中断响应快、一般可嵌套中断、使用实地址、多任务; (实…...
【Linux】进程控制1——进程创建和进程终止
1.进程创建 1.1.再谈fork 在linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。 #include <unistd.h> pid_t fork(void);//pid_t为整形 返回值:子进程中的fork()返回0ÿ…...
计算机图形学入门16:曲线
1.曲线 曲线(Curves)在图形学中应用非常广泛,比如:相机的拍摄路径、物体的移动路径、动画曲线、矢量字体等。如下图所示,是使用曲线到矢量字体的应用,通过移动一些控制点来改变字体。 2.贝塞尔曲线 2.1 贝…...
【Ruby基础01】windows和termux中搭建Ruby开发环境
windows下环境搭建 railsinstaller官方git地址 按照文档安装git、nodejs、yarn,安装教程百度一下。railsinstall可以从release页面下载最新版本4.1.0。 安装完成如下 安装RubyMine 下载RubyMine RubyMine下载地址 安装激活 下载文件,按照里面的流程…...
2406c++,iguana动态反射
原文 iguana是一个基于编译期反射的序化库,支持从结构序化到不同数据格式. iguana可序化一个C结构到json,xml,yaml和protobuf格式.这都是通过编译期反射实现的. 现在iguana也支持了动态反射,主要特征: 1,通过对象名创建对象实例 2,取对象所有字段名 3,根据字段名取字段值 4,根…...
干货分享——AB站帮你解决独立站收款难题
目前,国内已经有抖音、拼多多和淘宝平台推出“仅退款”售后服务,无疑是加剧了原本就在疯狂打价格战的国内电商的严峻现状,使得商家不得不担心被顾客“薅羊毛”。在国内电商环境严重“内卷”的情况下,拓宽海外市场不失为一大妙计。…...
C++继承与派生
1.基本知识 类的继承是新类从已有类那里获得特性,从已有的类产生新类的过程称为类的派生; 已有类称为基类或父类,派生出的新类则称为派生类或子类; 继承的功能: (1)使得基类与派生类之间建立…...
Survival Animations
一套生存游戏的动画集,包括采集、建造、捕鱼、剥皮/鞣制、篝火等更多内容。 总动画数:89 建造/制作 30 篝火 28 饮水 3 水壶 3 觅食 2 治疗 3 空闲 1 原始捕鱼 7 剥皮 1 矛捕鱼 4 伐木 5 下载:Unity资源商店链接资源下载链接 效果图:...
Cargo 教程
Cargo 教程 1. 引言 Cargo 是 Rust 编程语言的包管理器和构建工具。它为 Rust 项目提供了依赖管理、编译和打包等功能。本教程将详细介绍 Cargo 的基本用法,帮助您快速上手 Rust 项目开发。 2. 安装 Cargo 在开始使用 Cargo 之前,您需要确保已经安装了 Rust 编程语言。Ru…...
linux中“PXE高效批量装机”
在大规模的 Linux 应用环境中,如 Web 群集、分布式计算等,服务器往往并不配备光驱设备,在这种情况下,如何为数十乃至上百台服务器裸机快速安装系统呢?传统的 USB光驱、移动硬盘等安装方法显然已经难以满足需求。 PXE …...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent
安全大模型训练计划:基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标:为安全大模型创建高质量、去偏、符合伦理的训练数据集,涵盖安全相关任务(如有害内容检测、隐私保护、道德推理等)。 1.1 数据收集 描…...
论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving
地址:LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂,正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...
stm32wle5 lpuart DMA数据不接收
配置波特率9600时,需要使用外部低速晶振...
