——个人笔记
注:没有开始界面还有一些复杂的功能,这里只介绍最核心的功能。
逻辑
首先推箱子,我们最最最核心的就是怎么去推。也就是去实现移动功能,改变地图。那么,逻辑中只要考虑人怎么移动就行了。首先,人移动最简单的就是前面是空地或者目的地那么就直接把人移动过去就行了,还有一个就是前面是墙,那么不改变。复杂的就是推箱子游戏设计,人移动前面是箱子(包括已经到达目的地的),那么我们还有判断箱子的前面(这个前面是指人要移动的方向)是否为空地或者目的地,如果是空地或者目的地,那么箱子和人同时向前移动并且做相应的改变(如果是目的地箱子推进去有变化,箱子推出目的地也有变化),如果箱子前面是墙同样不动。
懂了逻辑了,就继续往下走。我们先规定一下0 空地,1墙3D素材,2人人物立绘,3箱子,4目的地,7达到目的地为什么7是达到目的地?因为3+4=7我们地图的改变会使用到加法,这里有一个隐藏的6也是表示人,只不过这人站在目的地上面。(这里不懂继续往下看就知道了),下面一步一步完成
地图
这里我们做成通关的小demo,所以所有地图我们用一个三维数组存储,然后用一个二维数组来获取当前关卡的地图。
//全局变量
int allMap[3][10][10]=·····;//这里是所有关卡的地图,太长了,自己定义。
int nowMap[10][10];//当前关卡的地图
int level=0;//当前关卡
//获取当前关卡地图
void InitMap()
{
for(int i=0;i<10;i++)
for (int j = 0; j < 10; j++)
{
nowMap[i][j] = allMap[level][i][j];
}
}
绘图
这里就是根据地图来用easyX贴图,绘图要在每次移动之后都要调用。贴图,我们先要加载图片loadimage:
void InitImg()
{
loadimage(&img[0], "photo/0.jpg", 500, 500);
//TODO 所有加载图片都可以放在这,可以利用循环也行。
//比如:
/*for(int i=1;i<6;i++)
{
char ch[12] = {'p','h','o','t','o','/',i+'0','.','j','p','g'};
loadimage(&img[i], (LPCTSTR)ch, 50, 50);
}*/
}
那么开始贴图:
void DrawMap()
{
//清屏
cleardevice();
//开始批量绘图,不会出现那种闪烁
BeginBatchDraw();
putimage(0, 0, &img[0]);//背景图
//根据地图的数字来贴图
//0 空地,1墙,2 和6人,3箱子,4目的地,7达到目的地
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
{
switch (nowMap[i][j])
{
case 1:
putimage(j * 50, i * 50, &img[1]);
break;
case 2:
case 6:
putimage(j * 50, i * 50, &img[2]);
break;
case 3:
putimage(j * 50, i * 50, &img[3]);
break;
case 4:
putimage(j * 50, i * 50, &img[4]);
break;
case 7:
putimage(j * 50, i * 50, &img[5]);
break;
}
}
EndBatchDraw();
}
移动
上面两步已经把模型都搞好了,只差移动就能爽一把了。首先,我们要获取人物的位置。
int playerX, playerY;//这两个是全局变量
void PlayPos()
{
for(int i=0;i<10;i++)
for (int j = 0; j < 10; j++)
{
if (nowMap[i][j] == 2)
{
playerX = i;
playerY = j;
return;
}
}
}
然后我们使用_getch()来获取玩家按键,因为直接输入就能获取,需要引入头文件#include。我们这里使用加减法来实现移动,比如,人离开了那个位置就减去他自己本身的数字2,进入的那个位置就加上他本身的数字2。
下面都用向上走为例子,其他方向一样只是if的判断的位置不一样。
0 空地,1墙,2 和6人,3箱子,4目的地,7达到目的地
第一种情况(人的前面是空地和目标地):
if (nowMap[playerX - 1][playerY] == 0 || nowMap[playerX - 1][playerY] == 4)
{
nowMap[playerX - 1][playerY] += 2;//人进入
nowMap[playerX][playerY] -= 2;//人离开
playerX-=1;//人的位置发生变化
}
第二种情况(人前面是箱子):
//7也是箱子,只是到达目的地而已
else if (nowMap[playerX - 1][playerY] == 3 || nowMap[playerX - 1][playerY ] == 7)
{
//判断箱子前面是不是空地或者目的地
if (nowMap[playerX - 2][playerY] == 0 || nowMap[playerX - 2][playerY ] == 4)
{
nowMap[playerX - 2][playerY ] += 3;//箱子进入+3
nowMap[playerX - 1][playerY ] -= 1;//箱子离开,同时人进入+3-2=-1
nowMap[playerX][playerY] -= 2;//人离开-2
playerX -= 1;//人位置变化
}
}
第三种情况(前面是墙):不用处理,你知道就行!
移动的完整代码:
void Move()
{
switch (_getch())
{
case 'w':
if (nowMap[playerX - 1][playerY] == 0 || nowMap[playerX - 1][playerY] == 4)
{
nowMap[playerX - 1][playerY] += 2;
nowMap[playerX][playerY] -= 2;
playerX-=1;
}
else if (nowMap[playerX - 1][playerY] == 3 || nowMap[playerX - 1][playerY ] == 7)
{
if (nowMap[playerX - 2][playerY] == 0 || nowMap[playerX - 2][playerY ] == 4)
{
nowMap[playerX - 2][playerY ] += 3;
nowMap[playerX - 1][playerY ] -= 1;
nowMap[playerX][playerY] -= 2;
playerX -= 1;
}
}
break;
case 'a':
if (nowMap[playerX][playerY-1] == 0 || nowMap[playerX ][playerY - 1] == 4)
{
nowMap[playerX][playerY-1] += 2;
nowMap[playerX][playerY] -= 2;
playerY-=1;
}
else if (nowMap[playerX][playerY - 1] == 3|| nowMap[playerX][playerY - 1] == 7)
{
if (nowMap[playerX][playerY - 2] == 0|| nowMap[playerX][playerY - 2] == 4)
{
nowMap[playerX][playerY - 2] += 3;
nowMap[playerX][playerY - 1] -= 1;
nowMap[playerX][playerY] -= 2;
playerY -= 1;
}
}
break;
case 's':
if (nowMap[playerX +1][playerY] == 0 || nowMap[playerX +1][playerY] == 4)
{
nowMap[playerX + 1][playerY] += 2;
nowMap[playerX][playerY] -= 2;
playerX+=1;
}
else if (nowMap[playerX +1][playerY ] == 3 || nowMap[playerX + 1][playerY ] == 7)
{
if (nowMap[playerX + 2][playerY ] == 0 || nowMap[playerX + 2][playerY] == 4)
{
nowMap[playerX + 2][playerY] += 3;
nowMap[playerX + 1][playerY] -= 1;
nowMap[playerX][playerY] -= 2;
playerX += 1;
}
}
break;
case 'd':
if (nowMap[playerX ][playerY+1] == 0 || nowMap[playerX ][playerY+1] == 4)
{
nowMap[playerX][playerY+1] += 2;
nowMap[playerX][playerY] -= 2;
playerY+=1;
}
else if (nowMap[playerX][playerY + 1] == 3 || nowMap[playerX][playerY + 1] == 7)
{
if (nowMap[playerX][playerY + 2] == 0 || nowMap[playerX][playerY + 2] == 4)
{
nowMap[playerX][playerY + 2] += 3;
nowMap[playerX][playerY + 1] -= 1;
nowMap[playerX][playerY] -= 2;
playerY += 1;
}
}
break;
}
}
游戏通关
上面的只是一个关卡的进行,而且输了也不会提示。那么我们要进行游戏胜利和失败的判断。
int level=0;//全局变量,0表示游戏中,1胜利,2失败。
void IsWin()
{
int number = 0;//记录有多少个没有没到达的箱子
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
{
if (nowMap[i][j] == 3)
{
++number;
//这里只是简单的判断是否失败
//判断的逻辑是
//没有到达目的地的箱子上下有一个箱子并且左右有一个箱子
if (nowMap[i - 1][j] == 1 || nowMap[i + 1][j] == 1)
{
if (nowMap[i][j - 1] == 1 || nowMap[i][j + 1] == 1)
{
life = 2;
return;//游戏结束
}
}
}
}
if(number == 0)//没有没到达的箱子
life = 1;
}
所有功能我们都完成了,那么main函数!
main
这里有一个逻辑推箱子游戏设计,要先绘图再判断游戏是否胜利最后才是移动,因为,图先出来,然后看有没有赢,再移动。如果调换你可以看看有什么效果。
int main()
{
initgraph(500, 500 );//创建窗口
InitImg(); //加载图片
InitMap();//加载地图
PlayPos();//获取玩家位置
while (1)
{
DrawMap();//绘图
IsWin();//判断是否胜利
if (life == 1)//胜利
{
if (MessageBox(GetHWnd(), "游戏胜利", "你胜利了!", MB_YESNO) == IDYES)
{
level++;//下一关
if (level == 3)//这里看你做了几关,这个数字就是几
{
if (MessageBox(GetHWnd(), "最后一关", "是否重新开始游戏!", MB_YESNO) == IDYES)
{
level = 0;
}
else
return 0;
}
InitMap();//因为下一关,要重新加载地图
DrawMap();//地图变了要重新绘画
PlayPos();//地图变量要重新获取玩家位置
life = 0;//设置正在游戏中
}
else
return 0;
}
else if (life == 2)//失败
{
if (MessageBox(GetHWnd(), "游戏失败", "是否要重新开始", MB_YESNO) == IDYES)
{
InitMap();//重新加载本地图,因为你移动过地图,要重新获取原来的
DrawMap();//绘图
PlayPos();//获取玩家位置
life = 0;//设置游戏中
}
else return 0;
}
Move(); //移动
}
getchar();
closegraph();
return 0;
}
文章来源:https://blog.csdn.net/weixin_43701019/article/details/101178554