cocos2dx 植物大战僵尸 22 寒冰射手

寒冰射手是我目前感觉比较难的植物,因为这个植物的子弹会给僵尸一个减速的debuff的,而这个debuff对有的僵尸 起作用,比如一般的僵尸,而对带有报纸的僵尸或者一些特殊的僵尸也是不会减速的,所以饰品需要以下两个功能

1.吸收伤害

2.吸收一些debuff

因为c++无法有两个返回值,所以就不能使用返回值了,对于c++,可以使用引用来改变伤害值和当前攻击类型。先对当前的饰品基类进行改变。

class Garnishry : public Entity
{
public:
	enum class Type
	{
		Common,//普通饰品
		Iron,//铁质饰品
	};
	SDL_SYNTHESIZE(int,m_nHitPoint,HitPoint);//当前血量
	SDL_SYNTHESIZE(Type,m_type,Type);//饰品类型
public:
	Garnishry();
	~Garnishry();
	/**吸收伤害值
	*baseDamage attackType可能会改变*/
	virtual void absorbDamage(int &baseDamage,AttackType &attackType);
路障和报纸需要作一些改变
void Conehead::absorbDamage(int &baseDamage,AttackType &attackType)
{
	//吸收部分伤害,如果伤害值小于0,强制减少1
	auto damage = baseDamage - this->getDefense();

	if (damage < 0)
	{
		damage = 1;
	}

	baseDamage = damage;
}
void Paper::absorbDamage(int &baseDamage,AttackType &attackType)
{
	int afterDamage = 0;
	//跟踪性子弹,无法吸收
	if (Bullet::isTrackBullet(attackType))
	{
		afterDamage = baseDamage;
	}
	else//吸收伤害TODO
	{
		auto afterHP = this->getHitPoint() - baseDamage;
		//饰品即将死亡
		if (afterHP <= 0)
		{
			afterDamage = SDL_abs(afterHP);
			afterHP = 0;
		}
		this->setHitPoint(afterHP);
		m_pHpBar->setValue((float)afterHP);
		//如果受到寒冰攻击,转换成正常状态
		if (attackType == AttackType::Deceleration)
		{
			attackType = AttackType::Common;
		}
	}
	baseDamage = afterDamage;
}
报纸能使得当前的报纸僵尸免疫减速效果的,这里注意,AttackType增加了一个减速类型,目前的Attack Type如下
enum class AttackType
{
	Common,/*无效果*/
	Boom,/*爆炸效果*/
	Swallow,/*吞噬效果*/
	Track,/*追踪效果*/
	Deceleration,/*减速*/
	TrackAndDeceleration,/*追踪且减速*/
};
这是对以后的一些适配,以后可能还是会修改的。接下来就是僵尸基类的改变了。
void ZombieBase::hurt(int baseDamage,AttackType attackType)
{
	int afterDamage = baseDamage;
	//调用饰品,吸收伤害
	if (m_pGarnishry != nullptr && m_pGarnishry->getHitPoint() > 0)
	{
		m_pGarnishry->absorbDamage(baseDamage,attackType);

		afterDamage = baseDamage;
		//如果饰品死亡,回调饰品死亡函数
		if (m_pGarnishry->getHitPoint() <= 0)
			onGarnishryDead();
	}

	if (afterDamage <= 0)
		return ;
	//进行debuff的操作
	this->debuff(attackType);

	auto afterHP = this->getHitPoint() - afterDamage;
	bool bDead = false;

	if (afterHP <= 0)
	{
		afterHP = 0;
		bDead = true;
	}
	this->setHitPoint(afterHP);
	//设置血量条
	if (m_pHpBar != nullptr)
	{
		m_pHpBar->setValue((float)afterHP);
	}
	onHurt();
	//如果死亡,回调死亡函数
	if (bDead)
	{
		if (attackType == AttackType::Swallow)
		{
			onSwallowDead();
		}
		else if (attackType == AttackType::Boom)
		{
			onBoomDead();
		}
		else
		{
			onNormalDead();
		}
	}
}

在这之前还需要添加

/*僵尸的减益效果*/
enum class DebuffType
{
	Deceleration,
};
typedef struct Debuff
{
	DebuffType type;
	float duration;
public:
	Debuff(DebuffType type,float d):type(type),duration(d){}
}Debuff;
表示当前的减益效果和持续时间。然后需要在ZombieBase种添加一个数组,来保存当前的debuff
vector<Debuff> m_debuffs;//当前的僵尸的debuff

然后添加了两个函数。

	//减速debuff开始动画必须经过Speed包装
	virtual void onDecelerationDebuffEnter();
	//减速debuff结束
	virtual void onDecelerationDebuffExit();
void ZombieBase::debuff(AttackType attackType)
{
	//TODO
	if (attackType == AttackType::Deceleration)
	{
		DebuffType debuffType = DebuffType::Deceleration;
		
		auto it = find_if(m_debuffs.begin(),m_debuffs.end(),[debuffType](Debuff debuff)
		{
			return debuff.type == debuffType;
		});

		if (it != m_debuffs.end())
		{
			it->duration = 10.f;
		}
		else//添加buff
		{
			m_debuffs.push_back(Debuff(debuffType,10.f));
			//回调减速函数
			this->onDecelerationDebuffEnter();
		}
	}
}
同时修改了update的函数。
void ZombieBase::update(float dt)
{
	//当前僵尸血量小于0,死亡
	if (this->getHitPoint() <= 0)
	{
		auto afterCRP = this->getCriticalPoint() - 0.4f;
		this->setCriticalPoint(afterCRP);
		//僵尸真正死亡
		if (afterCRP <= 0.f)
		{
			onCRPDead();
		}
	}
	else
	{
		updateAlive(dt);
	}
	//进行debuff的更新
	for (auto it = m_debuffs.begin();it != m_debuffs.end();)
	{
		auto &debuff = *it;

		debuff.duration -= dt;
		//减速结束
		if (debuff.duration <= 0.f &&
			debuff.type == DebuffType::Deceleration)
		{
			it = m_debuffs.erase(it);
			this->onDecelerationDebuffExit();
		}
		else
		{
			it++;
		}

	}
	performMove(dt);
}
在update中进行debuff的更新,如果持续时间到了之后,就回调onDecelrationDebuffExit()函数。
void ZombieBase::onDecelerationDebuffEnter()
{
	if (m_pSprite)
	{
		m_pSprite->setColorMod(Color3B(0,255,255));
		
		auto action = this->getSprite()->getActionByTag(ANIMATION_TAG);
		auto speed = dynamic_cast<Speed*>(action);

		speed->setSpeed(0.7f);
	}
}

void ZombieBase::onDecelerationDebuffExit()
{
	if (m_pSprite)
	{
		m_pSprite->setColorMod(Color3B(255,255,255));

		auto action = this->getSprite()->getActionByTag(ANIMATION_TAG);
		auto speed = dynamic_cast<Speed*>(action);

		speed->setSpeed(1.f);
	}
}
注意,在僵尸减速时会使得动画播放会变得很慢,所以需要内部动画使用Speed进行封装(Speed使用了装饰者模式),这个需要在子类中进行定义每个动画的tag必须是ANIMATION_TAG,并且是Speed才行。
float ZombieBase::getCurSpeed()const
{
	auto speed = m_fBaseSpeed;
	//减速成三分之二
	if (this->isDuringDeceleration())
	{
		speed = speed /3.f * 2.f;
	}
	return speed;
}
获取当前的速度收到减速的影响,会减速到原来的三分之二
bool ZombieBase::isDuringDeceleration()const
{
	auto it = find_if(m_debuffs.begin(),m_debuffs.end(),[](Debuff debuff)
	{
		return debuff.type == DebuffType::Deceleration;
	});

	if (it != m_debuffs.end())
	{
		return true;
	}
	return false;
}
表示当前是否存在减速状态。然后需要在子类僵尸中进行更新动画,以报纸僵尸为例。
bool PaperZombie::init(const string&zombieName)
{
	//正常动画
	this->setZombieName(zombieName);
	//获取站立状态贴图
	int status = m_bIsAngry ? 0 : 1;
	auto animationName = StringUtils::format("%sWalk%d",m_zombieName.c_str(),status);

	auto animation = AnimationCache::getInstance()->getAnimation(animationName);
	//设置贴图
	auto firstFrame = animation->getFrames().front()->getSpriteFrame();

	m_pSprite = Sprite::createWithSpriteFrame(firstFrame);

	auto size = m_pSprite->getContentSize();
	m_pSprite->setPosition(size.width/2,size.height/2);

	this->setContentSize(size);
	this->addChild(m_pSprite);
	//运行站立动画
	auto animate = Animate::create(animation);
	Speed*speed = Speed::create(animate,1.f);
	
	speed->setTag(ANIMATION_TAG);

	m_pSprite->runAction(speed);
	//设置为行走状态
	m_state = State::Walk;

	return true;
}
同时在
	virtual void changeState(State state);
	virtual void showZombieHead();
	virtual float getCurSpeed()const;
	virtual void onGarnishryDead();
也是需要上面的更新。
float PaperZombie::getCurSpeed()const
{
	auto speed = ZombieBase::getCurSpeed();

	if (m_bIsAngry)
		speed *= 2.f;

	return speed;
}
当前速度受到了减速效果,同时也会加速的。然后就是寒冰子弹的实现了,寒冰子弹的实现类似于一般的豌豆子弹,只是死亡动画不同,不再叙述。
SnowPeaBullet*BulletLayer::addSnowPeaBullet()
{
	//设置基础属性
	auto bullet = SnowPeaBullet::create();
	bullet->setDead(false);
	bullet->setAttackType(AttackType::Deceleration);
	bullet->setHitPoint(1);

	m_bullets.push_back(bullet);

	return bullet;
}

本节游戏截图。


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值