[Cocos2d塔防游戏开发]Cocos2dx-3.X完成塔防游戏《王国保卫战》--防御塔(二)之初级箭塔

该章节主要介绍如何制作初级箭塔

首先我们先观察下这个游戏的箭塔

 

这个游戏的箭塔都是拥有两个弓箭手。以初级塔为例,左右两边分别有两个弓箭手,可以攻击不同的目标,并且同时只有一个弓箭手在攻击。根据这个特性我们写一个BaseArrowTower

class BaseArrowTower: public BaseTower
{
public:

protected:
	Sprite* shooter_1;//弓箭手1号
	Sprite* shooter_2;//弓箭手2号
	Sprite* towerBase;//塔
	int shootTag;//弓箭手标记
	void initTower(int level);//初始化弓箭塔
	void addTerrain();//添加塔坯子(就是那个都是塔下面那个都是弓箭的地面,不同地图有不同的坯子~)
	virtual Bullet* ArrowTowerBullet();//生成弓箭
	virtual void shoot(float dt);//射!
};


现在让我们看下防御塔建造过程:

1.选择建造类型

2.执行建造动画(进度条,冒烟等)

3.去除动画精灵,添加防御塔

4.开始攻击

同样用1级箭塔举例

class SimpleArrowTowerlvl1: public BaseArrowTower
{
public:

	bool init();//初始化
        CREATE_FUNC(SimpleArrowTowerlvl1);
	void updateTower();//升级
	void showUpdateMenu();//显示升级菜单
	Bullet* ArrowTowerBullet();//生成弓箭
private:
	void buildingAnimation();//开始建造动画
	void buildingSmokeAnimation(float dt);
};

其中init()函数会由BaseArrowTower中的CREATE_FUNC宏自动执行,在init()中依次初始化各个参数,并且执行建造动画buildingAnimation

其中建造动画就是添加进度条、建造动画精灵等动作

void SimpleArrowTowerlvl1::buildingAnimation()
{
    auto building = Sprite::create();
    auto constructing = Sprite::createWithSpriteFrameName("tower_constructing_0004.png");
    auto hpBgSprite = Sprite::createWithSpriteFrameName("buildbar_bg.png");
    hpBgSprite->setPosition(Point(constructing->getContentSize().width / 2, constructing->getContentSize().height /2+10));
    auto hpBar = ProgressTimer::create(Sprite::createWithSpriteFrameName("buildbar.png"));
    hpBar->setType(ProgressTimer::Type::BAR);
    hpBar->setMidpoint(Point(0, 0.5f));
    hpBar->setBarChangeRate(Point(1, 0));
    hpBar->setPercentage(0);
    hpBar->setPosition(Point(hpBgSprite->getContentSize().width / 2, hpBgSprite->getContentSize().height / 2 ));
    hpBgSprite->addChild(hpBar);
    constructing->addChild(hpBgSprite);
    building->addChild(constructing);
    addChild(building);
    hpBar->runAction(Sequence::create(ProgressTo::create(0.5f, 100)
	, CallFuncN::create(CC_CALLBACK_0(Sprite::removeFromParent, building))
                                           , NULL));
    scheduleOnce(schedule_selector(SimpleArrowTowerlvl1::buildingSmokeAnimation),0.5f);
}
hpBar->runAction(Sequence::create(ProgressTo::create(0.5f, 100), CallFuncN::create(CC_CALLBACK_0(Sprite::removeFromParent, building)), NULL));是执行一个动画序列,首先是执行进度条的动画,时间0.5秒,从0-100,再执行removeFromParent将建造动画精灵移除。

再延迟0.5S执行scheduleOnce(schedule_selector(SimpleArrowTowerlvl1::buildingSmokeAnimation),0.5f);执行一个冒烟动画然后将塔添加进去(当然这里也可以写到上面的动画序列当中)

void SimpleArrowTowerlvl1::buildingSmokeAnimation(float dt)
{
    auto smoke = Sprite::createWithSpriteFrameName("effect_buildSmoke_0001.png");
    addChild(smoke,99);
    smoke->runAction(Sequence::create(
		Animate::create(AnimationCache::getInstance()->getAnimation("build_smoke")),
		CallFuncN::create(CC_CALLBACK_0(Sprite::removeFromParent, smoke)),
		NULL));
    SoundManager::playArcherReady();
    initTower(1);
    setListener();

    schedule(schedule_selector(SimpleArrowTowerlvl1::shoot), 1.0f);
}
并在1S后开始执行shoot攻击敌人
void BaseArrowTower::shoot(float dt)
{
    auto instance = GameManager::getInstance();
    checkNearestMonster();
    char temp1[20]; 
    sprintf(temp1, "level%d_shoot_down", level); 
    char temp2[20]; 
    sprintf(temp2, "level%d_shoot_top", level);//根据等级生成图片名,保存临时变量
    if(nearestMonster!=NULL && nearestMonster->getCurrHp() > 0 )
    {
	auto currBullet = ArrowTowerBullet();
	Point shootVector = nearestMonster->baseSprite->getPosition() - this->getParent()->getPosition();//怪物精灵是在地图上添加的,而塔的父精灵才是在地图上添加的,所以要统一标准计算
        //计算防御塔与敌人之间的角度
	float startAngle = currBullet->getRotation();
	float endAngle = 0;
	auto pVectr = currBullet->getPosition()-shootVector;
        float angleRadians=atan(pVectr.y/pVectr.x);
        float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
		
	if(shootVector.x - currBullet->getPosition().x<=0)//敌人在坐标,需要向左攻击
	{
	    startAngle = startAngle + abs(angleDegrees);//初始弓箭角度
	    endAngle = -90;//弓箭结束角度,向下,即插入地面
	    if(shootTag == 1)//轮到1号弓箭手
	    {
		currBullet->setPosition(Point(0,30));//子弹设置在弓箭手所在位置	
		shooter_1->setFlippedX(true);//X轴翻转,即面向左边
		if(shootVector.y - currBullet->getPosition().y<=0)
		{
		    //执行攻击动画,AnimationCache是自定义的动画类,会根据传入图片名生成帧动画
		    shooter_1->runAction(Animate::create(AnimationCache::getInstance()->getAnimation(temp1)));
		}else{
		    shooter_1->runAction(Animate::create(AnimationCache::getInstance()->getAnimation(temp2)));
		}
		    shootTag = 2;
		}
		    else//轮到2号弓箭手
		{
		    currBullet->setPosition(Point(10,30));		
		    shooter_2->setFlippedX(true);
		    if(shootVector.y - currBullet->getPosition().y<=0)
		    {
			shooter_2->runAction(Animate::create(AnimationCache::getInstance()->getAnimation(temp1)));
		    }else{
			shooter_2->runAction(Animate::create(AnimationCache::getInstance()->getAnimation(temp2)));
		    }
			shootTag = 1;
		    }
		}else//敌人在右边,其他同上
		{
		    startAngle = startAngle - abs(angleDegrees);
		    endAngle = 270;
		    if(shootTag == 1)
		    {
			currBullet->setPosition(Point(0,30));		
			shooter_1->setFlippedX(false);
			if(shootVector.y - currBullet->getPosition().y<=0)
			{
			    shooter_1->runAction(Animate::create(AnimationCache::getInstance()->getAnimation(temp1)));
			}else{
			    shooter_1->runAction(Animate::create(AnimationCache::getInstance()->getAnimation(temp2)));
			}
			    shootTag = 2;
			}
		    else
		    {
			currBullet->setPosition(Point(10,30));		
			shooter_2->setFlippedX(false);
			if(shootVector.y - currBullet->getPosition().y<=0)
			{
			    shooter_2->runAction(Animate::create(AnimationCache::getInstance()->getAnimation(temp1)));
			}else{
			    shooter_2->runAction(Animate::create(AnimationCache::getInstance()->getAnimation(temp2)));
			}
			    shootTag = 1;
			}
		}
		//贝叶斯弧线
		ccBezierConfig bezier;
		if(shootTag == 1)//播放射箭音效
		    SoundManager::playArrowShoot1();
		else
		    SoundManager::playArrowShoot2();
		//计算贝叶斯曲线的两个控制点
		bezier.controlPoint_1 = Point(currBullet->getPosition().x,currBullet->getPosition().y+200); 
		bezier.controlPoint_2 = Point(shootVector.x,shootVector.y+200);; 
		bezier.endPosition = shootVector;

		auto action = Spawn::create(BezierTo::create(0.5f, bezier),RotateTo::create(0.5f,endAngle),NULL);
		//攻击动画传递弓箭
		currBullet->setBulletAction(action);
		currBullet->shoot();
		currBullet = NULL;
	}
}
根据角度使用ccBezierConfig类来生成BezierTo移动动画,是一个弧线,具体内容百度的到

然后用Spwan将BezierTo与弓箭旋转动画合成为一个action,将action传递给子弹类,由子弹类具体执行,为何不在塔类中执行,将在子弹章节中讲解。

执行子弹类的shoot,攻击动画完成



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值