贪吃蛇小游戏(C++)
首先我们需要下载EasyX(具体的方法在EasyX专栏中有提到)
easyX下载和绘制简单基本图形_小梁今天敲代码了吗的博客-CSDN博客
贪吃蛇这个游戏我们一定都玩过,玩家使用方向键操控一条“蛇”,蛇会朝着一个方向不断移动,玩家可以通过上下左右键改变其运动方向。同时屏幕上随机会出现各种“食物”,玩家要控制蛇去吃掉这些食物,每吃掉一个,蛇的身体就会增长一节。
想要实现这个游戏,我们主要得考虑蛇和食物
蛇:
蛇的移动方向如何实现
蛇的身体长度如何实现增长
食物:
食物如何随机生成
下面我将代码部分拆解做一个简单的说明,后附源码
首先是播放背景音乐:
将音乐的mp3格式与代码放在一个文件夹中,用以下函数调用:
#include<mmsystem.h>//头文件
#pragma comment(lib,"winmm.lib")//库文件//播放音乐 mci media control interface(多媒体设备接口)//Send 发送 String字符串
//音乐需要放在程序同一文件目录中
mciSendString("open 音乐.mp3",0,0,0);
mciSendString("play 音乐.mp3", 0, 0, 0);
创建“精灵类”,它是“蛇类”和“食物类”的父类
这里难理解的地方是:碰撞检测(我们如何去判定蛇能吃到食物?这里采用的方法是当蛇头的左上方x,y坐标完全与食物的左上方x,y坐标相等时,我们认为蛇吃到了食物)
这个函数用于设置当前设备填充颜色。
void setfillcolor(COLORREF color);
这个函数用于画有边框的填充矩形。
void fillrectangle(int left,int top,int right,int bottom
);
//精灵类
class Sprite
{
public:Sprite():Sprite(0,0) {};Sprite(int x, int y) :m_x(x), m_y(y),m_color(RED) {};//绘制精灵virtual void draw(){//设置填充颜色setfillcolor(m_color);//绘制矩形fillrectangle(m_x, m_y, m_x + 10, m_y + 10);}//移动void moveBy(int dx, int dy){m_x += dx;m_y += dy;}//碰撞检测bool collision(const Sprite& other){return m_x == other.m_x && m_y == other.m_y;}
protected:int m_x;int m_y;COLORREF m_color;//颜色
};
蛇类这里移动时,将上一个格子坐标赋值给下一个格子,实现移动
push_back()函数的用法
函数将一个新的元素加到vector的最后面,位置为当前最后一个元素的下一个元素
//蛇类
class Snake : public Sprite
{
public:Snake():Snake(0,0) {}Snake(int x,int y):Sprite(x,y),dir(VK_RIGHT){//初始化三节蛇nodes.push_back(Sprite(20, 0));nodes.push_back(Sprite(10, 0));nodes.push_back(Sprite(0, 0));}void draw() override{for (int i = 0; i < nodes.size(); i++){nodes[i].draw();}}//蛇的身体移动void bodyMove(){//身体跟着蛇头移动for (size_t i = nodes.size()-1; i >0; i--){nodes[i] = nodes[i - 1];}//移动蛇头switch (dir){case VK_UP:nodes[0].moveBy(0,-10);break;case VK_DOWN:nodes[0].moveBy(0,10);break;case VK_LEFT:nodes[0].moveBy(-10, 0);break;case VK_RIGHT:nodes[0].moveBy(10, 0);break;}}bool collision(const Sprite& other){return nodes[0].collision(other);}//蛇增加一节void incrment(){nodes.push_back(Sprite());}
private://蛇只有一节吗?std::vector<Sprite> nodes;//蛇的所有节点public:int dir;//蛇的方向
};
食物:
为了使程序在每次执行时都能生成一个新序列的随机值,我们通常通过为随机数生成器提供一粒新的随机种子。函数srand()可以为随机数生成器播散种子。随机生成食物时,我们需要它的坐标为10的整数倍,因为蛇的身体我们设定的占10个像素,所以只能吃到坐标为10的整数倍的食物
//食物
class Food :public Sprite
{
public:Food() :Sprite(0, 0) {changePos();}void draw()override{setfillcolor(m_color);solidellipse(m_x, m_y, m_x + 10, m_y + 10);}//改变食物的坐标void changePos(){//随机生成坐标m_x = rand() % 64 * 10;m_y = rand() % 48 * 10;}
};
游戏场景:
这里引用的函数是什么意思基本已经在代码中进行了标注
这里的switch代码是在蛇的移动过程中,让它不能掉头
switch (msg.vkcode){case VK_UP:if (snake.dir != VK_DOWN)snake.dir = msg.vkcode;break;case VK_DOWN:if (snake.dir != VK_UP)snake.dir = msg.vkcode;break;case VK_LEFT:if (snake.dir != VK_RIGHT)snake.dir = msg.vkcode;break;case VK_RIGHT:if (snake.dir != VK_LEFT)snake.dir = msg.vkcode;break;}
ExMessage这个结构体用于保存鼠标消息
WM_KEYDOWN | EX_KEY | 按键按下消息 |
BeginBatchDraw()这个函数用于开始批量绘图。执行后,任何绘图操作都将暂时不输出到绘图窗口上,直到执行 FlushBatchDraw 或 EndBatchDraw 才将之前的绘图输出。
void BeginBatchDraw();
cleardevice()这个函数使用当前背景色清空绘图设备。
void cleardevice();
/*游戏场景*/
class GameScene
{
public:GameScene() {};void run(){BeginBatchDraw();//双缓冲绘图 防止屏幕闪烁cleardevice();//清屏snake.draw();food.draw();EndBatchDraw();//移动蛇,改变蛇的坐标snake.bodyMove();snakeEatFood();//获取消息ExMessage msg = { 0 };while (peekmessage(&msg, EX_KEY)){onMsg(msg);}}//改变蛇的移动方向 获取键盘按键 _getch() //响应消息:鼠标消息 键盘消息void onMsg(const ExMessage& msg){//如果有键盘消息(有没有按键按下)if (msg.message == WM_KEYDOWN){//判断具体的是哪个按键按下 virtual key code 虚拟键码switch (msg.vkcode){case VK_UP:if (snake.dir != VK_DOWN)snake.dir = msg.vkcode;break;case VK_DOWN:if (snake.dir != VK_UP)snake.dir = msg.vkcode;break;case VK_LEFT:if (snake.dir != VK_RIGHT)snake.dir = msg.vkcode;break;case VK_RIGHT:if (snake.dir != VK_LEFT)snake.dir = msg.vkcode;break;}//std::cout << msg.vkcode << std::endl;}}//判断蛇能否吃到食物void snakeEatFood(){if (snake.collision(food))//如果蛇和食物产生了碰撞{//蛇的节数增加snake.incrment();//食物重新产生在别的地方food.changePos();}}
private:Snake snake;Food food;};
最后源码如下:
#include<iostream>//标准输入输出头文件
#include<graphics.h>
#include<mmsystem.h>
#pragma comment(lib,"winmm.lib")
#include<easyx.h>
#include<vector> //顺序表
#include<ctime>
//精灵类
class Sprite
{
public:Sprite():Sprite(0,0) {};Sprite(int x, int y) :m_x(x), m_y(y),m_color(RED) {};//绘制精灵virtual void draw(){//设置填充颜色setfillcolor(m_color);//绘制矩形fillrectangle(m_x, m_y, m_x + 10, m_y + 10);}//移动void moveBy(int dx, int dy){m_x += dx;m_y += dy;}//碰撞检测bool collision(const Sprite& other){return m_x == other.m_x && m_y == other.m_y;}
protected:int m_x;int m_y;COLORREF m_color;//颜色
};//蛇类
class Snake : public Sprite
{
public:Snake():Snake(0,0) {}Snake(int x,int y):Sprite(x,y),dir(VK_RIGHT){//初始化三节蛇nodes.push_back(Sprite(20, 0));nodes.push_back(Sprite(10, 0));nodes.push_back(Sprite(0, 0));}void draw() override{for (int i = 0; i < nodes.size(); i++){nodes[i].draw();}}//蛇的身体移动void bodyMove(){//身体跟着蛇头移动for (size_t i = nodes.size()-1; i >0; i--){nodes[i] = nodes[i - 1];}//移动蛇头switch (dir){case VK_UP:nodes[0].moveBy(0,-10);break;case VK_DOWN:nodes[0].moveBy(0,10);break;case VK_LEFT:nodes[0].moveBy(-10, 0);break;case VK_RIGHT:nodes[0].moveBy(10, 0);break;}}bool collision(const Sprite& other){return nodes[0].collision(other);}//蛇增加一节void incrment(){nodes.push_back(Sprite());}
private://蛇只有一节吗?std::vector<Sprite> nodes;//蛇的所有节点public:int dir;//蛇的方向
};
//食物
class Food :public Sprite
{
public:Food() :Sprite(0, 0) {changePos();}void draw()override{setfillcolor(m_color);solidellipse(m_x, m_y, m_x + 10, m_y + 10);}//改变食物的坐标void changePos(){//随机生成坐标m_x = rand() % 64 * 10;m_y = rand() % 48 * 10;}
};
/*游戏场景*/
class GameScene
{
public:GameScene() {};void run(){BeginBatchDraw();//双缓冲绘图 防止屏幕闪烁cleardevice();//清屏snake.draw();food.draw();EndBatchDraw();//移动蛇,改变蛇的坐标snake.bodyMove();snakeEatFood();//获取消息ExMessage msg = { 0 };while (peekmessage(&msg, EX_KEY)){onMsg(msg);}}//改变蛇的移动方向 获取键盘按键 _getch() //响应消息:鼠标消息 键盘消息void onMsg(const ExMessage& msg){//如果有键盘消息(有没有按键按下)if (msg.message == WM_KEYDOWN){//判断具体的是哪个按键按下 virtual key code 虚拟键码switch (msg.vkcode){case VK_UP:if (snake.dir != VK_DOWN)snake.dir = msg.vkcode;break;case VK_DOWN:if (snake.dir != VK_UP)snake.dir = msg.vkcode;break;case VK_LEFT:if (snake.dir != VK_RIGHT)snake.dir = msg.vkcode;break;case VK_RIGHT:if (snake.dir != VK_LEFT)snake.dir = msg.vkcode;break;}//std::cout << msg.vkcode << std::endl;}}//判断蛇能否吃到食物void snakeEatFood(){if (snake.collision(food))//如果蛇和食物产生了碰撞{//蛇的节数增加snake.incrment();//食物重新产生在别的地方food.changePos();}}
private:Snake snake;Food food;};
int main()
{//初始化窗口界面initgraph(640,480,EW_SHOWCONSOLE);GameScene scene;scene.run();//设置随机数种子srand(time(nullptr));//播放音乐 mci media control interface(多媒体设备接口)//Send 发送 String字符串mciSendString("open 音乐.mp3",0,0,0);mciSendString("play 音乐.mp3", 0, 0, 0);Snake snake;snake.draw();while (true){scene.run();Sleep(100);}getchar();//防止程序闪退return 0;
}
至此我们就实现了简单的贪吃蛇游戏,它可以上下左右移动,并在吃到食物后增长一格身体
贪吃蛇小游戏(C++)相关推荐
- 100行代码,使用 Pygame 制作一个贪吃蛇小游戏!
作者 | 周萝卜 来源 | 萝卜大杂烩 相信我们大家都玩过贪吃蛇游戏,今天我们就从头一起来写一个贪吃蛇小游戏,只需要100多行的代码就完成了. 用到的 Pygame 函数 贪吃蛇小游戏用到的函数 功能 ...
- Python实现贪吃蛇小游戏(双人模式)
这篇文章主要为大家详细介绍了Python实现双人模式的贪吃蛇小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 简单用py写了一个贪吃蛇游戏,有单人.双人模式,比较简 ...
- GUI编程---贪吃蛇小游戏开发
学习链接:狂神说Java–1小时开发贪吃蛇小游戏 ①初识理论 帧:时间片足够小=>就是动画,1秒30帧.连起来是动画,拆开就是静态的图片! 键盘监听 定时器Timer 游戏图片素材:GUI之贪吃 ...
- python 贪吃蛇小游戏代码_10分钟再用Python编写贪吃蛇小游戏
Python编写贪吃蛇 前不久我们公众号发布了一篇C++编写贪吃蛇小游戏的推文,反响空前.看来大家对这类简单易上手小游戏还是很喜爱的. 恰逢2018年IEEE Spectrum编程语言排行榜新鲜出炉, ...
- python100行代码程序-100行python代码,轻松完成贪吃蛇小游戏
大家小时候都玩过贪吃蛇吧?小编小时候可喜欢拿爸妈的手机玩了,厉害着呢!今天,小编就来用100行代码实现一个简易版的贪吃蛇.在网上,贪吃蛇教程蛮多的,但要安装蛮多库的,而且也不够清晰,今天的代码比较短, ...
- python小游戏编程实例-10分钟教你用Python写一个贪吃蛇小游戏,适合练手项目
另外要注意:光理论是不够的.这里顺便总大家一套2020最新python入门到高级项目实战视频教程,可以去小编的Python交流.裙 :七衣衣九七七巴而五(数字的谐音)转换下可以找到了,还可以跟老司机交 ...
- python100行代码-怎样写贪吃蛇小游戏?用100行python代码轻松解决!
大家小时候都玩过贪吃蛇吧?小编小时候可喜欢拿爸妈的手机玩了,厉害着呢!今天,小编就来用100行代码实现一个简易版的贪吃蛇.在网上,贪吃蛇教程蛮多的,但要安装蛮多库的,而且也不够清晰,今天的代码比较短, ...
- python编程小游戏-10分钟用Python编写一个贪吃蛇小游戏,简单
贪吃蛇,大家应该都玩过.小编当初第一次接触贪吃蛇的时候 ,还是能砸核桃的诺基亚上,当时玩的不亦乐乎.今天,我们用Python编程一个贪吃蛇游戏,下面我们先看看效果: 好了,先介绍一个思路 所有的游戏最 ...
- 再来一次的C语言贪吃蛇小游戏(三)
8.游戏的不同界面 为了便于实现主要功能,之前我们所有的状态控制都是放在游戏中,但实际上我们应该把这些状态控制抽离出来,通过菜单来控制,以便在不同游戏界面间切换. 菜单界面 游戏界面 排行榜 游戏结束 ...
- 基于stm32、0.96寸OLED实现的贪吃蛇小游戏(详细源码注释)
简介:本实验基于stm32最小系统.0.96寸OLED(68*128)和摇杆实现一个经典的贪吃蛇小游戏.项目源码地址:点击下载. 硬件设计: 普通摇杆,0.96寸OLED 单色屏幕(SPI协议通讯), ...
最新文章
- React JSX 实例图解
- java.lang.NoClassDefFoundError: org/springframework/boot/context/embedded/FilterRegistrationBean
- python 图片地址_python解码data:image开头的图片地址
- aix磁盘挂载到linux,AIX下文件系统挂载点相互调换方案
- VS2013在Release情况下使用vector有时候会崩溃的一个可能原因
- 开源管理项目管理_避免开源项目管理中的不良做法
- 获取指定路径下所有PDF文件的总页数
- 微信模板消息发送帮助类
- 4、Android下实现Google街景
- 推荐几部好看的漫画,漫迷们不容错过的动漫新番哦
- 一个屌丝程序猿的人生(五十七)
- C语言简单程序——解二元一次方程
- 汉诺塔问题解法心路历程及C语言学习请教
- python股票网格交易_不知道哪位交易员可以解释下网格交易法?
- 初学实体框架EF(Entity Framework)
- 互联网快讯:华为正式开启二手机业务;法院审理认定阿卡索赔猿辅导20万;极米高性能投影产品获用户青睐;谷歌Pixel 6 Pro首次放弃使用高通基带
- Hydra教程——非常详细
- 高校版MATLAB license checkout failed问题及解决
- php解析json转数组,php json转数组出错
- Nav2极简笔记01-安装与试用
热门文章
- linux fvwm作用_使用FVWM自定义Linux桌面
- iOS版本的APP已上线,但是AppStore里面按钮显示的是打开
- 计算机术语表-主板术语
- IT民工系列——c#操控海康威视视屏监控卡(海康威视 4路视频捕捉卡 DS-4004HC)...
- 如何进行链路捆绑(详细实验流程)
- 真正牛逼的员工,是让领导又爱又怕
- Unity-场景-Terrain
- 定出公式对应的c语言表达式,代数式到c语言表达式和常用的c语言数学库函数_pow_sqrt_exp_fabs_abs...
- 通过ArcGIS对GlobeLand30影像镶嵌拼接并去除黑边
- 家具防霉方案(适用于家具厂)