学习贪吃蛇项目总结
掌握的知识
- C语言开发
- 熟悉C语言数组
- 熟悉结构体
- 按键交互操作,鼠标交互
- 创建图形窗口
- 基本绘图
新知识输入
头文件
- 头文件<conio.h>:C语言非标准的输入输出文件,其中包含输入输出函数。
- 头文件<stdlib.h>:他是C语言标准库函数。在本项目中,我们运用了它的伪随机数生成函数。
- 头文件<graphics.h>:这个头文件,我们需要安装easyx这个软件,安装头文件。是C语言标准的图形文件库的头文件。所有的图形函数原型均在graphic.h头文件中
- **头文件<mmsystem.h>:**是音频播放的库函数注意要搭配pragma comment(lib,“winmm.lib”).重点强调一下,这是多媒体设备播放接口的两个头文件
-
这里在详细说明一下:在程序中添加背景音乐,首先要包含<mmsystem.h>这个播放音乐的头文件,然后必须搭配****#pragma comment(lib,“winmm.lib”):这条#pragma指令是一条编译器指令,是给告诉编译器你要链接的一些东西,然后通过comment指明你要链接的东西,需要导入什么库。这里即导入或者说是链接winmm.h库头文件。
#include <mmsystem.h>
pragma comment(lib,"winmm.lib")
定义蛇和食物中的新知识
- POINT类型用来表示点的坐标。
- 定义flag代表食物究竟是否被吃。
- 用到随机种子来定义食物产生的随机位置。这里需要用到srand函数,存在于stdlib.h头文件中。
初始化中涉及到的新知识
- int rand(void)函数: 表示从srand(seed)中指定的seed种子开始,返回一个[seed,RAND_MAX)间的随机整数。
- void srand(unsigned seed) :参数seed是rand()的种子,用来初始化rand()的起始值。
- 值得注意的是:rand()函数每次被调用的时候,需要执行两个操作中的一个:1)如果用户在此之前调用过srand(seed)函数,那么rand()函数自动调用srand(seed)一次来初始化它的种子区间的最小值;2)如果用户在此前没有调用过srand(seed)函数,那么rand()函数默认从srand(1)开始。值得强调!!!rand函数每次从计算机接受一个随机数种子,用这个种子来产生随机数,而如果计算机每次给的随机数种子都是一样的,那么他每次产生的随机数也是一样的,如果要让他产生真的随机数,需要rand函数与srand函数搭配使用,srand函数可以产生一个时间种子,而且时间是变化的,并不是每一次时间都相同,所以它产生的时间的种子也是变化的,这个变化的时间种子传给rand函数,自然产生不一样的随机数。通常指定当前系统流逝的时间
time_t time(0);
- 另一个需要注意的是:!!!rand()的返回值与某一个整数求模是必须的,这样才能确保随机数落在[0,某个数)的范围之内,否则rand()函数本身的返回值是很巨大的!!!例如:我们关于
time_t time(0)//time_t 定义为长整型,返回从1970年1月1日0时0分0秒到目前为止所经过的时间
- GetTickCount函数的功能:GetTcikCount返回从操作系统启动到现在所经过的毫秒数,它的返回值类型是DWORD。调用方法是srand(GetTickCount())。一般只在进行一大批随机数产生之前进行一次随机种子的初始化。
初始化按键控制函数
- _kbhit():用来检测是否有按键选择。
编程以及思考过程
定义相关结构体
定义🐍
- 🐍要有坐标,有多少节,🐍的方向,🐍的速度
- 定义🐍中,因为蛇有不同的属性,所以,我们需要去定义一个蛇类型的结构体struct类型。
- SHOWCONSOLE显示控制台。这通常是调试代码所用到的
- 涉及到point类型的数据:表示一系列点的坐标数据,在windef.h已经定义好了。
//定义蛇的结构体
#def MaxLength 500
struct snake
{
int dir;//定义方向
int speed;//定义速度
int r;//定义尺寸
POINT coor[MaxLength];
}
定义食物(有蛇必须有吃的)
我们在定义食物的过程中,必须想清楚食物随机产生,食物的尺寸,食物的颜色,食物的形状等基本要素。同时我们还要考虑食物在随机出现的位置上,是否被吃了,通过设定flag来判断食物究竟是否被吃
# include <stdlib.h>//产生随机数的种子
struct Food
{
//食物的坐标
int x;
int y;
int r;
bool flag;
DWORD color
}
定义移动的方向
我们通过枚举类型(enum)来定义一个结构体。因为我们只有有限个选择,所以通过美剧可以美剧完成
//显示定义移动的方向,四种上下左右。
enum DIR
{
UP,
DOWN,
LEFT,
RIGHT
}
定义结构体等类型的初始化
将游戏所有设置进行初始化
忘记编写的代码:
初始化幕布函数
Initgraph(640,480);//1...
//2....
初始化游戏幕布函数
//游戏初始化
void GameInit()
{
//初始化幕布
Initgraph(640,480)
//我们需要初始化背景音乐
mciSendString("open ./文件名 alias bgm",0,0,0);//alias表示将我们的文件名重命名一个简单的名字alias bgm表示将文件名重新命名为bgm
mciSendString("play bgm",0,0,0);//先打开文件,在播放文件
//初始化蛇
snake.size = 3;
snake.direction = RIGHT;
snake.speed = 10;
for(int i =0;i<snake.size-1;i++)//将蛇的节数分别定义相应的坐标
{
snake.coor[i].x = 40-10*i;
snake.coor[i].y = 10;
}
//初始化食物
food.x = rand(srand(GetTickCount()))%640;
food.y = rand(srand(GetTickCount()))%480;
food.r = rand(srand(GetTickCount()))%10+5;[5,15]
food.flage = true;
food.color= red;
}
初始化游戏的按键控制函数
//初始化键盘按键函数
void KeyControl()
{
if(_kbhit)//如果有案件选择
{
//读取这个按键的数值
switch (_getch())
{
case 72:
if(snake.direction!= DOWN)
snake.direction = UP;
break;
case 80:
if(snake.direction !=UP)
snake.direction = DOWN;
break;
case 75:
if(snake.direction != RIGHT)
snake.direction = LEFT;
break;
case 77:
fi(snake.direction != LEFT)
snake.direction =RIGHT;
break;
case ' ':
while(1)
{
if(_getch()==' ')
return;
}
break;
}
}
}
其实最后的while循环没咋看懂目前存在疑惑。
进行幕布绘制,蛇绘制,食物绘制以及最后的蛇吃食物
幕布绘制
void GramDraw
{
//防止闪屏功能
BeginBatchDraw();
//设置幕布的颜色
setbkcolor(RED);
//清除背景的默认设置
cleardevice()
//设置蛇的颜色,并绘制蛇
setfillcolor(BULE);
for(int i=0i<snake.size-1;i++)
{
soildcircle(snake.coor[i].x,snake.coor[i].y,5);
}
//如果食物没有被吃,那么我们在幕布上画食物
if(food.flage)
{
//设置食物的颜色以及位置
solidcircle(food.x,food.y,foor.r);
}
EndBatchDraw();
}
蛇移动
void snakmove()
{
for(int i=snake.size-1;i>0;i--)
{
snake.coor[i]=snake.coor[i-1];
}
switch(snake.direction)
case UP:
{
snake.coor[0].y-=snake.speed;
//穿越幕布功能
if(snake.coor[0].y-10<0)
{
snake.coor[0].y = 480;
}
}
case DOWN:
{
snake.coor[0].y+=snake.speed;
if(snake.coor[0].y-10>480)
{
snake.coor[0].y = 0;
}
}
break;
case RIGHT:
{
snake.coor[0].x+=snake.speed;
if(snake.coor[0].x-10>640)
{
snake.coor[0].x = 0;
}
break;
}
case LEFT:
{
if(snake.coor[0].x-10<0)
{
snake.coor[0].x = 640;
}
snake.coor[0].x-=snake.speed;
break;
}
}
蛇吃食物
void FoodEat()
{
if(food.flage && food.r+food.x>snake.coor[0].x && food.x-food.r<snake.coor[0].x && food.y+food.r>snake.coor[0].y && food.y-food.r<snake.coor[0].y)
{
food.flag = false;
snzke.size++;
}
if(!food.flag)
{
food.x = rand() % 640;
food.y = rand() % 480;
food.r = rand() % 10+5;
food.color = red;
food.flag = true;
}
}
main函数
int main()
{
GameInit();
while(1)
{
GrameDraw();
snakeMove();
keyControl();
EatFood();
sleep(20);
}
closegraph();
return 0 ;
}