原版植物大战僵尸的路障是饰品,能阻挡一部分伤害,在路障掉落前路障僵尸是不会受伤的。
如下为个人头脑风暴。
路障僵尸使用装饰者的话,需要继承自ZombieBase,由于图片原因,所以内部需要有一个普通僵尸。对木桶僵尸,内部处理的逻辑为站立,行走,攻击,当路障死亡后更新交给Zombie即可。路障在活着时负责对伤害的吸收,在路障死亡时,会有一个路障掉落动画。同时路障僵尸的贴图消失,显示内部僵尸的贴图。但是用装饰者无法实现磁力菇,因为磁力菇需要判断僵尸是否有饰品,如果有还需要判断饰品是否为铁质饰品。故新建饰品类为Garnishry,不过这样一来路障僵尸就需要继承自普通僵尸,因为植物大战僵尸使用的是骨骼动画,能很容易地实现路障等饰品随僵尸运动的效果,而帧动画要实现就很困难了。 目前思路1 路障僵尸的路障可以增加防御力,比如豌豆攻击20,则吸收10即可。这样和原著稍微不同,好处是动画会连贯,(需要在死亡时头和饰品全部掉落.显得不那么突兀) 思路2 尽量跟进原版,缺点是动画处理肯定不流畅,优点就是和原版接近。 个人偏向于思路1的,毕竟帧动画限制。不过还是需要实现路障僵尸类,毕竟贴图不同 以上就是我决定添加饰品类和路障僵尸的部分思路 先看看路障的实现吧。 //-------------------------路障Conehead---------------------------- class Conehead : public Garnishry { SDL_SYNTHESIZE(int,m_nDefense,Defense);//防御值 public: Conehead(); ~Conehead(); CREATE_FUNC(Conehead); bool init(); virtual int absorbDamage(int baseDamage,AttackType attackType); }; bool Conehead::init() { //设置血量 不小于0即可 this->setHitPoint(1); this->setType(Type::Common); this->setDefense(13); return true; } int Conehead::absorbDamage(int baseDamage,AttackType attackType) { //吸收部分伤害,如果伤害值小于0,强制少1 auto damage = baseDamage - this->getDefense(); if (damage < 0) { damage = 1; } return damage; }路障专用于路障僵尸,每次都会吸收13点伤害。路障僵尸继承于Zombie /*由于资源和帧动画限制,只能继承自Zombie*/ class ConeheadZombie : public Zombie { public: ConeheadZombie(); ~ConeheadZombie(); static ConeheadZombie*create(const string&zombieName); bool init(const string&zombieName); protected: virtual void changeState(State state); virtual void showZombieHead(); };由于是继承自Zombie,路障僵尸实现就简单多了 void ConeheadZombie::changeState(State state) { //状态没有发生改变,直接退出 if (m_state == state) return ; m_state = state; string animationName; if (m_state == State::Walk) { animationName = StringUtils::format("%sWalk",m_zombieName.c_str()); } else if (m_state == State::Attack) { animationName = StringUtils::format("%sAttack",m_zombieName.c_str()); } else if (m_state == State::WalkDead) { animationName = "ZombieLostHead"; this->showZombieHead(); } else if (m_state == State::AttackDead) { animationName = "ZombieLostHeadAttack"; this->showZombieHead(); } //停止原先的动画 this->getSprite()->stopActionByTag(ANIMATION_TAG); auto animation = AnimationCache::getInstance()->getAnimation(animationName); auto animate = Animate::create(animation); animate->setTag(ANIMATION_TAG); this->getSprite()->runAction(animate); }改变状态时改变对应的动画,在Zombie::update()中进行调用。 void ConeheadZombie::showZombieHead() { //调整位置 Point bornPos = this->getPosition(); Size size = this->getContentSize(); bornPos.x += size.width/4.f; m_pDelegate->showZombieHead(bornPos); //显示路障掉落动作 Point pos = this->getPosition(); pos.x += size.width/4; pos.y -= size.height/2; m_pDelegate->showConeAction(pos); }这里比普通僵尸多了的就是路障掉落动作了,在特效层实现。 void EffectLayer::showConeAction(const Point&pos,Layer*layer,int tag) { //获取路障精灵名称 auto spriteName = "Zombie_cone3.png"; float duration = 0.8f; float rotation = 20.f; Sprite*sprite = Sprite::createWithSpriteFrameName(spriteName); sprite->setPosition(pos); sprite->setRotation(rotation); layer->addChild(sprite,tag); //运行动作 JumpBy*jump = JumpBy::create(duration,Point(40.f,140.f),-10.f,1); RotateBy*rotate = RotateBy::create(duration,40.f); RemoveSelf*remove = RemoveSelf::create(); auto spawn = Spawn::createWithTwoActions(jump,rotate); auto seq = Sequence::createWithTwoActions(spawn,remove); sprite->runAction(seq); }然后在cards.plist添加路障僵尸卡片即可 <!--路障僵尸--> <key>ConeheadZombie</key> <dict> <key>desc</key> <string></string> <key>worth</key> <integer>75</integer> <key>CD</key> <real>7.5</real> <key>ready time</key> <real>0</real> <key>active</key> <string>all</string> <key>needful terrain</key> <array> <string>Lawn</string> </array> </dict>然后在ZombieFactory中实现对应的创建方法 ConeheadZombie*ZombieFactory::createConeheadZombie(const string&zombieName) { auto zombie = ConeheadZombie::create(zombieName); //设置基础属性 zombie->setDead(false); zombie->setHitPoint(200); zombie->setBaseSpeed(0.15f); zombie->setColdDownTime(1.f); zombie->setDamage(100); zombie->setCriticalPoint(70.f); //设置装饰品 zombie->setGarnishry(Conehead::create()); //添加血条 HpBar*hpBar = HpBar::create("hpBar1.png","hpBarBG.png",200.f); //设置血条位置 auto rect = zombie->getSprite()->getSpriteFrameRect(); Size size = zombie->getContentSize(); Size barSize = hpBar->getContentSize(); Point pos; pos.x = rect.origin.x + rect.size.width/2; pos.y = rect.size.height/2 - size.height/2 - barSize.height/2; hpBar->setPosition(pos); zombie->bindHpBar(hpBar); return zombie; }然后在ZombieLayer中的makeZombie中调用这个函数 else if (zombieName == CONEHEADZOMBIE_NAME) { zombie = m_pZombieFactory->createConeheadZombie(zombieName); zombie->setZombieDir(ZombieDir::Left); moveBehavior = new LineMoveBehavior(); }本节截图