旅游网站建设策划书,监控网站模版,网站建设外包网,石家庄专业建站公司一. 游戏效果 贪吃蛇 二. 游戏背景 贪吃蛇是久负盛名的游戏#xff0c;它也和俄罗斯⽅块#xff0c;扫雷等游戏位列经典游戏的⾏列。 贪吃蛇起源于1977年的投币式墙壁游戏《Blockade》#xff0c;后移植到各种平台上。具体如下#xff1a; 起源。1977年#xff0c;投币式…一. 游戏效果 贪吃蛇 二. 游戏背景 贪吃蛇是久负盛名的游戏它也和俄罗斯⽅块扫雷等游戏位列经典游戏的⾏列。 贪吃蛇起源于1977年的投币式墙壁游戏《Blockade》后移植到各种平台上。具体如下 起源。1977年投币式墙壁游戏生产商Gremlin推出了经典的街机游戏《Blockade》两名玩家要分别控制角色移动角色会不停长大而且走过的地方会变成围栏谁先碰到围栏或碰到自己的身体就算输。 贪吃蛇最初的版本是像素版本后来又衍生出3D版本、多人对战版本等2 3。 三、游戏开发日志 四、知识准备 本次实现贪吃蛇会使⽤到的⼀些Win32 API知识那么就学习⼀下 4.1 Win32 API Windows 这个多作业系统除了协调应⽤程序的执⾏、分配内存、管理资源之外 它同时也是⼀个很⼤的服务中⼼调⽤这个服务中⼼的各种服务每⼀种服务就是⼀个函数可以帮应⽤程式达到开启 视窗、描绘图形、使⽤周边设备等⽬的由于这些函数服务的对象是应⽤程序(Application) 所以便 称之为 Application Programming Interface 简称 API 函数。 WIN32 API也就是Microsoft Windows 32位平台的应⽤程序编程接⼝。 4.2 控制台程序 平常我们运⾏起来的⿊框程序其实就是控制台程序。 我们可以使⽤cmd命令来设置控制台窗⼝的⻓宽也可以通过命令设置控制台窗⼝的名字 设置控制台窗⼝的⼤⼩30⾏100列设置控制台窗⼝的名字。 //控制台窗口设置
system(mode con cols100 lines35);
system(title 贪吃蛇); 4.3 控制台屏幕上的坐标COORD COORD 是Windows API中定义的⼀种结构表⽰⼀个字符在控制台屏幕上的坐标 typedef struct _COORD {
SHORT X;
SHORT Y;
} COORD, *PCOORD; 4.4 GetStdHandle GetStdHandle是⼀个Windows API函数。它⽤于从⼀个特定的标准设备标准输⼊、标准输出或标准错误中取得⼀个句柄⽤来标识不同设备的数值使⽤这个句柄可以操作设备。 HANDLE hOutput NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput GetStdHandle(STD_OUTPUT_HANDLE); 4.5 GetConsoleCursorInfo 检索有关指定控制台屏幕缓冲区的光标⼤⼩和可⻅性的信息 HANDLE hOutput NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, CursorInfo);//获取控制台光标信息 4.5.1 CONSOLE_CURSOR_INFO 这个结构体包含有关控制台游标的信息 typedef struct _CONSOLE_CURSOR_INFO {
DWORD dwSize;
BOOL bVisible;
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO; 1 dwSize由光标填充的字符单元格的百分⽐。 此值介于1到100之间。 光标外观会变化范围从完全填充单元格到单元底部的⽔平线条。 2 bVisible游标的可⻅性。 如果光标可⻅则此成员为 TRUE。 CursorInfo.bVisible false; //隐藏控制台光标 5.6 SetConsoleCursorInfo 设置指定控制台屏幕缓冲区的光标的⼤⼩和可⻅性。 HANDLE hOutput GetStdHandle(STD_OUTPUT_HANDLE);
//影藏光标操作
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, CursorInfo);//获取控制台光标信息
CursorInfo.bVisible false; //隐藏控制台光标
SetConsoleCursorInfo(hOutput, CursorInfo);//设置控制台光标状态 5.7 SetConsoleCursorPosition 设置指定控制台屏幕缓冲区中的光标位置我们将想要设置的坐标信息放在COORD类型的pos中调 ⽤SetConsoleCursorPosition函数将光标位置设置到指定的位置。 COORD pos { 10, 5};
HANDLE hOutput NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput GetStdHandle(STD_OUTPUT_HANDLE);
//设置标准输出上光标的位置为pos
SetConsoleCursorPosition(hOutput, pos); 温馨提示 这里我们可以将SetPos封装⼀个设置光标位置的函数 //设置光标的坐标
void SetPos(short x, short y)
{
COORD pos { x, y };
HANDLE hOutput NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput GetStdHandle(STD_OUTPUT_HANDLE);
//设置标准输出上光标的位置为pos
SetConsoleCursorPosition(hOutput, pos);
} 5.8 GetAsyncKeyState 获取按键情况将键盘上每个键的虚拟键值传递给函数函数通过返回值来分辨按键的状态。 返回值是short类型在上⼀次调⽤ GetAsyncKeyState 函数后如果 返回的16位的short数据中最⾼位是1说明按键的状态是按下如果最⾼是0说明按键的状态是抬起如果最低位被置为1则说明该按键被按过否则为0。 如果我们要判断⼀个键是否被按过可以检测GetAsyncKeyState返回值的最低值是否为1. 我们这里定义一个宏 #define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) 0x1) ? 1 : 0 ) 5.9 宽字符打印 在游戏地图上我们打印墙体使⽤宽字符□打印蛇使⽤宽字符●打印⻝物使⽤宽字符■ 普通的字符是占⼀个字节的这类宽字符是俩个字节。 5.9.1 setlocale函数 char* setlocale (int category, const char* locale); setlocale 函数⽤于修改当前地区可以针对⼀个类项修改也可以针对所有类项。 setlocale 的第⼀个参数如果是LC_ALL就会影响所有的类项。 C标准给第⼆个参数仅定义了2种可能取值C和 。 在任意程序执⾏开始都会隐藏式执⾏调⽤: setlocale(LC_ALL, C); 当地区设置为C时库函数按正常⽅式执⾏. 当地区设置为 时这种模式下程序会适应本地环境。⽐如切换到我们的本地模式后就⽀ 持宽字符汉字的输出等。 setlocale(LC_ALL, );//切换到本地环境 宽字符的打印如下 #include stdio.h
#includelocale.h
int main() {
setlocale(LC_ALL, );
wchar_t ch1 L●;
wprintf(L%c\n, ch1);
return 0;
} 五、游戏实现 5.1 游戏逻辑主体 #define _CRT_SECURE_NO_WARNINGS
#includesnake.h
#includelocale.h
#includestdio.h
int main()
{char ch;setlocale(LC_ALL, );//切换到本地环境,支持宽字符srand((unsigned int)time(NULL));do{Snake snake { 0 };GameInit(snake);GameRun(snake);GameOver(snake);printf(小垃圾还要再来吗是Y,否N\n);ch getchar();getchar();} while (ch y || ch Y);return 0;
}5.2 游戏初始化实现 #define _CRT_SECURE_NO_WARNINGS
#includesnake.h#define WALL L□
#define BODY L●
#define FOOD L█
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, 13);printf(欢迎来到贪吃蛇小游戏);SetPos(42, 22);system(pause);//会显示按任意键继续的信息按任意键后继续执行下一步system(cls);SetPos(25, 12);printf(↑ . ↓ . ← . → 分别控制蛇的移动 F3为加速F4为减速\n);SetPos(42, 22);system(pause);//会显示按任意键继续的信息按任意键后继续执行下一步system(cls);/*getchar();*/}
void CreateMap()
{SetPos(0,0);int i 0;for(i0;i58;ii2){wprintf(L%c, WALL);}SetPos(0, 26);for (i 0; i 58; i i 2){wprintf(L%c, WALL);}for (i 1; i 26; i){SetPos(0, i);wprintf(L%c, WALL);}for (i 1; i 26; i){SetPos(56, i);wprintf(L%c, WALL);}/*getchar();*/
}void InitSnake(Snake* snake)
{//初始化蛇身for (int i 0; i 5; i){SnakeNode* node (SnakeNode*)malloc(sizeof(SnakeNode));node-x 24 2 * i;node-y 15;node-next NULL;if (snake-pSnake NULL){snake-pSnake node;}else{node-next snake-pSnake;snake-pSnake node;}}SnakeNode* cur snake-pSnake;while (cur){int x cur-x;int y cur-y;SetPos(x, y);wprintf(L%c, BODY);cur cur-next;}snake-status RUN;snake-dir RIGHT;snake-FoodWeight 10;snake-pFood NULL;snake-score 0;snake-SleepTime 200;
}
void CreateFood(Snake* snake)
{int x 0;int y 0;again:do{x rand() % 53 2;y rand() % 24 1;} while (x % 2 ! 0);SnakeNode* cur snake-pSnake;do{if (x cur-x y cur-y){goto again;}cur cur-next;} while (cur);SnakeNode* food (SnakeNode*)malloc(sizeof(SnakeNode));food-x x;food-y y;snake-pFood food;SetPos(x, y);wprintf(L%c, FOOD);/*getchar();*/}void GameInit(Snake* snake)
{//控制台窗口设置system(mode con cols100 lines35);system(title 贪吃蛇);//隐藏光标HANDLE hOutput GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(hOutput, CursorInfo);//获取控制台光标信息CursorInfo.bVisible false; //隐藏控制台光标SetConsoleCursorInfo(hOutput, CursorInfo);//设置控制台光标状态//打印欢迎界面WelcomeToGame();//创建地图CreateMap();//初始化贪吃蛇InitSnake(snake);//创建食物CreateFood(snake);
}5.3 游戏运行实现 void PrintHelpInfo()
{SetPos(60, 13);printf(1. 不能穿墙不能咬到自己\n);SetPos(60, 14);printf(2.↑.↓.←.→分别控制蛇的移动\n);SetPos(60, 15);printf(3. F3为加速F4为减速\n);SetPos(60, 16);printf(4. ESC-退出空格-暂停\n);
}void Pause()
{while (1){Sleep(200);if (KEY_PRESS(VK_SPACE) 1){break;}}}
void EatFood(Snake* snake, SnakeNode* snakenext)
{snakenext-next snake-pSnake;snake-pSnake snakenext;SnakeNode* cur snake-pSnake;while (cur){SetPos(cur-x, cur-y);wprintf(L%lc, BODY);cur cur-next;}free(snake-pFood);snake-pFood NULL;CreateFood(snake);}
void NoEatFood(Snake* snake, SnakeNode* snakenext)
{snakenext-next snake-pSnake;snake-pSnake snakenext;SnakeNode* cur snake-pSnake;while (cur-next-next){SetPos(cur-x, cur-y);wprintf(L%lc, BODY);cur cur-next;}SetPos(cur-x, cur-y);wprintf(L%lc, BODY);SetPos(cur-next-x, cur-next-y);printf( );free(cur-next);cur-next NULL;
}void SnakeMove(Snake* snake)
{SnakeNode* snakenext (SnakeNode*)malloc(sizeof(SnakeNode));if (snake-dir UP){snakenext-x snake-pSnake-x;snakenext-y snake-pSnake-y -1;snakenext-next NULL;}else if (snake-dir DOWN){snakenext-x snake-pSnake-x;snakenext-y snake-pSnake-y 1;snakenext-next NULL;}if (snake-dir LEFT){snakenext-x snake-pSnake-x-2;snakenext-y snake-pSnake-y ;snakenext-next NULL;}if (snake-dir RIGHT){snakenext-x snake-pSnake-x 2;snakenext-y snake-pSnake-y;snakenext-next NULL;}//判断下一个节点是否为食物if (snakenext-x snake-pFood-x snakenext-y snake-pFood-y){EatFood(snake,snakenext);//吃食物snake-score snake-FoodWeight;}else{NoEatFood(snake,snakenext);//不吃食物}//碰撞检测if (snake-pSnake-x 0 || snake-pSnake-x 56 || snake-pSnake-y 0 || snake-pSnake-y 26){snake-status KILL_BY_WALL;}SnakeNode* cur snake-pSnake-next;while (cur){if (cur-x snake-pSnake-x cur-y snake-pSnake-y){snake-status KILL_BY_SELF;}cur cur-next;}
}void GameRun(Snake* snake)
{//打印帮助信息PrintHelpInfo();do{SetPos(60, 8);printf(游戏总得分%5d , snake-score);SetPos(60, 9);printf(每个食物的分数%2d , snake-FoodWeight);if (KEY_PRESS(VK_UP) 1snake-dir!DOWN){snake-dir UP;}else if (KEY_PRESS(VK_DOWN) 1 snake-dir ! UP){snake-dir DOWN;}else if (KEY_PRESS(VK_RIGHT) 1 snake-dir ! LEFT){snake-dir RIGHT;}else if (KEY_PRESS(VK_LEFT) 1 snake-dir ! RIGHT){snake-dir LEFT;}else if (KEY_PRESS(VK_F3) 1){if (snake-SleepTime80){snake-SleepTime - 30;snake-FoodWeight 2;}}else if (KEY_PRESS(VK_F4) 1){if (snake-SleepTime320){snake-SleepTime 30;snake-FoodWeight - 2;}}else if (KEY_PRESS(VK_ESCAPE) 1){snake-status OVER;break;}else if (KEY_PRESS(VK_SPACE) 1){Pause();}SnakeMove(snake);Sleep(snake-SleepTime);//每一帧停0.2s} while (snake-statusRUN);
}5.4 游戏结束实现 void GameOver(Snake* snake)
{switch (snake-status){case KILL_BY_WALL:SetPos(20, 15);printf(你已经撞墙了小垃圾\n);break;case KILL_BY_SELF:SetPos(20, 15);printf(你已经自杀了小垃圾\n);break;case OVER:SetPos(20, 15);printf(你退出游戏了小垃圾\n);break;}SetPos(0, 29);} 六、 完整代码 6.1 snake.h #define _CRT_SECURE_NO_WARNINGS
#includestdbool.h
#includestdio.h
#includewindows.h
#includestdlib.h
#includetime.h
#define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) 0x1) ? 1 : 0 )
enum direction{UP 1, DOWN, LEFT, RIGHT};//蛇的方向
enum game_status{RUN,KILL_BY_WALL,KILL_BY_SELF,OVER};typedef struct SnakeNode
{int x;int y;struct SnakeNode* next;
}SnakeNode;typedef struct Snake
{SnakeNode* pSnake;//指向贪吃蛇头节点SnakeNode* pFood;//指向食物的节点int score;int FoodWeight;int SleepTime;enum direction dir;//蛇的方向enum game_status status;//游戏状态
}Snake;
void GameInit(Snake*snake);
void WelcomeToGame();
void CreateMap();
void InitSnake(Snake* snake);
void CreateFood(Snake* snake);
void GameRun(Snake* snake);
void PrintHelpInfo();
void Pause();
void SnakeMove(Snake* snake);void EatFood(Snake* snake,SnakeNode*snakenext);
void NoEatFood(Snake* snake, SnakeNode* snakenext);
void GameOver(Snake* snake); 6.2 snake.c #define _CRT_SECURE_NO_WARNINGS
#includesnake.h#define WALL L□
#define BODY L●
#define FOOD L█
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, 13);printf(欢迎来到贪吃蛇小游戏);SetPos(42, 22);system(pause);//会显示按任意键继续的信息按任意键后继续执行下一步system(cls);SetPos(25, 12);printf(↑ . ↓ . ← . → 分别控制蛇的移动 F3为加速F4为减速\n);SetPos(42, 22);system(pause);//会显示按任意键继续的信息按任意键后继续执行下一步system(cls);/*getchar();*/}
void CreateMap()
{SetPos(0,0);int i 0;for(i0;i58;ii2){wprintf(L%c, WALL);}SetPos(0, 26);for (i 0; i 58; i i 2){wprintf(L%c, WALL);}for (i 1; i 26; i){SetPos(0, i);wprintf(L%c, WALL);}for (i 1; i 26; i){SetPos(56, i);wprintf(L%c, WALL);}/*getchar();*/
}void InitSnake(Snake* snake)
{//初始化蛇身for (int i 0; i 5; i){SnakeNode* node (SnakeNode*)malloc(sizeof(SnakeNode));node-x 24 2 * i;node-y 15;node-next NULL;if (snake-pSnake NULL){snake-pSnake node;}else{node-next snake-pSnake;snake-pSnake node;}}SnakeNode* cur snake-pSnake;while (cur){int x cur-x;int y cur-y;SetPos(x, y);wprintf(L%c, BODY);cur cur-next;}snake-status RUN;snake-dir RIGHT;snake-FoodWeight 10;snake-pFood NULL;snake-score 0;snake-SleepTime 200;
}
void CreateFood(Snake* snake)
{int x 0;int y 0;again:do{x rand() % 53 2;y rand() % 24 1;} while (x % 2 ! 0);SnakeNode* cur snake-pSnake;do{if (x cur-x y cur-y){goto again;}cur cur-next;} while (cur);SnakeNode* food (SnakeNode*)malloc(sizeof(SnakeNode));food-x x;food-y y;snake-pFood food;SetPos(x, y);wprintf(L%c, FOOD);/*getchar();*/}void GameInit(Snake* snake)
{//控制台窗口设置system(mode con cols100 lines35);system(title 贪吃蛇);//隐藏光标HANDLE hOutput GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(hOutput, CursorInfo);//获取控制台光标信息CursorInfo.bVisible false; //隐藏控制台光标SetConsoleCursorInfo(hOutput, CursorInfo);//设置控制台光标状态//打印欢迎界面WelcomeToGame();//创建地图CreateMap();//初始化贪吃蛇InitSnake(snake);//创建食物CreateFood(snake);
}void PrintHelpInfo()
{SetPos(60, 13);printf(1. 不能穿墙不能咬到自己\n);SetPos(60, 14);printf(2.↑.↓.←.→分别控制蛇的移动\n);SetPos(60, 15);printf(3. F3为加速F4为减速\n);SetPos(60, 16);printf(4. ESC-退出空格-暂停\n);
}void Pause()
{while (1){Sleep(200);if (KEY_PRESS(VK_SPACE) 1){break;}}}
void EatFood(Snake* snake, SnakeNode* snakenext)
{snakenext-next snake-pSnake;snake-pSnake snakenext;SnakeNode* cur snake-pSnake;while (cur){SetPos(cur-x, cur-y);wprintf(L%lc, BODY);cur cur-next;}free(snake-pFood);snake-pFood NULL;CreateFood(snake);}
void NoEatFood(Snake* snake, SnakeNode* snakenext)
{snakenext-next snake-pSnake;snake-pSnake snakenext;SnakeNode* cur snake-pSnake;while (cur-next-next){SetPos(cur-x, cur-y);wprintf(L%lc, BODY);cur cur-next;}SetPos(cur-x, cur-y);wprintf(L%lc, BODY);SetPos(cur-next-x, cur-next-y);printf( );free(cur-next);cur-next NULL;
}void SnakeMove(Snake* snake)
{SnakeNode* snakenext (SnakeNode*)malloc(sizeof(SnakeNode));if (snake-dir UP){snakenext-x snake-pSnake-x;snakenext-y snake-pSnake-y -1;snakenext-next NULL;}else if (snake-dir DOWN){snakenext-x snake-pSnake-x;snakenext-y snake-pSnake-y 1;snakenext-next NULL;}if (snake-dir LEFT){snakenext-x snake-pSnake-x-2;snakenext-y snake-pSnake-y ;snakenext-next NULL;}if (snake-dir RIGHT){snakenext-x snake-pSnake-x 2;snakenext-y snake-pSnake-y;snakenext-next NULL;}//判断下一个节点是否为食物if (snakenext-x snake-pFood-x snakenext-y snake-pFood-y){EatFood(snake,snakenext);//吃食物snake-score snake-FoodWeight;}else{NoEatFood(snake,snakenext);//不吃食物}//碰撞检测if (snake-pSnake-x 0 || snake-pSnake-x 56 || snake-pSnake-y 0 || snake-pSnake-y 26){snake-status KILL_BY_WALL;}SnakeNode* cur snake-pSnake-next;while (cur){if (cur-x snake-pSnake-x cur-y snake-pSnake-y){snake-status KILL_BY_SELF;}cur cur-next;}
}void GameRun(Snake* snake)
{//打印帮助信息PrintHelpInfo();do{SetPos(60, 8);printf(游戏总得分%5d , snake-score);SetPos(60, 9);printf(每个食物的分数%2d , snake-FoodWeight);if (KEY_PRESS(VK_UP) 1snake-dir!DOWN){snake-dir UP;}else if (KEY_PRESS(VK_DOWN) 1 snake-dir ! UP){snake-dir DOWN;}else if (KEY_PRESS(VK_RIGHT) 1 snake-dir ! LEFT){snake-dir RIGHT;}else if (KEY_PRESS(VK_LEFT) 1 snake-dir ! RIGHT){snake-dir LEFT;}else if (KEY_PRESS(VK_F3) 1){if (snake-SleepTime80){snake-SleepTime - 30;snake-FoodWeight 2;}}else if (KEY_PRESS(VK_F4) 1){if (snake-SleepTime320){snake-SleepTime 30;snake-FoodWeight - 2;}}else if (KEY_PRESS(VK_ESCAPE) 1){snake-status OVER;break;}else if (KEY_PRESS(VK_SPACE) 1){Pause();}SnakeMove(snake);Sleep(snake-SleepTime);//每一帧停0.2s} while (snake-statusRUN);
}void GameOver(Snake* snake)
{switch (snake-status){case KILL_BY_WALL:SetPos(20, 15);printf(你已经撞墙了小垃圾\n);break;case KILL_BY_SELF:SetPos(20, 15);printf(你已经自杀了小垃圾\n);break;case OVER:SetPos(20, 15);printf(你退出游戏了小垃圾\n);break;}SetPos(0, 29);}6.3 text.c #define _CRT_SECURE_NO_WARNINGS
#includesnake.h
#includelocale.h
#includestdio.h
int main()
{char ch;setlocale(LC_ALL, );//切换到本地环境,支持宽字符srand((unsigned int)time(NULL));do{Snake snake { 0 };GameInit(snake);GameRun(snake);GameOver(snake);printf(小垃圾还要再来吗是Y,否N\n);ch getchar();getchar();} while (ch y || ch Y);return 0;
}