原版植物大战僵尸的路障是饰品,能阻挡一部分伤害,在路障掉落前路障僵尸是不会受伤的。
如下为个人头脑风暴。
路障僵尸使用装饰者的话,需要继承自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();
}
本节截图