cocos2dx 植物大战僵尸 23 撑杆僵尸

撑杆僵尸在一开始快速运动,能跳过第一个碰到的植物,并且在这之后速度会变慢下来,并且在跳的过程中是不与子弹碰撞 以及免疫冰冻等特殊效果的。所以需要有一个撑杆饰品类,作为以后的扩展使用,同时需要更新僵尸基类。

class ZombieDelegate
{
public:
	virtual Plant*getTopPlant(Terrain*terrain) = 0;
	virtual void showZombieHead(const Point&pos,int tag) = 0;
	virtual void showZombieDie(const Point&pos,int tag) = 0;
	virtual void showConeAction(const Point&pos,int tag) = 0;
	virtual void showZombieBoomDie(const Point&pos,int tag)=0;
	virtual void showPaperZombieDie(const Point&pos,int tag) = 0;
	virtual void showPaperZombieHead(const Point&pos,int tag) = 0;
	virtual void showPoleVaultingZombieHead(const Point&pos,int tag)=0;
	virtual void showPoleVaultingZombieDie(const Point&pos,int tag)=0;
};
增加了撑杆的死亡动画,同时所有的这些方法都添加了一个tag,这个tag是表示的当前僵尸所处的tag来处理各种遮挡。需要在其他类中进行相应的更新。

//是否参与与子弹的碰撞,不包括Boom
virtual bool isActiveForBullet()const;
这个是ZombieBase新添加的方法,默认返回true。接下来看看ZombieDelegate的更新。然后在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))
		{
			this->handleCollision(bullet,zombie);
		}
	}
	//子弹碰撞结束
	bullet->contactEnd();
}
把僵尸和子弹的碰撞处理放到了一个新的函数中。

void BulletLayer::handleCollision(Bullet*bullet,ZombieBase*zombie)
{
	auto attactType = bullet->getAttackType();
	bool isTrack = Bullet::isTrackBullet(attactType);
	bool bIsHurt = false;
	//当前子弹是Boom 则无法避免
	if (bullet->getAttackType() == AttackType::Boom)
	{
		bIsHurt = true;
	}//僵尸是和子弹能发生碰撞
	else if (zombie->isActiveForBullet())
	{
		//是追踪性子弹 并且碰撞的是目标僵尸
		if (isTrack && zombie == bullet->getAimZombie())
			bIsHurt = true;
		//不是追踪子弹
		else if (!isTrack)
			bIsHurt = true;
	}
	if (bIsHurt)
	{
		bullet->hurt();
		//僵尸受伤
		zombie->hurt(bullet->getDamage(),bullet->getAttackType());
	}
}
这里用了新添加的函数isActiveForBullet()来处理碰撞。接着就是实现撑杆僵尸相应的动画更改和逻辑。

class PoleVaultingZombie : public ZombieBase
{
private:
	enum class State
	{
		None,
		Walk,
		Attack,
		WalkDead,
		AttackDead,
		Jump,
		Jump2,
	};
private:
	bool m_bLosePole;//是否失去了撑杆
	bool m_bIsActiveForBullet;//是否对子弹有效
	State m_state;
	float m_duration;
	float m_elapsed;
public:
	PoleVaultingZombie();
	~PoleVaultingZombie();

	static PoleVaultingZombie*create(const string&zombieName);
	bool init(const string&zombieName);
private:
	virtual void updateAlive(float dt);
	virtual void performMove(float dt);
	virtual float getCurSpeed()const;
	virtual Rect getCollisionBoundingBox()const;
	virtual void onNormalDead();
	virtual void onCRPDead();
	virtual bool isActiveForBullet()const;

	void jump();//僵尸跳起
	void jump2();//跳起阶段2
	void jumpEnd();
	void attackUpdate(float dt);
	void changeState(State state);
	void showZombieHead();
};
看看相应的实现。

bool PoleVaultingZombie::init(const string&zombieName)
{
	this->setZombieName(zombieName);

	//获取行走状态贴图
	auto animationName = zombieName;
	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*0.55f);

	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;
}
动画处理和以前的僵尸类相同,没什么太多注意的。
void PoleVaultingZombie::updateAlive(float dt)
{
	//处于跳起状态
	if (m_state == State::Jump)
	{
		m_elapsed += dt;
		//跳起完成 检测是否碰撞的是否是高坚果
		if (m_elapsed >= m_duration)
		{
			m_elapsed = 0.f;
			this->jump2();
		}
	}//跳起2
	else if (m_state == State::Jump2)
	{
		m_elapsed += dt;
		//转到正常动画
		if (m_elapsed >= m_duration)
		{
			m_elapsed = 0.f;
			this->jumpEnd();
		}
	}
	else if (m_pAim != nullptr)
	{
		//当前存在植物
		if (m_pAim->getInnerPlant() != nullptr)
		{
			if (m_bLosePole)
				this->attackUpdate(dt);
			else
				this->jump();
		}
		else
		{
			this->clearAim();
			m_elapsed = 0.f;
		}
	}
}
在updateAlive中进行相应的逻辑更新。

void PoleVaultingZombie::performMove(float dt)
{
	if (m_state == State::Jump || m_state == State::Jump2)
		return;

	if (m_pMoveBehavior != nullptr &&
		(m_state == State::Walk || m_state == State::WalkDead))
	{
		m_pMoveBehavior->performMove(this);
	}
}
撑杆僵尸在跳起阶段是不会进行移动的,这个需要注意。
float PoleVaultingZombie::getCurSpeed()const
{
	auto speed = ZombieBase::getCurSpeed();

	if (m_bLosePole)
		speed /= 3.f;

	return speed;
}
获取当前的速度则是直接除以三即可,也可以进行相应的调整。
Rect PoleVaultingZombie::getCollisionBoundingBox()const
{
	auto rect = ZombieBase::getCollisionBoundingBox();

	rect.origin.x += rect.size.width/2.f;
	rect.size.width /= 4.f;
	rect.origin.y += rect.size.height/2.f;
	rect.size.height /= 2.f;

	return rect;
}
获取当前的碰撞面积,这个跟撑杆僵尸的图片有关,撑杆僵尸的图片如下

void PoleVaultingZombie::onNormalDead()
{
	if (m_state == State::Walk)
		changeState(State::WalkDead);
	else if (m_state == State::Attack)
		changeState(State::AttackDead);
}

void PoleVaultingZombie::onCRPDead()
{
	this->setDead(true);
	//显示死亡动画
	m_pDelegate->showPoleVaultingZombieDie(this->getPosition(),this->getTag());
}

bool PoleVaultingZombie::isActiveForBullet()const
{
	return m_bIsActiveForBullet;
}

void PoleVaultingZombie::jump()
{
	this->changeState(State::Jump);
	//不对子弹起碰撞
	m_bIsActiveForBullet = false;
}

void PoleVaultingZombie::jump2()
{
	this->changeState(State::Jump2);
	//失去撑杆
	m_bLosePole = true;
	//是否能跳过去 TODO
	//直接设置位置
	auto pos = this->getPosition();
	auto size = this->getContentSize();
	auto rect = this->getCollisionBoundingBox();

	//获取当前的植物是否是高坚果
	auto topPlant = m_pDelegate->getTopPlant(m_pAim);
	//跳过失败
	if (PlantLayer::isTallNut(topPlant))
	{
		this->setPosition(pos - Point(40.f,0.f));
	}
	else
	{
		this->setPosition(pos - Point(120.f,0.f));
	}
	//清除当前目标
	this->clearAim();
}

void PoleVaultingZombie::jumpEnd()
{
	this->changeState(State::Walk);
	m_bIsActiveForBullet = true;
}

void PoleVaultingZombie::attackUpdate(float dt)
{
	this->changeState(State::Attack);
	m_elapsed += dt;
	//到达攻击时间
	if (m_elapsed >= this->getColdDownTime())
	{
		m_elapsed -= this->getColdDownTime();
		//进行攻击
		auto topPlant = m_pDelegate->getTopPlant(m_pAim);
		topPlant->hurt(this->getDamage());
	}
}
void PoleVaultingZombie::changeState(State state)
{
	//状态没有发生改变,直接退出
	if (m_state == state)
		return ;

	m_state = state;
	string animationName;
	Animation*animation = nullptr;
	auto zombieName = this->getZombieName();

	if (m_state == State::Walk)
	{
		if (m_bLosePole)
		{
			animationName = StringUtils::format("%sWalk",zombieName.c_str());
		}
		else
		{
			animationName = zombieName;
		}

		animation = AnimationCache::getInstance()->getAnimation(animationName);
	}
	else if (m_state == State::Attack)
	{
		animationName = StringUtils::format("%sAttack",zombieName.c_str());
		animation = AnimationCache::getInstance()->getAnimation(animationName);
	}
	else if (m_state == State::Jump)
	{
		animationName = StringUtils::format("%sJump",zombieName.c_str());
		animation = AnimationCache::getInstance()->getAnimation(animationName);
		m_duration = animation->getDuration();
	}
	else if (m_state == State::Jump2)
	{
		animationName = StringUtils::format("%sJump2",zombieName.c_str());
		animation = AnimationCache::getInstance()->getAnimation(animationName);
		m_duration = animation->getDuration();
	}
	else if (m_state == State::WalkDead)
	{
		if (!m_bLosePole)
		{
			animationName = StringUtils::format("%sLostHead",zombieName.c_str());
		}
		else
		{
			animationName = StringUtils::format("%sLostHeadWalk",zombieName.c_str());
		}
		animation = AnimationCache::getInstance()->getAnimation(animationName);
		this->showZombieHead();
	}
	else if (m_state == State::AttackDead)
	{
		animationName = StringUtils::format("%sLostHeadAttack",zombieName.c_str());
		animation = AnimationCache::getInstance()->getAnimation(animationName);

		this->showZombieHead();
	}
	if (animation != nullptr)
	{
		//停止原先的动画
		this->getSprite()->stopActionByTag(ANIMATION_TAG);

		auto animate = Animate::create(animation);
		//是否处于减速状态
		Speed*speed = Speed::create(animate,1.f);
		if (this->isDuringDeceleration())
			speed->setSpeed(0.7f);

		speed->setTag(ANIMATION_TAG);

		this->getSprite()->runAction(speed);
	}
}

void PoleVaultingZombie::showZombieHead()
{
	//调整位置
	Point bornPos = this->getPosition();
	Size size = this->getContentSize();

	m_pDelegate->showPoleVaultingZombieHead(bornPos,this->getTag());
}
changeState中依旧是对动画进行改变的。接下来就是ZombieFactory

PoleVaultingZombie*ZombieFactory::createPoleVaultingZombie(const string&zombieName)
{
	auto zombie = PoleVaultingZombie::create(zombieName);
	//设置基础属性
	zombie->setDead(false);
	zombie->setHitPoint(430);
	zombie->setBaseSpeed(0.3f);
	zombie->setColdDownTime(1.f);
	zombie->setDamage(100);
	zombie->setCriticalPoint(70.f);
	//添加血条 并对血条的位置进行调整
	Size size = zombie->getContentSize();
	Rect rect = zombie->getSprite()->getSpriteFrameRect();

	Point pos(size.width*0.75f,rect.origin.y);

	this->bindHpBarForZombie(zombie,pos);

	return zombie;
}
新建撑杆僵尸,并且设置血条位置

Point ZombieFactory::bindHpBarForZombie(ZombieBase*zombie,const Point&pos)
{
	float hp = (float)zombie->getHitPoint();
	HpBar*hpBar = HpBar::create("hpBar1.png","hpBarBG.png",hp);

	hpBar->setPosition(pos);

	zombie->bindHpBar(hpBar);

	return pos;
}
对绑定血条相应的更新
Point ZombieFactory::bindHpBarForZombie(ZombieBase*zombie)
{
	//设置血条位置
	auto rect = zombie->getSprite()->getSpriteFrameRect();
	Size size = zombie->getContentSize();

	Point pos = Point(rect.origin.x + rect.size.width/2,rect.size.height/2 - size.height/2);
	
	return this->bindHpBarForZombie(zombie,pos);
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值