cocos2dx 植物大战僵尸 18 土豆雷

土豆雷是我打植物大战僵尸时喜欢使用的植物,它能保证在开局时能快速地种植植物。今天就实现土豆雷。
土豆雷有一个准备时间,在准备时间完成前不具有任何攻击力。以后破土,能够炸死小范围的僵尸,之后土豆雷死亡。 土豆雷在破土后,每一帧检查是否有僵尸和它发生碰撞,如果有,就炸死小范围的僵尸,然后有一个土豆雷炸过后的特效,以及僵尸有一个变成灰的特效。我的思路是使用一个特殊的子弹Boom,这个子弹并没有贴图,只是负责在一帧之内炸死所有和它发生碰撞的所在行的僵尸,这样一来土豆雷就负责调用API,主要的逻辑就给了Boom和检测是否碰撞的方法。
class PotatoMine : public Plant
{
	SDL_SYNTHESIZE(float,m_fReadyTime,ReadyTime);//破土时间
	SDL_SYNTHESIZE(int,m_nDamage,Damage);//伤害值
private:
	bool m_bReady;//是否已经准备完成
	float m_elapsed;
public:
	PotatoMine();
	~PotatoMine();
	static PotatoMine*create(const string&plantName);
	bool init(const string&plantName);

	virtual void updateHook(float dt);
private:
	void readySuccess();
	void checkCollision();
};
看看updateHook()
void PotatoMine::updateHook(float dt)
{
	//当前还没破土
	if (!m_bReady)
	{
		m_elapsed += dt;
		//到达破土时间,破土
		if (m_elapsed >= m_fReadyTime)
		{
			this->readySuccess();
			m_elapsed -= m_fReadyTime;
		}
	}
	else
	{
		//进行僵尸的检测
		this->checkCollision();
	}
}
updateHook()负责逻辑上的更新,并且会在准备完成后判断是否和僵尸碰撞回调函数。
void PotatoMine::checkCollision()
{
	auto row = m_pCarrier->getRow();
	auto rect = this->getBoundingBox();
	auto pos = this->getPosition();

	auto zombie = m_pDelegate->findCollidedZombie(row,rect);
	//发生碰撞,炸死僵尸
	if (zombie != nullptr && zombie->getHitPoint() > 0)
	{
		//展示特效
		m_pDelegate->showExplosionSpudow(pos);
		//直接死亡
		this->setDead(true);
		//爆炸
		m_pDelegate->addBoom(this->getDamage(),row,rect);
	}
}
获取当前行的僵尸并判断是否和僵尸发生碰撞,主要就是findCollidedZombie()函数。
void PotatoMine::readySuccess()
{
	m_bReady = true;
	//获取破土后的动画
	auto animationName = AnimationCache::getInstance()->getAnimation(this->getPlantName());
	auto animate = Animate::create(animationName);

	this->getSprite()->runAction(animate);
	//显示破土特效
	auto pos = this->getPosition();
	Size size = this->getContentSize();

	m_pDelegate->showRisingDirt(pos + Point(0,size.height/3));
}
这个是在破土之后的动画以及破土后的动画
ZombieBase*GameScene::findCollidedZombie(int row,const Rect&rect)
{
	auto zombies = this->getZombiesOfRow(row);
	ZombieBase *zombie = nullptr;

	auto it = find_if(zombies.begin(),zombies.end(),[rect](ZombieBase*zombie)
	{
		return zombie->getCollisionBoundingBox().intersectsRect(rect);
	});
	if (it != zombies.end())
	{
		zombie = *it;
	}
	return zombie;
}
这里是获取一行的僵尸,然后判断是否和所给的矩形发生碰撞,并返回发生碰撞的第一个僵尸。另外就是 并且更新了getZombiesOfRow()函数。
vector<ZombieBase*> GameScene::getZombiesOfRow(int row)
{
	const auto&allZombies = m_pZombieLayer->getZombies();
	vector<ZombieBase*> zombies;

	for (auto mapIter = allZombies.begin();mapIter != allZombies.end();mapIter++)
	{
		auto curRow = mapIter->first;
		auto &lineZombies = mapIter->second;

		if (row == curRow)
		{
			return lineZombies;
		}
		else if (row == -1)
		{
			copy(lineZombies.begin(),lineZombies.end(),back_inserter(zombies));
		}
	}
	return zombies;
}
这里做了一个小小的更新,如果row为-1时则返回所有的僵尸。 另外为Bullet添加一个虚函数,负责获取当前的碰撞范围。
	//碰撞结束后调用
	virtual void contactEnd();
	virtual Rect getCollisionBoundingBox()const;
实现Boom。另外需要注意,如果跨行直接设置row为-1即可。这样就能很简单地实现樱桃炸弹,窝瓜等植物。
class Boom : public Bullet
{
	SDL_SYNTHESIZE(Rect,m_collisionRect,CollisionRect);
public:
	Boom();
	~Boom();
	CREATE_FUNC(Boom);
	bool init();

	virtual void hurt();
	virtual void contactEnd();
	virtual Rect getCollisionBoundingBox()const;
};
Boom类似一般的子弹,接下来看看实现
void Boom::hurt()
{
}

void Boom::contactEnd()
{
	//在一帧后死亡
	this->setHitPoint(0);
	this->setDead(true);
}

Rect Boom::getCollisionBoundingBox()const
{
	return m_collisionRect;
}
contactEnd函数是在BulletLayer中调用的。
void BulletLayer::checkCollisionBetweenZombieAndBullet(Bullet*bullet)
{
	auto row = bullet->getRow();

	auto zombies = m_pDelegate->getZombiesOfRow(row);
	auto r = bullet->getCollisionBoundingBox();

	for (auto it = zombies.begin();it != zombies.end();it++)
	{
		auto zombie = *it;

		if (bullet->isDying())
			break;

		auto rect = zombie->getCollisionBoundingBox();
		//僵尸收到伤害
		if (r.intersectsRect(rect))
		{
			bullet->hurt();
			//僵尸受伤
			zombie->hurt(bullet->getDamage(),bullet->getAttackType());
		}
	}
	//子弹碰撞结束
	bullet->contactEnd();
}
至于土豆雷在发生碰撞后就直接死亡了,其他显示地全是特效层内容罢了,这里就不贴上了。本节效果图

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
植物大战僵尸游戏需要掌握cocos2d-x引擎的基础知识,包括场景、图层、精灵、动画等,同时还需要了解游戏的规则和逻辑。下面是一个简单的植物大战僵尸游戏的实现思路: 1. 创建游戏场景和游戏图层 2. 加载游戏背景、植物、僵尸等资源 3. 实现植物的种植和僵尸的出现 4. 实现植物攻击僵尸和僵尸攻击植物 5. 实现游戏结束和胜利的判定 具体实现细节可以参考下面的代码示例: 1. 创建游戏场景和游戏图层 ``` auto scene = Scene::create(); auto layer = Layer::create(); scene->addChild(layer); ``` 2. 加载游戏资源 ``` auto bg = Sprite::create("bg.png"); auto sunflower = Sprite::create("sunflower.png"); auto zombie = Sprite::create("zombie.png"); ``` 3. 实现植物的种植和僵尸的出现 ``` auto addSunflower = CallFunc::create([&](){ auto sunflower = Sprite::create("sunflower.png"); sunflower->setPosition(Vec2(100, 100)); layer->addChild(sunflower); }); auto addZombie = CallFunc::create([&](){ auto zombie = Sprite::create("zombie.png"); zombie->setPosition(Vec2(500, 100)); layer->addChild(zombie); }); auto sequence = Sequence::create(addSunflower, DelayTime::create(5.0f), addZombie, nullptr); layer->runAction(RepeatForever::create(sequence)); ``` 4. 实现植物攻击僵尸和僵尸攻击植物 ``` auto sunflowerAttack = CallFunc::create([&](){ // 植物攻击 auto bullet = Sprite::create("bullet.png"); bullet->setPosition(sunflower->getPosition()); layer->addChild(bullet); auto move = MoveTo::create(1.0f, zombie->getPosition()); auto remove = RemoveSelf::create(); bullet->runAction(Sequence::create(move, remove, nullptr)); }); auto zombieAttack = CallFunc::create([&](){ // 僵尸攻击 auto attack = Sprite::create("attack.png"); attack->setPosition(zombie->getPosition()); layer->addChild(attack); auto remove = RemoveSelf::create(); attack->runAction(Sequence::create(DelayTime::create(1.0f), remove, nullptr)); }); auto sunflowerSequence = Sequence::create(sunflowerAttack, DelayTime::create(1.0f), nullptr); sunflower->runAction(RepeatForever::create(sunflowerSequence)); auto zombieSequence = Sequence::create(zombieAttack, DelayTime::create(1.0f), nullptr); zombie->runAction(RepeatForever::create(zombieSequence)); ``` 5. 实现游戏结束和胜利的判定 ``` bool isGameOver = false; bool isGameWin = false; auto checkGameOver = CallFunc::create([&](){ if (isGameOver) { // 游戏结束 // ... } }); auto checkGameWin = CallFunc::create([&](){ if (isGameWin) { // 游戏胜利 // ... } }); auto gameOverSequence = Sequence::create(DelayTime::create(10.0f), checkGameOver, nullptr); auto gameWinSequence = Sequence::create(DelayTime::create(10.0f), checkGameWin, nullptr); layer->runAction(gameOverSequence); layer->runAction(gameWinSequence); ``` 以上就是一个简单的植物大战僵尸游戏的实现思路,具体实现还需要根据自己的需求进行调整和完善。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值