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

上篇我们完成了地图的信息获取和碰撞检测,这篇我们整合到程序中。

在这之前我们改造一下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;
}
可以看到我们先初始化了地图信息,然后通过地图信息创建了一个坦克,并把坦克放到了地图中的初始化位置。


下面我们看看运行后的碰撞效果:




完整源码下载地址:

http://download.csdn.net/detail/yincheng01/6756657

原文地址:https://www.cnblogs.com/new0801/p/6177290.html