cocos2d-x游戏开发系列教程-坦克大战游戏之坦克和地图碰撞的检测上

来源:互联网 发布:一对一直播源码 编辑:程序博客网 时间:2024/05/11 20:59

在上篇我们可以控制坦克在地图上任意行走了,

但是实际游戏中遇到墙就应该是无法走动的,这节课我们继续完善程序,

让他能在地图检测到墙壁,而无法通过。

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 };

5.然后我们在定义一个数组,可以通过传进图块的gid值来获取图块类型,对应于上面截图中的图块:

//根据地图中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};

6.然后实现函数void initMapInfoWithFile(const char* tmxFile);,从一个tmx地图文件初始化地图信息:

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));}

7.然后实现一个静态方法,返回一个TileMapInfo的实例:

TileMapInfo* TileMapInfo::createMapInfoWithFile(const char* tmxFile){TileMapInfo* tileMapInfo = new TileMapInfo();tileMapInfo->initMapInfoWithFile(tmxFile);return tileMapInfo;}

8.最后实现碰撞检测的函数bool TileMapInfo::collisionTest(CCRect rect)

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类进行一些修改。

0 0
原创粉丝点击