当前位置:网站首页>C实现贪吃蛇小游戏
C实现贪吃蛇小游戏
2022-07-04 06:02:00 【浪雨123】
贪吃蛇小游戏可以说是很多小伙伴的游戏启蒙之物,今天我们一起来用C语言复刻童年经典游戏贪吃蛇,在编写这个游戏之前,需要了解一些easyx图形库的知识,因为游戏的窗口就是靠此来提供。
这篇文章主要介绍编写这个游戏要实现的功能,另外我会再写一篇关于这个游戏常见的一些BUG及其解决办法,如果已经能完成部分的编写,而困于某些BUG的伙伴可以移步另一篇文章,可能会有你遇到的一些BUG。
实现贪吃蛇游戏,首先我们需要设置一个游戏窗口,利用easyx图形库,设置一个经典的640*480大小的窗口。窗口设定好了,接下来就可以定义蛇了,我们用结构体来定义蛇的类型,分析一下蛇需要用到那些数据,我们首先需要知道这个蛇有多长,便于游戏开始时蛇的长度设定,及游戏结束后蛇长的统计,那我们就用 int n 来表示蛇的长度。蛇在移动过程中是要有一个移动方向的,因此我们也需要设置一个int direction 来表示蛇移动的方向,因为方向就四个,我们干脆就把四个方向枚举出来,然后蛇的移动方向就用枚举变量来表示
//枚举方向
enum direction
{
up = 72,
down = 80,
left = 75,
right = 77
};
其次我们需要知道蛇的每一节身体的坐标,这样我们通过坐标来让蛇移动,以及把蛇绘制到窗口上,因为蛇的身体有很多节,坐标又有x , y两个值。我们就把坐标单独定义为结构体,然后身体的每一节都对应着一个坐标,我们用数组来表示身体
//定义蛇的坐标
struct coor
{
int x;
int y;
}coor;
最终蛇的定义如下
//定义蛇的数据类型
struct snake
{
int n = 3;
direction site;
coor szb[NUM];
}snake;
//其中NUM是该数组的最大值即蛇的身体最长长度,自行定义
定义完蛇的类型,接下来我们就把蛇初始化以下,写一个初始化函数, initsnake() 假设蛇刚开始长度为3, 方向向左, 坐标依次为
snake.n = 3;
snake.site = left;
snake.szb[0].x = 320;
snake.szb[0].y = 240;
snake.szb[1].x = 310;
snake.szb[1].y = 240;
snake.szb[2].x = 300;
snake.szb[2].y = 240;
初始化完成后,我们就把蛇绘制到窗口上,写一个 Drawsnake() 函数,其实就是一个循环,以蛇的长度为判定条件,从蛇头的坐标开始依次绘制,画矩形或者圆都可,这里我用的是矩形
void Drawsnake()
{
for (int i = 0; i < snake.n; i++)
{
rectangle(snake.szb[i].x, snake.szb[i].y, snake.szb[i].x+10, snake.szb[i].y+10);
}
}
绘制完成之后,接下来就要让蛇动起来了,这点很关键,如何实现让蛇动起来,分析可知,蛇移动的原理是让蛇头的坐标朝向某个方向不断的改变,身体再跟着蛇头一起改变,坐标每变换一次就重新绘制蛇的身体,因为这个过程足够快,我们将其处理的速度用Sleep()再延缓一点,就能形成我们眼睛所能识别的帧率,从而看着蛇是连续移动的。既然要不断的变换蛇头的坐标,并且重新绘制蛇的身体,那就要将这两个函数放到循环里面,蛇的移动我们编写一个Movesnake()。
int main()
{
initgraph(640, 480);
initgame();
while (ture)
{
cleardevice();
Movesnake();
Drawsnake();
Sleep(100);
}
}
那么如何让蛇的坐标不断朝着某个方向改变呢?接下来我们就仔细解决Movesnake(),首先我们要判断具体往哪个方向移动,还记得在定义蛇的时候,设置了一个方向变量site嘛,现在它派上用场了。我们在初始化的时候,将这个变量初始化向左移动,然后程序将蛇头坐标的x减少10,即向左改变了10个像素点,因为在循环里,只要site的值不变,蛇头就一直向左移动,第二节身体的坐标移动到原先蛇头的位置,其他节身体的坐标依次移动到它上一节身体的坐标处,这样就实现了蛇的移动,别忘了加上一个cleardevice()函数,清除上一次绘制的图形。
switch (snake.site)
{
case up:
snake.szb[0].y-=10;
break;
case down:
snake.szb[0].y+=10;
break;
case left:
snake.szb[0].x-=10;
break;
case right:
snake.szb[0].x+=10;
break;
}
for (int i = snake.n - 1; i > 0; i--) //将蛇的每一节身体的坐标替换成上一节身体的坐标
{
snake.szb[i].x = snake.szb[i - 1].x;
snake.szb[i].y = snake.szb[i - 1].y;
}
蛇的移动完成之后,接下来就是蛇在移动的时候,方向的改变,如果不让蛇的方向改变,那也没法玩呢,首先我们只有在按下方向键的时候蛇头的方向才会改变,那就先设置一个变量用来接收我们按下的方向键,然后再把这个方向键赋值给蛇头的方向变量,我们就编写一个Chdirection()函数来实现
void Chdirection()
{
char key;
key = _getch();
switch(key)
{
case up:
if (snake.site != down)
{
snake.site = up;
}
break;
case down:
if (snake.site != up)
{
snake.site = down;
}
break;
case left:
if (snake.site != right)
{
snake.site = left;
}
break;
case right:
if (snake.site != left)
{
snake.site = right;
}
break;
}
}
这里为什么要在每一个分支后面加上 if 判断语句呢,其实就是为了防止蛇直接就调头了,这和现实是不符的,显示中的掉头要绕圈子的。
其实,直接掉头也是可以的,还蛮有意思的,像火车一样两头开,哈哈,感兴趣可以试试。
转向的问题搞定了,但是程序怎么知道什么时候转向呢?因为这个程序是放在循环里的,我们不妨加一个判断语句,用kbhit()函数来检测玩家是否按下了按键,如果按下了就返回真值,进入转向函数,并在其内部判断该转向哪里,没有按下就为假,不进入转向函数。
int main()
{
initgraph(640, 480);
initgame();
while (ture)
{
cleardevice();
Movesnake();
Drawsnake();
Sleep(100);
if ( kbhit() )
{
Chdirection();
}
}
}
小蛇能跑起来了,接下就是吃食物了,那吃食物的效果又该如何实现呢?同样,我们要给食物定义一个数据类型,首先就是食物的坐标,其次是食物此刻的状态,是被吃了还是没被吃,状态我们就用bool变量
//定义食物的数据类型
struct food
{
int x;
int y;
bool state;
}food;
接着我们回到初始化函数处,给第一个食物的状态设定一下,定义为true,表示被吃了,为何设定为被吃了,等会解释,我们接着编写Createfood(),用来创造食物,就是给食物的坐标附上随机值,随机值就用随机值生成种子,一旦我们创建一个食物,那创建的瞬间,需要将食物的状态改成false,表示未被吃。
void Creatfood()
{
while (1)
{
food.x = rand() % 62 * 10;
food.y = rand() % 46 * 10;
if (food.x >= 20 && food.y >= 20)
{
food.state = false;
break;
}
}
}
//这里我加循环是不想让食物生成到边界点
那么什么时候生成食物呢,那当然是食物的状态为true表示被吃了的时候,这也是为什么我们要在开头处将食物的状态设置为true,就是为了开局就生成一个食物。同样要用到一个判断语句
int main()
{
initgraph(LENGTH, WIDTH);
initgame();
while (1)
{
if (food.state)
{
Creatfood();
}
cleardevice();
Movesnake();
Drawsnake();
Drawfood();
Sleep(100);
EndBatchDraw();
if (_kbhit())
{
Chdirection();
}
}
食物创建好了,现在就剩下最后一步了,那就是实现吃的过程,就编写个Eatfood(),当蛇头的坐标与食物的坐标重合时就可以吃了,然后食物的状态改为true,蛇的身长加1.
void Eatfood()
{
if (snake.szb[0].x == food.x && snake.szb[0].y == food.y)
{
snake.n++;
food.state = true;
}
}
就这样,简易的贪吃蛇就完成了,还有一个绘制食物,这个蛮简单的,各位伙伴自己实现吧。
int main()
{
initgraph(LENGTH, WIDTH);
initgame();
while (1)
{
if (food.state)
{
Creatfood();
}
cleardevice();
Movesnake();
Drawsnake();
Drawfood();
Eatfood();
Sleep(100);
if (_kbhit())
{
Chdirection();
}
}
getchar();
}
边栏推荐
- 746. Climb stairs with minimum cost
- 如何实现视频平台会员多账号登录
- JSON Web Token----JWT和传统session登录认证对比
- 如何判断数组中是否含有某个元素
- Detectron:训练自己的数据集——将自己的数据格式转换成COCO格式
- Qt发布多语言国际化翻译
- Steady! Huawei micro certification Huawei cloud computing service practice is stable!
- 1.1 history of Statistics
- My NVIDIA developer journey - optimizing graphics card performance
- lightroom 导入图片灰色/黑色矩形 多显示器
猜你喜欢
冲击继电器JC-7/11/DC110V
[microservice] Nacos cluster building and loading file configuration
Actual cases and optimization solutions of cloud native architecture
Halcon image calibration enables subsequent image processing to become the same as the template image
Impact relay jc-7/11/dc110v
buuctf-pwn write-ups (8)
HMS v1.0 appointment. PHP editid parameter SQL injection vulnerability (cve-2022-25491)
Take you to quickly learn how to use qsort and simulate qsort
One click filtering to select Baidu online disk files
每周小结(*63):关于正能量
随机推荐
JSON web token -- comparison between JWT and traditional session login authentication
Canoe panel learning video
How to determine whether an array contains an element
Halcon image calibration enables subsequent image processing to become the same as the template image
How to get the parent node of all nodes in El tree
How to configure static IP for Kali virtual machine
Design and implementation of redis 7.0 multi part AOF
MySQL的information_schema数据库
JS execution mechanism
Luogu deep foundation part 1 Introduction to language Chapter 5 array and data batch storage
px em rem的区别
js获取对象中嵌套的属性值
C语言练习题(递归)
Review | categories and mechanisms of action of covid-19 neutralizing antibodies and small molecule drugs
19. Framebuffer application programming
fastjson
Invalid revision: 3.18.1-g262b901-dirty
JS flattened array of number shape structure
Practical gadget instructions
Overview of relevant subclasses of beanfactorypostprocessor and beanpostprocessor