您的位置:首页 > 移动开发 > Cocos引擎

[Cocos2d塔防游戏开发]Cocos2dx-3.X完成塔防游戏《王国保卫战》--敌人(一)

2015-10-18 15:05 585 查看
该章节介绍如何制作敌人

首先根据可能出现的情况定义一个枚举类型,包括了敌人可能出现的所有状态,将在以后用到

typedef enum{
stateNone = 0, //无状态
stateWalkRight, //向右走走状态
stateWalkLeft, //向左走
stateWalkUp, //向上走
stateWalkDown, //向下走
stateAttackLeft,
stateAttackRight, //攻击
stateDeath,//死亡
stateFrozen
}MonsterState;


CC_SYNTHESIZE一些可能用到的属性,例如生命值、攻击力,此处略

生成敌人生命条,是一个ProgressTimer

void BaseMonster::createAndSetHpBar()
{
hpBgSprite = Sprite::createWithSpriteFrameName("lifebar_bg_small.png");

hpBgSprite->setPosition(Point(baseSprite->getContentSize().width / 2, baseSprite->getContentSize().height ));
baseSprite->addChild(hpBgSprite);

hpBar = ProgressTimer::create(Sprite::createWithSpriteFrameName("lifebar_small.png"));
hpBar->setType(ProgressTimer::Type::BAR);
hpBar->setMidpoint(Point(0, 0.5f));
hpBar->setBarChangeRate(Point(1, 0));
hpBar->setPercentage(hpPercentage);
hpBar->setPosition(Point(hpBgSprite->getContentSize().width / 2, hpBgSprite->getContentSize().height / 2 ));
hpBgSprite->addChild(hpBar);
}



因为是一个2.5D的游戏,我们必须设置敌人在Z轴的位置,防止在上面的敌人盖住了下面的敌人,确保下面的敌人盖住上面的敌人

我们将Y轴分为100层,根据敌人所处的Y轴的位置,设置Z轴,确保上面的敌人盖住下面的敌人

void BaseMonster::setMonsterZorder(int yOrder)
{
int hunder = (yOrder/100);
switch (hunder)
{
case(0):
this->setLocalZOrder(10);
break;
case(1):
this->setLocalZOrder(9);
break;
case(2):
this->setLocalZOrder(8);
break;
case(3):
this->setLocalZOrder(7);
break;
case(4):
this->setLocalZOrder(6);
break;
case(5):
this->setLocalZOrder(5);
break;
case(6):
this->setLocalZOrder(4);
break;
case(7):
this->setLocalZOrder(3);
break;
case(8):
this->setLocalZOrder(2);
break;
case(9):
this->setLocalZOrder(1);
break;
case(10):
this->setLocalZOrder(0);
break;
default:

break;
}
}


下面说说从生产敌人到敌人开始行走的步骤,以上图这种最简单的敌人为例:

首先在地图类的定时刷新敌人方法中(见地图类1)

auto thug = Thug::createMonster(path.at(monsterData->getRoad()).at(monsterData->getPath()));
addChild(thug);
GameManager::getInstance()->monsterVector.pushBack(thug);//讲敌人加入单例数组


会调用BaseMonster子类的createMonster函数,将从Plist读取的敌人行走路线点传给BaseMonster类,并且设置一些基本属性

Thug* Thug::createMonster(std::vector<Point> points)
{
auto monster = new Thug();
if (monster && monster->init())
{
monster->setPointsVector(points);
monster->setMaxHp(35);
monster->setCurrHp(35);
monster->setMoney(10);
monster->setForce(4);
monster->setArmor(0);
monster->setForce(8);
monster->setAttackBySoldier(true);//可以被士兵攻击
monster->setRunSpeed(40);//行走速度
monster->runNextPoint();
monster->autorelease();
return monster;
}
CC_SAFE_DELETE(monster);
return NULL;
}


在Init方法中我们会添加敌人静态图片精灵,并且通过scheduleUpdate设置定时器,不断调用update函数,在update函数中,我们根据敌人的状态更新图片和动画

void BaseMonster::update(float dt)
{
//若状态更新
if(lastState!=getState()){
//根据状态判断
switch (getState())
{
case(stateWalkRight):{
lastState = stateWalkRight;
//停止之前动画
stopMonsterAnimation();
baseSprite->setFlippedX(false);
auto action = RepeatForever::create(Animate::create(AnimationCache::getInstance()->getAnimation(getName()+"runright")));
action->setTag(stateWalkRight);
baseSprite->runAction(action);}
break;
case(stateWalkLeft):{
lastState = stateWalkLeft;
stopMonsterAnimation();
baseSprite->setFlippedX(true);
auto action = RepeatForever::create(Animate::create(AnimationCache::getInstance()->getAnimation(getName()+"runleft")));
action->setTag(stateWalkLeft);
baseSprite->runAction(action);}
break;
case(stateWalkUp):{
lastState = stateWalkUp;
stopMonsterAnimation();
baseSprite->setFlippedX(false);
auto action = RepeatForever::create(Animate::create(AnimationCache::getInstance()->getAnimation(getName()+"runup")));
action->setTag(stateWalkUp);
baseSprite->runAction(action);}
break;
case(stateWalkDown):{
lastState = stateWalkDown;
stopMonsterAnimation();
baseSprite->setFlippedX(false);
auto action = RepeatForever::create(Animate::create(AnimationCache::getInstance()->getAnimation(getName()+"rundown")));
action->setTag(stateWalkDown);
baseSprite->runAction(action);}
break;
case(stateAttackRight):{
//默认向右边攻击
lastState = stateAttackRight;
stopMonsterAnimation();
baseSprite->setFlippedX(false);
auto action = RepeatForever::create(Animate::create(AnimationCache::getInstance()->getAnimation(getName()+"attack")));
action->setTag(stateAttackRight);
baseSprite->runAction(action);}
break;
case(stateAttackLeft):{
lastState = stateAttackLeft;
stopMonsterAnimation();
baseSprite->setFlippedX(true);
auto action = RepeatForever::create(Animate::create(AnimationCache::getInstance()->getAnimation(getName()+"attack")));
action->setTag(stateAttackLeft);
baseSprite->runAction(action);}
break;
case(stateNone):{
lastState = stateNone;}
break;
case(stateFrozen):{
lastState = stateFrozen;}
break;
case(stateDeath):{
lastState = stateDeath;}
break;
}

}
}


最后通过nunNextPoint()方法让敌人开始行走

void BaseMonster::runNextPoint()
{
auto tempCurrPoint = currPoint();

baseSprite->setPosition(tempCurrPoint);

tempNextPoint = nextPoint();
setMonsterZorder(tempNextPoint.y);
if(fabs(tempNextPoint.y-tempCurrPoint.y)>5 && tempNextPoint.y > tempCurrPoint.y)//正在向上走
{
setState(stateWalkUp);
}else if(fabs(tempNextPoint.y-tempCurrPoint.y)>5 &&tempNextPoint.y <= tempCurrPoint.y)//正在向下走
{
setState(stateWalkDown);
}else if(tempNextPoint.x >= tempCurrPoint.x)//正在向右走
{
setState(stateWalkRight);
}
else if(tempNextPoint.x < tempCurrPoint.x)//正在向左走
{
setState(stateWalkLeft);
}
if( tempNextPoint!= tempCurrPoint ){

auto duration =  tempCurrPoint.getDistance(tempNextPoint) / getRunSpeed() ;

baseSprite->runAction(Sequence::create(MoveTo::create(duration, tempNextPoint)
, CallFuncN::create(CC_CALLBACK_0(BaseMonster::runNextPoint, this))
, NULL));
}else{
//走到终点
GameManager::getInstance()->LIFE --;
GameManager::getInstance()->monsterVector.eraseObject(this);
unscheduleAllCallbacks();
setCurrHp(0);
}
}
分析:

若tempNextPoint不等于tempCurrPoint,则表示还没有走到终点,根据下一个地点和目前所处的位置与速度,计算出所需时间,在这个时间结束后再次调用runNextPoiont函数,这样就使得敌人不断的行走,直到走到终点。期间根据下一个地点的位置,判断敌人是向左走、向右走、向上走,来更新敌人的动画。当走到终点后,从单例中清除。

这样就完成了最简单的敌人
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息