一、预备知识
1.使用EasyX必须要知道的一些基础函数
2.选择结构 if , switch
3.循环结构 for, while
4.多维数组 arr1[N], arr2[N][N] , arr3[N][N][N]
5.函数封装
二、游戏逻辑
想要写出推箱子,首先要知道推箱子游戏都有哪些元素和规则
1.贪吃蛇元素
1.蛇身 2.蛇头 3.墙壁 4.食物
有了素材,首先拿数字对应起来,再来一个加载资源函数Loadimg()
#define SIZE 25
IMAGE img[8];//存放图片变量
enum element
{
space=0,//空地
food=-4,//食物
wall=-1,//墙壁
head=1, //蛇头
move_rt=1,//向右
move_dw=2,//向下
move_lt=3,//向左
move_up=4,//向上
};
void Loadimg()
{
loadimage(&img[0],L"./images/0.jpg",SIZE,SIZE);
loadimage(&img[1],L"./images/1.jpg",SIZE,SIZE);
loadimage(&img[2],L"./images/2.jpg",SIZE,SIZE);
loadimage(&img[3],L"./images/3.jpg",SIZE,SIZE);
loadimage(&img[4],L"./images/4.jpg",SIZE,SIZE);
loadimage(&img[5],L"./images/5.jpg",SIZE,SIZE);
loadimage(&img[6],L"./images/6.jpg",SIZE,SIZE);
loadimage(&img[7],L"./images/7.jpg",SIZE,SIZE);
}
2.贪吃蛇规则
1.按键可以改变蛇上、下、左、右移动
2.蛇默认沿当前方向移动
3.蛇吃到食物身体边长
4.蛇撞到墙或者自己的身体游戏结束
三、游戏设计
知道游戏元素和规则就可以开始设计游戏了
1.地图设计
地图是一个二维数组,蛇的身体一次用1,2,3,4表示,-1表示墙壁,0表示空地
#define NUM 21
int map[NUM][NUM]=
{
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
-1, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
};
地图初始化好了,开始贴图,根据移动方向的不同,贴不同的蛇头,写个Drawmap()函数
int move=1;//默认向右移动,1向右移动,2向下,3向左,4向右
void Drawmap()
{
for(int i=0;i<NUM;i++)
{
for(int j=0;j<NUM;j++)
{
if(map[i][j]==wall)//贴墙
putimage(j*SIZE,i*SIZE,&img[6]);
else if(map[i][j]>1)//贴身
putimage(j*SIZE,i*SIZE,&img[0]);
else if(map[i][j]==food)//贴食物
putimage(j*SIZE,i*SIZE,&img[7]);
else if(map[i][j]==head)//贴头
if(move==move_rt)//向右移动
putimage(j*SIZE,i*SIZE,&img[move_rt]);
else if(move==move_dw)//向下移动
putimage(j*SIZE,i*SIZE,&img[move_dw]);
else if(move==move_lt)//向左移动
putimage(j*SIZE,i*SIZE,&img[move_lt]);
else if(move==move_up)//向上移动
putimage(j*SIZE,i*SIZE,&img[move_up]);
}
}
}
地图上还需要有蛇吃的食物,用随机函数产生食物,需要包含<time.h>,写个产生食物函数Producefood()
void Producefood()//产生食物
{
srand((unsigned)time(NULL));//根据时间设置随机数种子
for(int k=0;k<1; )
{
int x=rand()%(NUM-4) +2;//生成2 ~ 18的随机数
int y=rand()%(NUM-4) +2;//为避免产生相同的坐标,采用下面的方式
if(map[x][y]==0)
{//如果是空地
map[x][y]=food;
k++;//食物设置成功才加加
}
}
}
2.移动设计
上文提到
1.按键可以改变蛇上、下、左、右移动
2.蛇默认沿当前方向移动
但是我们知道,蛇向某个方向移动的时候,不能往该方向的相反方向移动,写一个函数Controlsnake()用键盘控制蛇移动
void Controlsnake()
{
char ch =_getch();
if( (ch=='w' || ch=='W' || ch==72) && move!=move_dw)
//如果想往上移动且现在不在向下移动
move=move_up;//向上移动
else if( (ch=='s' || ch=='S' || ch==80) && move!=move_up)
//如果想往下移动且现在不在向上移动
move=move_dw;//向下移动
else if( (ch=='a' || ch=='A' || ch==75) && move!=move_rt)
//如果想往左移动且现在不在向右移动
move=move_lt;//向左移动
else if( (ch=='d' || ch=='D' || ch==77) && move!=move_lt)
//如果想往右移动且现在不在向左移动
move=move_rt;//向右移动
}
上文提到
3.蛇吃到食物身体边长
4.蛇撞到墙或者自己的身体游戏结束
下面就要划重点了,我们如何让蛇在二维数组上移动呢?
此并非我自己想出来的,来源mooc,详情见下方链接
基于以上的描述,我们就可以写出蛇的移动函数Snakemove()
int oldheadx,oldheady,newheadx,newheady,tailx,taily;
int score=0,speed=150;//当前得分,和蛇的移动速度,越小速度越快
TCHAR s[100];//存放消息提示语句
void Snakemove()
{
//遍历地图把地图上正数全+1
for(int i=0;i<NUM;i++)
{
for(int j=0;j<NUM;j++)
{
if(map[i][j]>0)
map[i][j]++;
}
}
//最大数是尾巴,找到最大数坐标,移动后变成0
int max=0;
for(int a=0;a<NUM;a++)
{
for(int b=0;b<NUM;b++)
{
if(map[a][b]==2)
{
oldheadx=a;
oldheady=b;//旧蛇头坐标
}
if(map[a][b]>max)
{
max=map[a][b];
tailx=a;
taily=b;//蛇尾坐标
}
}
}
//根据移动方向计算新蛇头坐标的位置
if(move==move_rt)//如果向右移动
{
newheadx=oldheadx;
newheady=oldheady+1;
}
else if(move==move_dw)//如果向下移动
{
newheadx=oldheadx+1;
newheady=oldheady;
}
else if(move==move_lt)//如果向左移动
{
newheadx=oldheadx;
newheady=oldheady-1;
}
else if(move==move_up)//如果向上移动
{
newheadx=oldheadx-1;
newheady=oldheady;
}
if(map[newheadx][newheady]==food)
{//如果吃到食物
PlaySound(L"./images/eat.wav", nullptr, SND_FILENAME | SND_ASYNC);//播放吃到食物音效
score++;//得分增加
Producefood();//产生新的食物
//尾部不变
}
else if(map[newheadx][newheady]==wall || map[newheadx][newheady]>0 )
{//如果撞墙或撞自己
mciSendString(_T("close ./images/bg.mp3"), 0, 0, 0);//关闭背景音乐
PlaySound(L"./images/over.wav", nullptr, SND_FILENAME | SND_ASYNC);//播放结束音效
_stprintf_s(s, _T("游戏结束,你的得分:%d分"), score);
MessageBox(NULL,s,_T("游戏提示"),MB_OK | MB_SYSTEMMODAL) ;//显示得分
system("pause");
}
else
{//没吃到食物 游戏没结束
map[tailx][taily]=0;//尾巴变成0
}
map[newheadx][newheady]=1;//新的蛇头是1
oldheadx=newheadx;
oldheady=newheady;//新头坐标变为旧坐标
}
3.速度设计
我们用Sleep()函数来控制蛇移动的速度,写一个根据得分改变速度函数Changespeed()
void Changespeed()
{
if(score>=5 && score<10)
speed=130;
else if(score>=10 && score<15)
speed=110;
else if(score>=15 && score<20)
speed=90;
else if(score>=20 && score<25)
speed=70;
else if(score>=25 && score<30)
speed=50;
else if(score>=30)
speed=30;
Sleep(speed);
}
4.整体设计
下面把上面的函数组合起来就是贪吃蛇游戏,再来点音乐
#include<time.h>
#include<easyx.h>//图形库
#include<conio.h>//按键
#include<mmsystem.h>//音乐
#pragma comment(lib,"winmm.lib")//库文件
int main()
{
initgraph(NUM*SIZE,NUM*SIZE);//创建地图大小的窗口
Loadimg();//加载资源
setbkcolor(WHITE);//设置背景白色
Producefood();//产生食物
//循环播放背景音乐
mciSendString(L"open ./images/bg.mp3 ", 0, 0, 0);
mciSendString(_T("play ./images/bg.mp3 repeat"), 0, 0, 0);
while(true){
//绘制界面
BeginBatchDraw();//批量绘图开始
cleardevice();//清理屏幕
Drawmap();//绘制地图
EndBatchDraw();//批量绘图结束
if (_kbhit())//获取按键消息
{
Controlsnake();//改变蛇的移动
}
Snakemove();//蛇默认移动
Changespeed();//根据得分改变速度
}
return 0;
}
把上面所有代码复制到一个cpp文件里,再把素材改好命名放到images文件夹里,images文件夹在cpp文件旁边,就可以编译运行了!