自从游戏机发明以来,地图是什么样的呢?打蜜蜂,吃豆,地图是一个矩形,玩家在这个矩形框内活动。后来,地图得到扩展,可以纵向移动,比如打飞机;可以横向移动,比如超级玛丽、魂斗罗等等横板过关游戏。再后来,横向纵向都可以移动,后来又有45度地图,3D技术后终于实现了高度拟真的虚拟世界。
超级玛丽的地图可以看成是一个二维的格子。每个格子的大小是32x32像素。
游戏窗口大小为12个格子高,16个格子宽。
游戏地图宽度是游戏窗口的5倍,即12个格子高,5x16个格子宽。
地图物品有哪些呢?地面,砖块,水管。
存储问题:
先看一下存储结构:
struct MapObject
{
int x;
int y;
int w;
int h;
int id;
int iframe;
int iframemax;//最大帧数
int show; //是否显示
};
各个成员含义是横坐标,纵坐标,宽,高,id,当前帧,最大帧,是否可见。用第一关地图文件的地图物品举例:(只包含5个参数)
0 9 10 3 0
这个物品是什么呢?横向第0个格子,纵向第9个格子,宽度10个格子,高度3个格子,id为0,表示地面。
在显示的时候,只要把坐标、宽高乘以32,即可正确显示。
地图所有物品仍然用数组+游标的方法存储,如下:
struct MapObject MapArray[MAX_MAP_OBJECT];
int iMapObjNum;
地图生成:从地图文件中加载。
加载函数:int GAMEMAP::LoadMap()
代码:
while(temp[0]!='#' && !feof(fp))
{
//读取一个物品
sscanf(temp,"%d %d %d %d %d",
&MapArray[i].x,
&MapArray[i].y,
&MapArray[i].w,
&MapArray[i].h,
&MapArray[i].id);
MapArray[i].show=0;
iMapObjNum++;
i++;
//读取下一个物品
FGetLineJumpCom(temp,fp);
}
地图显示:和物品显示一样,只是地面和砖块需要双重循环。
函数:void GAMEMAP::Show(MYANIOBJ & bmobj)
代码:对于每个宽w格,高h格的地面、砖块,需要把单个地面砖块平铺w*h次,所以用双重循环。
for(i=0;i<iMapObjNum;i++)
{
ystart=MapArray[i].y*32;
switch(MapArray[i].id)
{
//进出水管
case ID_MAP_PUMP_IN:
case ID_MAP_PUMP_OUT:
xstart=MapArray[i].x*32;
bmobj.DrawItemNoMask(xstart, ystart, MapArray[i].id, 0);
break;
default:
for(j=0;j<MapArray[i].h;j++)
{
xstart=MapArray[i].x*32;
for(k=0;k<MapArray[i].w;k++)
{
bmobj.DrawItemNoMask(xstart, ystart, MapArray[i].id, 0);
xstart+=32;
}
ystart+=32;
} // end of for
break;
说明:水管是一个单独完整的图片,直接显示,不需要循环。
帧刷新:地面、砖块、水管都是静态图片,不涉及。
碰撞检测:保证玩家顺利地行走。如果玩家不踩在物品上,则不停地下落。
函数:int GAMEMAP::CheckRole()
代码:
//检测角色是否站在某个物体上
for(i=0;i<iMapObjNum;i++)
{
//玩家的下边线,是否和物品的上边线重叠
if( LINE_ON_LINE(rmain.xpos,
rmain.ypos+32,
32,
MapArray[i].x*32,
MapArray[i].y*32,
MapArray[i].w*32)
)
{
//返回1,表示玩家踩在这个物品上
return 1;
}
}
//角色开始下落
rmain.movey=1;
rmain.jumpx=0;//此时要清除跳跃速度,否则将变成跳跃,而不是落体
return 0;
}
至此,地图物品的功能完成,且听下回分解。
附:
超级玛丽第一版源码链接:http://download.csdn.net/source/497676
超级玛丽增强版源码链接:http://download.csdn.net/source/584350