有了防御塔没有子弹类是不能攻击敌人的,所以接着来讨论子弹,新建一个子弹基类Bullet.h
class Bullet : public Sprite { public: Bullet(); ~Bullet(); virtual bool init(); CREATE_FUNC(Bullet); protected: CC_SYNTHESIZE(int,maxForce,MaxForce);//攻击力 CC_SYNTHESIZE(int,bulletScope,BulletScope);//塔的子弹攻击范围 CC_SYNTHESIZE(int,bulletType,BulletType);//子弹类型 CC_SYNTHESIZE(Spawn*,bulletAction,BulletAction);//子弹飞行动画 Sprite* sprite;//子弹精灵-贴图 virtual void shoot(){};//攻击 virtual void removeBullet(){};//攻击完毕后移除 };
在基类中我们定义了一些共有的方法和属性,然后根据不同的子弹来重写它
例如上一篇提到的初级箭塔的弓箭,我们需要重写init()来给精灵贴上弓箭这张图片(arrow.png在plist里,实现加载过该plist,具体加载过程见开始动画章节)
bool Arrow::init() { if (!Sprite::init()) { return false; } sprite = Sprite::createWithSpriteFrameName("arrow.png"); addChild(sprite); return true; }然后重写shoot(),弓箭的攻击动作最简单,新建一个动画序列,先执行箭塔根据自身位置和敌人位置生成的弧线和弓箭自身旋转的动画,然后执行removeBullet
void Arrow::shoot() { SoundManager::playArrowRelease();//播放音效 runAction(Sequence::create(bulletAction,CallFuncN::create(CC_CALLBACK_0(Arrow::removeBullet,this)),NULL)); }其中弓箭在执行完上述动画后,若此时弓箭所在位置与敌人位置重叠即击中敌人,则根据攻击力减少敌人血量,弓箭所在的区域如下:
auto bulletRect = Rect(
this->getPositionX() +this->getParent()->getPositionX() - this->getContentSize().width /2,
this->getPositionY() +this->getParent()->getPositionY() - this->getContentSize().height/2,
this->sprite->getContentSize().width,
this->sprite->getContentSize().height );
因为弓箭是由防御塔创建并且添加在防御塔建造点那个精灵上上,所以需要通过this->getParent()->getPositionX()先来获取防御塔X轴所在的位置,this->getPositionX() 即子弹相对于防御塔的X轴位置,两者相加即子弹在地图所在的位置,Y轴同理,根据宽高计算相应的区域。
然后我们遍历保存在单例中的敌人,若区域重叠,则判断集中,进行更新敌人血量、执行喷血(血腥~)动画等动作。
具体思路来自于cocos2dx官网《贼来了》这款教程,但不同的是他将子弹的动画与击中敌人等动作由地图类完成,通过每一帧来判断是否集中敌人,这样方案在2D平面中可行,因为这款游戏是2.5D的,弓箭有一个飞到最高点并下落的过程,所以必须由其自身执行,并在其动画结束在判断。、
若为集中敌人,有一个弓箭插在地上并且等待若干时间后消失的动画
void Arrow::removeBullet() { bool isMissed = true;//判断是否击中,默认未击中 auto instance = GameManager::getInstance(); auto bulletRect = Rect(this->getPositionX() +this->getParent()->getPositionX() - this->getContentSize().width /2,this->getPositionY() +this->getParent()->getPositionY() - this->getContentSize().height/2,this->sprite->getContentSize().width,this->sprite->getContentSize().height ); auto monsterVector = instance->monsterVector; //遍历 for (int j = 0; j < monsterVector.size(); j++) { auto monster = monsterVector.at(j); auto monsterRect = monster->baseSprite->getBoundingBox(); //判断是否重叠并且可以被士兵击中,即不在地下(有种地下的敌人无法被射中) if (monsterRect.intersectsRect(bulletRect) && monster->getAttackBySoldier()) { auto currHp = monster->getCurrHp(); currHp = currHp - this->getMaxForce() + monster->getArmor();// if(currHp <= 0){ currHp = 0; } monster->setCurrHp( currHp ); monster->getHpBar()->setPercentage((currHp/monster->getMaxHp())*100);//更新血条 monster->getHurt(); isMissed = false; //设为击中 if(currHp == 0){ monster->death(); } break; } } if(isMissed){//若未击中 sprite->setSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("decal_arrow.png")); sprite->runAction(Sequence::create(FadeOut::create(1.0f),CallFuncN::create(CC_CALLBACK_0(Bullet::removeFromParent,NULL)); }else{ this->removeFromParent(); } }
这就是最简单的子弹类---弓箭,还有其他子弹例如炮弹、导弹甚至震荡波,巫毒图腾等~也是这个思路,只不过动画复杂的鞋
有了地图,防御塔,子弹,相信初学者已经可以独立完成这款游戏了,下面将介绍基本怪物类