石家庄模板建站行业解决方案,网站建设与管理项目1项目规划,网页设计dw实训报告,产品代理推广方案个人简介#xff1a;双非大二学生 个人博客#xff1a;Monodye 今日鸡汤#xff1a;人生就像一盒巧克力#xff0c;你永远不知道下一块是什么味的 C语言基础刷题#xff1a;牛客网在线编程_语法篇_基础语法 (nowcoder.com) 一.贪吃蛇游戏背景 贪吃蛇是久负盛名的游戏… 个人简介双非大二学生 个人博客Monodye 今日鸡汤人生就像一盒巧克力你永远不知道下一块是什么味的 C语言基础刷题牛客网在线编程_语法篇_基础语法 (nowcoder.com) 一.贪吃蛇游戏背景 贪吃蛇是久负盛名的游戏它也和俄罗斯⽅块扫雷等游戏位列经典游戏的⾏列。 在编程语⾔的教学中我们以贪吃蛇为例从设计到代码实现来提升学⽣的编程能⼒和逻辑能⼒。 二.游戏实现过程 大致分为三个大模块 GameStart完成游戏的初始化打印GameRun游戏运行时各个功能的实现GameEnd游戏结束以后的一些善后工作 2.1游戏功能 实现基本的功能 • 贪吃蛇地图绘制 • 蛇吃⻝物的功能 上、下、左、右⽅向键控制蛇的动作 • 蛇撞墙死亡 • 蛇撞⾃⾝死亡 • 计算得分 • 蛇⾝加速、减速 • 暂停游戏 2.2需要掌握的知识 C语⾔函数、枚举、结构体、动态 内存管理、预处理指令、链表、Win32 API等。 三.Win32API
3.1Win32API介绍 Windows 这个多作业系统除了协调应⽤程序的执⾏、分配内存、管理资源之外 它同时也是⼀个很⼤ 的服务中⼼调⽤这个服务中⼼的各种服务每⼀种服务就是⼀个函数可以帮应⽤程序达到开启 视窗、描绘图形、使⽤周边设备等⽬的由于这些函数服务的对象是应⽤程序(Application) 所以便 称之为 Application Programming Interface简称 API 函数。WIN32 API也就是Microsoft Windows 32位平台的应⽤程序编程接⼝。 3.2控制台程序 平常我们运⾏起来的⿊框程序其实就是控制台程序 我们可以使⽤cmd命令来设置控制台窗⼝的⻓宽设置控制台窗⼝的⼤⼩30⾏100列 mode con cols100 lines30 也可以通过命令设置控制台窗口的名字 title 贪吃蛇 这些命令我们使用C语言的system便可以实现 #include stdio.h
int main()
{//设置控制台窗⼝的⻓宽设置控制台窗⼝的⼤⼩30⾏100列system(mode con cols100 lines30);//设置cmd窗⼝名称system(title 贪吃蛇); return 0;
} 这里我们可以在后面实现的时候加一个getchar防止程序运行结束无法确定窗口是否设置成功。 这样就设置好了。 3.3控制台屏幕上的坐标COORD COORD 是Windows API中定义的⼀个结构体表⽰⼀个字符在控制台屏幕上的坐标 typedef struct _COORD {SHORT X;SHORT Y;
} COORD, *PCOORD;
通过这样一个结构体我们就可以给得到控制台上的坐标了。
这里我们可以设置一个坐标 COORD pos { 10, 15 }; 3.4GetStdHandle GetStdHandle是⼀个Windows API函数。它⽤于从⼀个特定的标准设备标准输⼊、标准输出或标 准错误中取得⼀个句柄⽤来标识不同设备的数值使⽤这个句柄可以操作设备。 它就像炒菜的手柄你想获得API函数的操作权就得有一个可以获得他们的手柄。
举个例子
HANDLE hOutput NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput GetStdHandle(STD_OUTPUT_HANDLE);
3.5GetConsoleCursorInfo 检索有关指定控制台屏幕缓冲区的光标⼤⼩和可⻅性的信息 其实就是获得光标的操作权。 举个例子
HANDLE hOutput NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, CursorInfo);//获取控制台光标信息
3.6CONSOLE_CURSOR_INFO 这个结构体包含有关控制台光标的信息可以通过它来得到光标的两个参数可见性光标所占的百分比 typedef struct _CONSOLE_CURSOR_INFO {DWORD dwSize;BOOL bVisible;
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO; 3.7SetConsoleCursorInfo 设置指定控制台屏幕缓冲区的光标的⼤⼩和可⻅性。 举个例子 HANDLE hOutput GetStdHandle(STD_OUTPUT_HANDLE);
//影藏光标操作
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, CursorInfo);//获取控制台光标信息
CursorInfo.bVisible false; //隐藏控制台光标
SetConsoleCursorInfo(hOutput, CursorInfo);//设置控制台光标状态 3.8 SetConsoleCursorPosition 设置指定控制台屏幕缓冲区中的光标位置我们将想要设置的坐标信息放在COORD类型的pos中调 ⽤SetConsoleCursorPosition函数将光标位置设置到指定的位置。 COORD pos { 10, 5};HANDLE hOutput NULL;//获取标准输出的句柄(⽤来标识不同设备的数值)hOutput GetStdHandle(STD_OUTPUT_HANDLE);//设置标准输出上光标的位置为posSetConsoleCursorPosition(hOutput, pos); 这里我们可以利用上面讲到的知识实现一个设置光标位置的函数
//设置光标的坐标
void SetPos(short x, short y)
{COORD pos { x, y };HANDLE hOutput NULL;//获取标准输出的句柄(⽤来标识不同设备的数值)hOutput GetStdHandle(STD_OUTPUT_HANDLE);
//设置标准输出上光标的位置为posSetConsoleCursorPosition(hOutput, pos);
}
3.9GetAsyncKeyState 获取按键情况GetAsyncKeyState的函数原型如下
SHORT GetAsyncKeyState(int vKey
); 将键盘上每个键的虚拟键值传递给函数函数通过返回值来分辨按键的状态。 GetAsyncKeyState 的返回值是short类型在上⼀次调⽤ GetAsyncKeyState 函数后如果 返回的16位的short数据中最⾼位是1说明按键的状态是按下如果最⾼是0说明按键的状态是抬 起如果最低位被置为1则说明该按键被按过否则为0。 如果我们要判断⼀个键是否被按过可以检测GetAsyncKeyState返回值的最低值是否为1. 我们可以将 GetAsyncKeyState的结果与0x1进行运算这样1代表按键0代表没按键。
#define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) 0x1) ? 1 : 0 )
四.GameStart 在这个函数里我们主要完成这样几个功能的实现 设置控制台的信息窗口的大小窗口名 隐藏光标 打印欢迎信息 绘制地图 初始化蛇 创建食物 void GameStart(pSnake ps)
{//设置控制台的信息窗口的大小窗口名system(mode con cols100 lines30);system(title 贪吃蛇);//隐藏光标HANDLE handle GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(handle, CursorInfo);CursorInfo.bVisible false;SetConsoleCursorInfo(handle, CursorInfo);//打印欢迎信息WelcomeToGame();//绘制地图GetMap();//初始化蛇InitSnake(ps);//创建食物CreateFood(ps);
}
这里需要特殊说明一下这里我们打印蛇身的时候使用的是中文符号可以下载搜狗输入法特殊字符获得并且这些中文字符是普通字符 的二倍大。
五.GameRun 用来实现这样几个功能 打印欢迎信息PrintfHelpInfo(); 按键的实现switch语句 蛇的移动SnakeMove();sleep一下移动一下 void GameRun(pSnake ps)
{PrintfHelpInfo();do{SetPos(62,10);printf(总分%5d\n,ps-Score);SetPos(62,11);printf(食物的分值%02d\n,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_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;}}SnakeMove(ps);Sleep(ps-SleepTime);} while (ps-statusOK);//getchar();}
这里是GameRun的基本框架一些具体的函数嵌套下文会有详细源码。 六.GameEnd 这个函数主要用来进行游戏结束时的一些善后工作 打印退出游戏的信息 逐个销毁创建的贪吃蛇蛇身节点 释放食物节点指针 void GameEnd(pSnake ps)
{SetPos(15,12);switch (ps-status){case ESC:printf(主动退出游戏正常退出\n);break;case KILL_BY_WALL:printf(很遗憾撞墙了游戏结束\n);break;case KILL_BY_SELF:printf(很遗憾咬到自己了游戏结束了\n);break;}PSnakeNode cur ps-pSnake;PSnakeNode del NULL;while (cur){del cur;cur - cur-next;free(del);}free(ps-pFood);ps-pFood NULL;
} 七.贪吃蛇小项目源码
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#includesnake.hvoid test()
{//创建蛇Snake snake {0};GameStart(snake);//GameRun(snake);//GameEnd(snake);
}
int main()
{//修改适配为中文环境setlocale(LC_ALL,);test();return 0;
}Snake.h
#define _CRT_SECURE_NO_WARNINGS 1
#include locale.h
#includestdio.h
#includestdlib.h
#includewindows.h
#includestdbool.h
#define KEY_PRESS(VK) ((GetAsyncKeyState(VK) 0x1) ? 1 : 0)
#define WALL L□
#define BODY L●
#define Food L★
#define POS_X 24
#define POS_Y 5
enum GAME_STATUS
{OK 1,ESC,KILL_BY_WALL,KILL_BY_SELF
};
enum DIRECTION
{UP1,DOWN,LEFT,RIGHT
};
//蛇身节点的定义
typedef struct SnakeNode
{int x;int y;struct SnakeNode* next;
}SnakeNode, *PSnakeNode;
//贪吃蛇
typedef struct Snake
{PSnakeNode pSnake;PSnakeNode pFood;int Score;int FoodWeight;int SleepTime;enum GAME_STATUS status;enum DIRECTION dir;
}Snake,*pSnake;void GameStart(pSnake ps);
void WelcomeToGame();
void GetMap();
void InitSnake(pSnake ps);
void CreateFood(pSnake ps);
void GameRun(pSnake ps);
void PrintfHelpInfo();
void SnakeMove(pSnake ps);
int NextIsFood(pSnake ps,PSnakeNode pNext);
void EatFood(pSnake ps, PSnakeNode pNext);
void NotFood(pSnake ps, PSnakeNode pNext);
void killByWall(pSnake ps);
void KillBySelf(pSnake ps);
void GameEnd(pSnake ps);
Snake.c
#define _CRT_SECURE_NO_WARNINGS 1
#includesnake.h
void SetPos(int x,int y)
{HANDLE handle GetStdHandle(STD_OUTPUT_HANDLE);COORD pos { x,y };SetConsoleCursorPosition(handle,pos);}
void WelcomeToGame()
{SetPos(35,10);printf(欢迎来到贪吃蛇小游戏\n);SetPos(38,20);system(pause);system(cls);//功能介绍界面SetPos(15,10);printf(用↑.↓.←.→来控制蛇的移动F3是加速F4是减速\n);SetPos(15,11);printf(加速得到更高的分数\n);SetPos(38, 20);system(pause);system(cls);
}
void GetMap()
{//上SetPos(0,0);int i 0;for ( i 0;i 56; i 2){wprintf(L%lc, WALL);}//下SetPos(0,26);for (i 0; i 56; i 2){wprintf(L%lc, WALL);}//左for (i 1; i 25; i ){SetPos(0,i);wprintf(L%lc, WALL);}//右for (i 1; i 25; i){SetPos(56,i);wprintf(L%lc, 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-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-dir RIGHT;ps-FoodWeight 10;ps-pFood NULL;ps-Score 0;ps-SleepTime 200;ps-status OK;
}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-xx;pFood-yy;ps-pFood pFood;SetPos(x,y);wprintf(L%lc,Food);}void GameStart(pSnake ps)
{//设置控制台的信息窗口的大小窗口名system(mode con cols100 lines30);system(title 贪吃蛇);//隐藏光标HANDLE handle GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(handle, CursorInfo);CursorInfo.bVisible false;SetConsoleCursorInfo(handle, CursorInfo);//打印欢迎信息WelcomeToGame();//绘制地图GetMap();//初始化蛇InitSnake(ps);//创建食物CreateFood(ps);
}
void PrintfHelpInfo()
{SetPos(62,15);printf(1.不能穿墙不能咬到自己\n);SetPos(62,16);printf(用↑.↓.←.→来控制蛇的移动\n);SetPos(62,17);printf(F3是加速F4是减速\n);SetPos(62,19);printf(版权Monodye\n);}
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;}elsereturn 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 NotFood(pSnake ps, PSnakeNode pNext)
{pNext-next ps-pSnake;ps-pSnake pNext;PSnakeNode cur ps-pSnake;while (cur-next-next ){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_SELF;}
}
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 0;}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-x2;pNext-y ps-pSnake-y;break;}if (NextIsFood(ps,pNext)){EatFood(ps,pNext);}else {NotFood(ps,pNext);}killByWall(ps);KillBySelf(ps);
}
void GameRun(pSnake ps)
{PrintfHelpInfo();do{SetPos(62,10);printf(总分%5d\n,ps-Score);SetPos(62,11);printf(食物的分值%02d\n,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_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;}}SnakeMove(ps);Sleep(ps-SleepTime);} while (ps-statusOK);//getchar();}
void GameEnd(pSnake ps)
{SetPos(15,12);switch (ps-status){case ESC:printf(主动退出游戏正常退出\n);break;case KILL_BY_WALL:printf(很遗憾撞墙了游戏结束\n);break;case KILL_BY_SELF:printf(很遗憾咬到自己了游戏结束了\n);break;}PSnakeNode cur ps-pSnake;PSnakeNode del NULL;while (cur){del cur;cur - cur-next;free(del);}free(ps-pFood);ps-pFood NULL;
} 文章转载自: http://www.morning.zwxfj.cn.gov.cn.zwxfj.cn http://www.morning.fdmfn.cn.gov.cn.fdmfn.cn http://www.morning.nlywq.cn.gov.cn.nlywq.cn http://www.morning.qggcc.cn.gov.cn.qggcc.cn http://www.morning.rqgjr.cn.gov.cn.rqgjr.cn http://www.morning.bpwdc.cn.gov.cn.bpwdc.cn http://www.morning.pslzp.cn.gov.cn.pslzp.cn http://www.morning.tlpgp.cn.gov.cn.tlpgp.cn http://www.morning.vibwp.cn.gov.cn.vibwp.cn http://www.morning.kbdjn.cn.gov.cn.kbdjn.cn http://www.morning.sfdsn.cn.gov.cn.sfdsn.cn http://www.morning.ndfwh.cn.gov.cn.ndfwh.cn http://www.morning.dqwykj.com.gov.cn.dqwykj.com http://www.morning.nkrmh.cn.gov.cn.nkrmh.cn http://www.morning.qpxrr.cn.gov.cn.qpxrr.cn http://www.morning.kcwkt.cn.gov.cn.kcwkt.cn http://www.morning.rbcw.cn.gov.cn.rbcw.cn http://www.morning.prjty.cn.gov.cn.prjty.cn http://www.morning.pbmkh.cn.gov.cn.pbmkh.cn http://www.morning.tkxr.cn.gov.cn.tkxr.cn http://www.morning.wtdyq.cn.gov.cn.wtdyq.cn http://www.morning.wmsgt.cn.gov.cn.wmsgt.cn http://www.morning.ypmqy.cn.gov.cn.ypmqy.cn http://www.morning.spnky.cn.gov.cn.spnky.cn http://www.morning.dmlgq.cn.gov.cn.dmlgq.cn http://www.morning.yjtnc.cn.gov.cn.yjtnc.cn http://www.morning.fflnw.cn.gov.cn.fflnw.cn http://www.morning.bndkf.cn.gov.cn.bndkf.cn http://www.morning.tntgc.cn.gov.cn.tntgc.cn http://www.morning.bmmhs.cn.gov.cn.bmmhs.cn http://www.morning.tqklh.cn.gov.cn.tqklh.cn http://www.morning.ykwqz.cn.gov.cn.ykwqz.cn http://www.morning.fgxr.cn.gov.cn.fgxr.cn http://www.morning.nzqqd.cn.gov.cn.nzqqd.cn http://www.morning.grqlc.cn.gov.cn.grqlc.cn http://www.morning.wmmqf.cn.gov.cn.wmmqf.cn http://www.morning.mlffg.cn.gov.cn.mlffg.cn http://www.morning.gtdf.cn.gov.cn.gtdf.cn http://www.morning.mpnff.cn.gov.cn.mpnff.cn http://www.morning.lhqw.cn.gov.cn.lhqw.cn http://www.morning.mmjqk.cn.gov.cn.mmjqk.cn http://www.morning.kbyp.cn.gov.cn.kbyp.cn http://www.morning.djwpd.cn.gov.cn.djwpd.cn http://www.morning.pqqzd.cn.gov.cn.pqqzd.cn http://www.morning.ztqj.cn.gov.cn.ztqj.cn http://www.morning.prlgn.cn.gov.cn.prlgn.cn http://www.morning.dqzcf.cn.gov.cn.dqzcf.cn http://www.morning.smdnl.cn.gov.cn.smdnl.cn http://www.morning.rwfp.cn.gov.cn.rwfp.cn http://www.morning.hyhqd.cn.gov.cn.hyhqd.cn http://www.morning.lskrg.cn.gov.cn.lskrg.cn http://www.morning.qfgxk.cn.gov.cn.qfgxk.cn http://www.morning.ktmbr.cn.gov.cn.ktmbr.cn http://www.morning.rxhn.cn.gov.cn.rxhn.cn http://www.morning.jxwhr.cn.gov.cn.jxwhr.cn http://www.morning.darwallet.cn.gov.cn.darwallet.cn http://www.morning.qzpw.cn.gov.cn.qzpw.cn http://www.morning.ysqb.cn.gov.cn.ysqb.cn http://www.morning.qrqg.cn.gov.cn.qrqg.cn http://www.morning.hyyxsc.cn.gov.cn.hyyxsc.cn http://www.morning.tqfnf.cn.gov.cn.tqfnf.cn http://www.morning.qpsdq.cn.gov.cn.qpsdq.cn http://www.morning.yrjfb.cn.gov.cn.yrjfb.cn http://www.morning.lwrks.cn.gov.cn.lwrks.cn http://www.morning.qmpbs.cn.gov.cn.qmpbs.cn http://www.morning.hxsdh.cn.gov.cn.hxsdh.cn http://www.morning.gtylt.cn.gov.cn.gtylt.cn http://www.morning.hpmzs.cn.gov.cn.hpmzs.cn http://www.morning.mkyny.cn.gov.cn.mkyny.cn http://www.morning.xgkxy.cn.gov.cn.xgkxy.cn http://www.morning.mqzcn.cn.gov.cn.mqzcn.cn http://www.morning.tgtwy.cn.gov.cn.tgtwy.cn http://www.morning.xkzr.cn.gov.cn.xkzr.cn http://www.morning.bpmdq.cn.gov.cn.bpmdq.cn http://www.morning.pxwjp.cn.gov.cn.pxwjp.cn http://www.morning.whnps.cn.gov.cn.whnps.cn http://www.morning.rksnk.cn.gov.cn.rksnk.cn http://www.morning.fpjw.cn.gov.cn.fpjw.cn http://www.morning.fzqfb.cn.gov.cn.fzqfb.cn http://www.morning.ndcjq.cn.gov.cn.ndcjq.cn