上篇我们完成了地图的信息获取和碰撞检测,这篇我们整合到程序中。
在这之前我们改造一下Tank类,使它更加模块化,共容易理解:
1.改造后的Tank类声明如下:
class Tank : public CCSprite
{
public :
Tank();
~Tank();
static Tank* createTankWithTankType(const char* tankTypeName, TileMapInfo* tileMapInfo);
void initTankWithTankType(const char* tankTypeName, TileMapInfo* tileMapInfo);
void command(enumOrder order);
TileMapInfo* mTileMapInfo;
};
static Tank* createTankWithTankType(const char* tankTypeName, TileMapInfo* tileMapInfo);
void initTankWithTankType(const char* tankTypeName, TileMapInfo* tileMapInfo);
可以看到这两个函数后面都多了TileMapInfo类的指针。
我们可以在坦克中使用这个指针来检测是否碰撞。
2.我们实现void initTankWithTankType(const char* tankTypeName, TileMapInfo* tileMapInfo);
void Tank::initTankWithTankType(const char* tankTypeName, TileMapInfo* tileMapInfo)
{
initWithSpriteFrameName(tankTypeName);
mTileMapInfo = tileMapInfo;
//将坦克放入地图层中
mTileMapInfo->getTileMap()->addChild(this);
//缩放到合适大小
CCTMXTiledMap* tmxTileMap = mTileMapInfo->getTileMap();
CCSize tileSize = tmxTileMap->getTileSize();
CCSize tankSize = getContentSize();
//比地图上砖块小一点
setScale((tileSize.height * 2-4) / (tankSize.height));
}
上面函数中,我们先把Tank类自己加入了地图层中,这样更方便我们进行一个位置计算。
然后缩放到了比地图上一整个砖块小一点的大小,这样可以正常通过砖块之间的通道。
3.简单的实现static Tank* createTankWithTankType(const char* tankTypeName, TileMapInfo* tileMapInfo);来返回一个Tank实例:
Tank* Tank::createTankWithTankType(const char* tankTypeName, TileMapInfo* tileMapInfo)
{
CCSpriteFrameCache* pCache = CCSpriteFrameCache::sharedSpriteFrameCache();
pCache->addSpriteFramesWithFile("tank.plist");
Tank* tank = new Tank();
tank->initTankWithTankType(tankTypeName, tileMapInfo);
tank->autorelease();
return tank;
}
可以看到我们添加了plist文件,然后从中加载了tankTypeName类型的Tank精灵,然后初始化,最后加入自动释放列表。
4.然后在void command(enumOrder order);函数中,我们在命令控制中加入检测碰撞的函数:
bool Tank::command(enumOrder order)
{
float stepX = 0.0f;
float stepY = 0.0f;
float fRotation = getRotation();
switch (order)
{
case cmdNothing:
break;
case cmdGoUP:
stepY = 1.0f;
fRotation = 0.0f;
break;
case cmdGoDown:
stepY = -1.0f;
fRotation = 180.0f;
break;
case cmdGoLeft:
stepX = -1.0f;
fRotation = 270.0f;
break;
case cmdGoRight:
stepX = 1.0f;
fRotation = 90.0f;
break;
case cmdFire:
//调用子弹开火
return mBullet->fire();
default:
break;
}
//根据运行方向旋转坦克
setRotation(fRotation);
//检测地图上的碰撞
CCRect rect = this->boundingBox();
if (!mTileMapInfo->collisionTest(CCRectMake(rect.getMinX() + stepX,
rect.getMinY() + stepY, rect.size.width, rect.size.height)))
{
setPositionX(getPositionX() + stepX);
setPositionY(getPositionY() + stepY);
return true;
}
return false;
}
可以看到我们跟之前的Tank类的command函数中多了碰撞检测,
先通过boundingBox获取Tank在地图中的矩形,然后传入移动后的矩形,
通过TileMapInfo类中的collisionTest碰撞函数,来检测是否碰撞,
如果碰撞则不移动,如果没有碰撞则按照stepX和stepY分量进行移动位置。
5.Tank类改造完了,最后我们需要在CityScene中初始化我们的新 TileMapInfo类和Tank类:
bool CityScene::init()
{
CCLayer::init();
//初始化地图信息
TileMapInfo* tileMapInfo = TileMapInfo::createMapInfoWithFile("Round1.tmx");
CCTMXTiledMap* tmxTileMap = tileMapInfo->getTileMap();
this->addChild(tmxTileMap);
//在已有的地图上,创建玩家坦克
mPlayerTank[0] = Tank::createTankWithTankType("player2U.png", tileMapInfo);
//放到地图中初始化位置
CCSize tileSize = tmxTileMap->getTileSize();
CCSize mapSize = tmxTileMap->getContentSize();
mPlayerTank[0]->setPosition(ccp(mapSize.width / 2 - tileSize.width * 3, tileSize.height));
//添加虚拟手柄的显示
mLayerPanel = Panel::create();
addChild(mLayerPanel, 3);
return true;
}
可以看到我们先初始化了地图信息,然后通过地图信息创建了一个坦克,并把坦克放到了地图中的初始化位置。
下面我们看看运行后的碰撞效果:
完整源码下载地址: