要开发一个游戏,地图是首先应该考虑的,我这里使用的是tiled来编辑地图。tiled对于一般的游戏开发还行,相对通用,不过也没有那么强的针对性。所以在开发游戏时要对从tiled解析的内容里再在程序中进行相应的处理。
今天考虑的是图块,对于图块,如果简单地分的话可以分为两种属性:1.priority属性 2.pass_down pass_left pass_right pass_up
priprity,顾名思义,就是优先级的意思,这里可以规定为0角色不可通过 1角色可通过,并且主角覆盖改图块 2角色可通过,图块在角色之上。
对于pass_%s 则是指的是对于一些特殊图块而言。比如这种
这种图块主角是可以在上面的,只不过某些方向不可通过,这就需要在程序中特殊处理。上图,主角向右是无法通行的。
关于寻路算法,大家可以参考A*算法,然后加上这种判断即可,比如我在代码中就是每次只能移动一格。以上图为例,下一个可以通过,但是从本图块到下一图块的pass_right 为false,这就无法过去了。反之亦然。
另外一个就是遮挡问题。这个问题虽然对于游戏性没什么关系,但是却相当重要。我的思路如下:把能和角色放生碰撞的层称之为碰撞层,然后角色也要加到碰撞层中。对于priprity为0的,因为无法通过,自然不存在什么遮挡问题,这时需要考虑和其他图块的遮挡问题。如果为1的主角的要在这些图块之后渲染,对应为2 的,则相反。
实现大致如下。
这里的tmx是我自己解析的,所以我就规定,从左至右 从上至下图块的localZOrder依次增大。这样能实现图块之间的遮挡关系。然后对于priority为2的单独处理。代码大致如下。
//保存所有优先级为2的图块
vector<int> tileIds;
auto tilesets = m_pTiledMap->getTilesets();
for (auto tileset : tilesets)
{
auto& properties = tileset->getProperties();
for(auto itMap = properties.cbegin();itMap != properties.cend();itMap++)
{
auto id = itMap->first;
auto& valueMap= itMap->second;
auto it = valueMap.find("priority");
if (it != valueMap.cend() && it->second.asInt() == 2)
tileIds.push_back(id + tileset->firstGrid);
}
}
//设置优先级为2的图块localZOrder
auto& children = this->getCollisionLayer()->getChildren();
for (auto child : children)
{
//获取精灵的名字
auto name = child->getName();
if (name.empty()) continue;
int id = SDL_atoi(name.c_str());
//设置localZOrder
if (find(tileIds.begin(),tileIds.end(),id) != tileIds.end())
{
child->setLocalZOrder(child->getLocalZOrder() + GameScene::CHARACTER_LOCAL_Z_ORDER);
}
}
<tileset name="Outside_A5" tilewidth="48" tileheight="48" tilecount="128" columns="8">
<image source="Outside_A5.png" width="384" height="768"/>
<tile id="0">
<properties>
<property name="pass" type="bool" value="false"/>
</properties>
</tile>
<tile id="88">
<properties>
<property name="pass_left" type="bool" value="false"/>
<property name="pass_up" type="bool" value="false"/>
</properties>
</tile>
注意上面的m_pTiledMap->getTilesets()获取的是tmx地图所使用的全部tileset。而下面的 auto& properties = tileset->getProperties()则是获取所有属性,其返回值是std::unordered_map<int,ValueMap>。
而接下开的则是获取tileset的图块属性来找出符合的图块。上面还有就是tileset对应的属性。
这样,在每次加载一个地图时,都需要一次设置即可,其他的就不需要处理了。当然,另外一个解决办法就是再有一个装饰层,使之在碰撞层后渲染,不过这样需要细心,也挺麻烦的。这个可以参考这个http://blog.youkuaiyun.com/lufy_Legend/article/details/17748629
发一张遮挡的图片。