[Cocos2d塔防游戏开发]Cocos2dx-3.X完成塔防游戏《王国保卫战》--敌人(一)
2015-10-18 15:05
585 查看
该章节介绍如何制作敌人
首先根据可能出现的情况定义一个枚举类型,包括了敌人可能出现的所有状态,将在以后用到
CC_SYNTHESIZE一些可能用到的属性,例如生命值、攻击力,此处略
生成敌人生命条,是一个ProgressTimer
因为是一个2.5D的游戏,我们必须设置敌人在Z轴的位置,防止在上面的敌人盖住了下面的敌人,确保下面的敌人盖住上面的敌人
我们将Y轴分为100层,根据敌人所处的Y轴的位置,设置Z轴,确保上面的敌人盖住下面的敌人
下面说说从生产敌人到敌人开始行走的步骤,以上图这种最简单的敌人为例:
首先在地图类的定时刷新敌人方法中(见地图类1)
会调用BaseMonster子类的createMonster函数,将从Plist读取的敌人行走路线点传给BaseMonster类,并且设置一些基本属性
在Init方法中我们会添加敌人静态图片精灵,并且通过scheduleUpdate设置定时器,不断调用update函数,在update函数中,我们根据敌人的状态更新图片和动画
最后通过nunNextPoint()方法让敌人开始行走
若tempNextPoint不等于tempCurrPoint,则表示还没有走到终点,根据下一个地点和目前所处的位置与速度,计算出所需时间,在这个时间结束后再次调用runNextPoiont函数,这样就使得敌人不断的行走,直到走到终点。期间根据下一个地点的位置,判断敌人是向左走、向右走、向上走,来更新敌人的动画。当走到终点后,从单例中清除。
这样就完成了最简单的敌人
首先根据可能出现的情况定义一个枚举类型,包括了敌人可能出现的所有状态,将在以后用到
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函数,这样就使得敌人不断的行走,直到走到终点。期间根据下一个地点的位置,判断敌人是向左走、向右走、向上走,来更新敌人的动画。当走到终点后,从单例中清除。
这样就完成了最简单的敌人
相关文章推荐
- 我是运营,我没有假期
- 每个 Linux 游戏玩家都绝不想要的恼人体验
- 在 Fedora 上使用 Steam play 和 Proton 来玩 Windows 游戏
- Steam 让我们在 Linux 上玩 Windows 的游戏更加容易
- 如何使用 Steam Play 在 Linux 上玩仅限 Windows 的游戏
- 新一代iPad适配应用之游戏篇
- VB实现的《QQ美女找茬游戏》作弊器实例
- C#实现洗牌游戏实例
- C#实现的算24点游戏算法实例分析
- C#实现简单的井字游戏实例
- C++编写简单的打靶游戏
- Cocos2d-x中背景音乐和音效使用实例
- C++实现基于控制台界面的吃豆子游戏
- Cocos2d-x学习笔记之CCScene、CCLayer、CCSprite的默认坐标和默认锚点实验
- Cocos2d-x UI开发之CCControlPotentiometer控件类使用实例
- Cocos2d-x UI开发之文本类使用实例
- Cocos2d-x保存用户游戏数据之XML文件是否存在问题判断方法
- Cocos2d-x UI开发之菜单类使用实例
- Cocos2d-x UI开发之CCControlButton控件类实例
- Cocos2d-x学习笔记之世界坐标系、本地坐标系、opengl坐标系、屏幕坐标系