在上篇我们可以控制坦克在地图上任意行走了,
但是实际游戏中遇到墙就应该是无法走动的,这节课我们继续完善程序,
让他能在地图检测到墙壁,而无法通过。
1.我们新建一个TileMapInfo类,来获取地图信息。
class TileMapInfo { public: bool collisionTest(CCRect rect); static TileMapInfo* createMapInfoWithFile(const char* tmxFile); void initMapInfoWithFile(const char* tmxFile); CC_SYNTHESIZE(CCTMXTiledMap*, mTMXTileMap, TileMap); private: CCTMXLayer* mTMXLayers[2]; };
可以看到定义中有一个collisionTest碰撞检测函数,
它根据传进来的rect检测是否与地图上的砖块发生了碰撞,
既然要检测碰撞,我们就需要知道地图中砖块的类型。
2.我们还记得Tiled程序吧,他可以制作tmx格式的地图,看下他的截图
可以看到右上边有两个层,layer_0和layer_1,我们分别单独勾选两个层对比看看,注意看下面两个图的区别:
我们可以看到第二个图层里面是草地,我们知道游戏中,坦克行走到草地会被遮挡住,
这样分层两个层,我们可以在第一层和第二层之间绘制坦克达到遮挡效果。
3.我们看截图右下方,看到很多类型的图块,他们在tmx中都以gid的名字保存,
如下图我标出了前面图块的gid值。
如上图所示我们一共有 36 个图块,那么最后一个图块gid值是36。
4,那么我们先定义上面图块的7种类型
//tile类型,草地,钢铁,河流等 enum enumTileType { tileNone, tileGrass, tileSteel, tileWall, tileRiver, tileKing };
//根据地图中gid获取对应tile的类型 static enumTileType gidToTileType[] = { tileNone, tileNone, tileNone, tileGrass, tileGrass, tileSteel, tileSteel, tileNone, tileNone, tileGrass, tileGrass, tileSteel, tileSteel, tileWall, tileWall, tileRiver, tileRiver, tileKing, tileKing, tileWall, tileWall, tileRiver, tileRiver, tileKing, tileKing, tileKing, tileKing, tileNone, tileNone, tileNone, tileNone, tileKing, tileKing, tileNone, tileNone, tileNone, tileNone };
void TileMapInfo::initMapInfoWithFile(const char* tmxFile) { mTMXTileMap = CCTMXTiledMap::create(tmxFile); mTMXLayers[0] = mTMXTileMap->layerNamed("layer_0"); mTMXLayers[1] = mTMXTileMap->layerNamed("layer_1"); CCSize winSize = CCDirector::sharedDirector()->getWinSize(); CCSize mapSize = mTMXTileMap->getContentSize(); //缩放地图到合适屏幕大小 mTMXTileMap->setScale(winSize.height / mTMXTileMap->getContentSize().height); //将地图放到屏幕中间 mTMXTileMap->setPosition(ccp((winSize.width - mapSize.width * mTMXTileMap->getScale()) / 2, (winSize.height - mapSize.height * mTMXTileMap->getScale()) / 2)); }
TileMapInfo* TileMapInfo::createMapInfoWithFile(const char* tmxFile) { TileMapInfo* tileMapInfo = new TileMapInfo(); tileMapInfo->initMapInfoWithFile(tmxFile); return tileMapInfo; }
bool TileMapInfo::collisionTest(CCRect rect) { int gid = 0; CCSize mapSize = mTMXTileMap->getContentSize(); CCSize tileSize = mTMXTileMap->getTileSize(); if (rect.getMinX() < 0 || rect.getMaxX() >= mapSize.width || rect.getMinY() < 0 || rect.getMaxY() >= mapSize.height) return true; //将坦克Y坐标转换为地图上的Y坐标 float MinY = mapSize.height - rect.getMinY(); float MaxY = mapSize.height - rect.getMaxY(); //对坦克四个顶点进行碰撞检测 gid = mTMXLayers[0]->tileGIDAt(ccp((int)(rect.getMinX() / tileSize.width), (int)(MinY / tileSize.height))); if (gidToTileType[gid] != tileNone && gidToTileType[gid] != tileGrass) return true; gid = mTMXLayers[0]->tileGIDAt(ccp((int)(rect.getMinX() / tileSize.width), (int)(MaxY / tileSize.height))); if (gidToTileType[gid] != tileNone && gidToTileType[gid] != tileGrass) return true; gid = mTMXLayers[0]->tileGIDAt(ccp((int)(rect.getMaxX() / tileSize.width), (int)(MaxY / tileSize.height))); if (gidToTileType[gid] != tileNone && gidToTileType[gid] != tileGrass) return true; gid = mTMXLayers[0]->tileGIDAt(ccp((int)(rect.getMaxX() / tileSize.width), (int)(MinY / tileSize.height))); if (gidToTileType[gid] != tileNone && gidToTileType[gid] != tileGrass) return true; return false; }可以看到碰撞检测函数比较麻烦,首先判断了传进来的矩形是否在地图中,
然后依次对矩形四个顶点进行碰撞检测,如果矩形进入了除 tileNone和tileGrass之外的区域
说明无法行走了,则返回true来表示碰撞了。
其中我们用到了tileGIDAt函数,他可以从一个tmx中表示的地图坐标获取gid。如下图:
可以看到 tmx 坐标中 3,24 所在的位置是一个tileNone类型的gid。
到这里TileMapInfo类已经完成了,下篇文章对Tank类进行一些修改。