[Cocos2d塔防游戏开发]Cocos2dx-3.X完成塔防游戏《王国保卫战》--防御塔(七)之士兵

该章节主要介绍兵营塔中的士兵

上一章讨论到兵营塔,兵营塔的关键在于士兵,士兵的一切动作,包括升级都在士兵类中完成,代码部分在Soilder文件夹中。

士兵的类型多种多样,不光兵营塔有士兵,法师塔与炮塔在升级到4级后均可以产生出一种士兵


typedef enum{
    SoldierStateNone = 0, //无状态
    SoldierStateRun,//行走
	SoldierStateHit, //攻击
	SoldierStateDeath,//死亡
	SoldierStateWait,//寻找敌人
	SoldierStateSkill1,
	SoldierStateSkill2
}SoldierState;

class BaseSoldier : public Sprite
{
public:
	CC_SYNTHESIZE(float, maxHp, MaxHp);
        CC_SYNTHESIZE(float, currHp, CurrHp);
	CC_SYNTHESIZE(float, force, Force);
	CC_SYNTHESIZE(float, armor, Armor);
	CC_SYNTHESIZE(float, hpPercentage, HpPercentage);
	CC_SYNTHESIZE(SoldierState, state, State);
        CC_SYNTHESIZE_READONLY(ProgressTimer*, hpBar, HpBar);
	CC_SYNTHESIZE(Point, location, Location);
	Sprite* baseSprite;
	virtual void runToLocation(Point point);
	virtual bool init();
	BaseMonster* nearestMonster;  
	virtual void updateSoldier(int level){};
protected:
	virtual void createAndSetHpBar();
	Sprite* hpBgSprite;
	virtual void lookingForMonsters(float dt);
	
	virtual void checkNearestMonster();
	virtual void attack();
	virtual void update(float dt){};
	
	virtual void runToDestination(Point destination,bool isAttacking){};
	SoldierState lastState;
	virtual void stopSoldierAnimation();
	void checkDirection(Point point);
	//false右边true左边
	virtual bool checkDirectionForMonster();
	float caculateTime(Point point);
	virtual void runToMonster();
	virtual void attackMonster(float dt){};
	int attackCount;//用于判断是否该释放技能了
};

士兵是一个自定义精灵,不同的士兵只是贴图不同,有的会根据attackCount攻击次数或者其他因素判断是否该释放技能

根据nearestMonster判断是否有敌人可以攻击,原理与防御塔相同,不同之处在于有一个走到敌人面前,并且与敌人搏斗的过程

当防御塔调用设置集结点方法后,调用每个士兵的runToLocation方法,使得士兵走到目的地,并且将状态设置成SoldierStateWait

最后添加一个定时器,相隔1秒调用lookingForMonsters检测附近敌人。

void BaseSoldier::runToLocation(Point point)
{
	if(getState()!=stateDeath){
		unscheduleAllCallbacks();
		scheduleUpdate();
		stopAllActions();
		if((point.x - this->getPositionX())>0){
			baseSprite->setFlippedX(false);//翻转,面向右边
		}else{
			baseSprite->setFlippedX(true);
		}
		setState(SoldierStateRun);
		runAction(Sequence::create(MoveTo::create(caculateTime(point),point),
			CallFuncN::create(CC_CALLBACK_0(BaseSoldier::setState, this,SoldierStateWait)),
			NULL));
		schedule(schedule_selector(BaseSoldier::lookingForMonsters), 1.0f,-1,caculateTime(point));
	}
}


当附近存在敌人并且敌人没有死亡,没有被其他士兵攻击(防止多个士兵攻击同一个敌人)时,将nearestMonster设置为该敌人,停止敌人动作,更改敌人状态为攻击,使得敌人执行攻击动画

if (monster->getAttackBySoldier() && distance < 50 && (!monster->getIsAttacking())) {
        nearestMonster = monster;
	nearestMonster->stopWalking();
	nearestMonster->setIsAttacking(true);
	break;
}
士兵的动画与敌人相同,都写在update(float dt)中,根据enum中的状态更新动画


若NearestMonster不为空,会执行attack,士兵会走到敌人面前,转身面向敌人,攻击(attackMonster(float dt)方法,dt可以看做是攻击速度,每隔dt敌人血量减少1次)

不同的士兵复写attackMonster方法,实行不同的攻击判断或者技能

如下

if(monsterCurrHp == 0){//若敌人死亡
	unschedule(schedule_selector(Assassin::attackMonster));
	nearestMonster->death();//更新敌人状态,执行四万动画
	if(this->getCurrHp()>0)
		runToLocation(location);//若士兵没死,走回地点
	}
	if(SoldierHp == 0){//若士兵死亡
		lastState = SoldierStateDeath;
		setState(SoldierStateDeath);//更新状态
		unscheduleAllCallbacks();//取消所有定时器
		stopAllActions();
		baseSprite->stopAllActions();//去下所有动画
		if(nearestMonster != NULL && nearestMonster->getCurrHp()>0){
			nearestMonster->restartWalking();//敌人胜利,敌人继续向前大步走
			nearestMonster->setIsAttacking(false);
		}
	baseSprite->runAction(Sequence::create//士兵死亡动画序列
		(CallFuncN::create(CC_CALLBACK_0(Assassin::setState, this,SoldierStateDeath))
		,Animate::create(AnimationCache::getInstance()->getAnimation("Assassin_dead"))
		,FadeOut::create(1.0f)
		,NULL));	
}

需要升级的士兵是基础士兵塔的士兵,即更新动画序列的frame中的图片前缀名即可

baseSprite->setSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName(String::createWithFormat("soldier_lvl%d_0001.png",level)->getCString()));

士兵原理上即一个可以行走的防御塔:可以让敌人停止行走-》让敌人执行攻击动画-》相隔一定时间两者同时掉血-》活下来的继续执行之前的动画

根据这个思路实现可以实现不同的士兵,仅仅是动画贴图不同,稍复杂的就是图中的坦克车,比普通士兵多一个导弹,相比士兵而言更像是防御塔而已



猜你喜欢

转载自blog.csdn.net/oShunz/article/details/49701985