cocos2dx 植物大战僵尸 18 土豆雷

xiaoxiao2021-02-28  84

土豆雷是我打植物大战僵尸时喜欢使用的植物,它能保证在开局时能快速地种植植物。今天就实现土豆雷。 土豆雷有一个准备时间,在准备时间完成前不具有任何攻击力。以后破土,能够炸死小范围的僵尸,之后土豆雷死亡。 土豆雷在破土后,每一帧检查是否有僵尸和它发生碰撞,如果有,就炸死小范围的僵尸,然后有一个土豆雷炸过后的特效,以及僵尸有一个变成灰的特效。我的思路是使用一个特殊的子弹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(); }至于土豆雷在发生碰撞后就直接死亡了,其他显示地全是特效层内容罢了,这里就不贴上了。本节效果图
转载请注明原文地址: https://www.6miu.com/read-61091.html

最新回复(0)