转载

cocos2dx - 生成怪物及AI

本节怪物及简单AI实现

一、怪物

同 cocos2dx - v2.3.3编辑器骨骼动画  里创建的 CPlalyer 一样,新建一个 CMonster 类,也可以提出一个公共基类 IEntity ,为了以后扩展其他类型的实体做准备。

这里怪物还要有一个AI的实体类 CAIModule 类。

相对玩家主要添加以下:

 //init方法中添加如下          m_pAIModule = CAIModule::create();         this->addChild(m_pAIModule); 

同时对移动和攻击进行修改

 void CMonster::Move(float delta) {     if (isFloatZero(delta))     {         PlayAction(enAction::ACT_DEFAULT);         if (m_pAIModule)         {             // 移动结束回调             m_pAIModule->OnActionCallback();         }     }     else     {         float fspeed = 4; // px/fps         float dx = delta;         if (isFartherThan(dx, fspeed))         {             dx = dx > 0 ? fspeed : -fspeed;         }         setPositionX(getPositionX() + dx);         m_deltaX = delta - dx;         PlayAction(ACT_RUN);         // 设置当前的方向         setScaleX(delta >0? -1 : 1);     } } // 攻击结束动作处理       m_pAction->play("attack", false);       std::function<void()> func = [this](){       m_pAction->play("default", true);       m_nActType = ACT_DEFAULT;       if (m_pAIModule)       {           // 攻击结束回调            m_pAIModule->OnActionCallback();        }       };        m_pAction->setLastFrameCallFunc(func);    

以上主要在移动和攻击结束的时候调用了 AI模块的动作回调

二、AI模块

本节只是实现最简单的AI机制,直接将策略写在了update中,在间隔一个 THINKTIME 时间后判断当前最优行动,并执行动作。

如下:

 void CAIModule::update(float dt) {     m_nThinkTime += int(dt*1000);     if (m_nThinkTime>THINKTIME)     {         if (CMonster* pMonster = dynamic_cast<CMonster*>(getParent()))         {             m_stepFunc = nullptr;             if (CPlayer* pPlayer = CBattleMgr::getInstance()->GetPlayer())             {                 if (m_pTarget)                 {                     m_pTarget->release();                     m_pTarget = nullptr;                 }                 m_pTarget = pPlayer;                 m_pTarget->retain();                  m_nStep = 0;                 m_nThinkTime = 0;                 float dis = pMonster->getPosition().distance(pPlayer->getPosition());                 if (dis <200)                 {                     m_stepFunc = std::bind(&CAIModule::Attack, this, std::placeholders::_1, std::placeholders::_2);                     Attack(pPlayer, m_nStep);                     //attack                 }                 else                 {                     m_stepFunc = std::bind(&CAIModule::Move2Node, this, std::placeholders::_1, std::placeholders::_2);                     Move2Node(pPlayer, m_nStep);                     //move to pos ;                 }             }         }     } } 

以上直接设定AI执行对象为玩家,在距离小于200执行攻击,否则向玩家节点靠近移动。同时清楚当前 m_nThinkTime 时间,在下一个 决策时间 到来之前怪物会根据动作步骤持续执行当前动作。

所以这里也需要设置一下动作的当前 m_nStep 为0,同时设置一下执行的函数 m_stepFunc

为了能够在怪物攻击或者移动结束后 m_nStep 执行到下一步,实现了一个 OnActionCallback 函数。如下:

 void CAIModule::OnActionCallback() {     if (m_stepFunc)     {         ++m_nStep;         m_stepFunc(m_pTarget, m_nStep);     } } 

这样即可实现简单的AI移动效果,让拥有该AI对象的怪物,不断靠近玩家并且攻击玩家。CAIModule全代码如下:

  #ifndef __CAIModule_H__ #define __CAIModule_H__ #include "IGameDef.h" #include "cocos2d.h" USING_NS_CC; class CAIModule : public Node { public:     // implement the "static create()" method manually     CREATE_FUNC(CAIModule);      virtual bool init();      void update(float dt);          void OnActionCallback(); private:          void Attack(Node* pEnemy, int step);      void Move2Node(Node* pNode,int step);      CAIModule();     ~CAIModule();       int  m_nStep;            // 当前操作的步骤数     float m_nThinkTime;        // 操作的间隔事件      Node*        m_pTarget;      std::function<void(Node* node, int step)>   m_stepFunc; };   #endif __CAIModule_H__  #include "AIModule.h" #include "Monster.h" #include "BattleMgr.h" #define THINKTIME (1000) // 决策时间 CAIModule::CAIModule() :m_nThinkTime(THINKTIME), m_pTarget(nullptr), m_stepFunc(nullptr), m_nStep(0) { }   CAIModule::~CAIModule() {     if (m_pTarget)     {         m_pTarget->release();         m_pTarget = nullptr;     } }  bool CAIModule::init() {     scheduleUpdate();     return true; }  void CAIModule::update(float dt) {     m_nThinkTime += int(dt*1000);     if (m_nThinkTime>THINKTIME)     {         if (CMonster* pMonster = dynamic_cast<CMonster*>(getParent()))         {             m_stepFunc = nullptr;             if (CPlayer* pPlayer = CBattleMgr::getInstance()->GetPlayer())             {                 if (m_pTarget)                 {                     m_pTarget->release();                     m_pTarget = nullptr;                 }                 m_pTarget = pPlayer;                 m_pTarget->retain();                  m_nStep = 0;                 m_nThinkTime = 0;                 float dis = pMonster->getPosition().distance(pPlayer->getPosition());                 if (dis <200)                 {                     m_stepFunc = std::bind(&CAIModule::Attack, this, std::placeholders::_1, std::placeholders::_2);                     Attack(pPlayer, m_nStep);                     //attack                 }                 else                 {                     m_stepFunc = std::bind(&CAIModule::Move2Node, this, std::placeholders::_1, std::placeholders::_2);                     Move2Node(pPlayer, m_nStep);                     //move to pos ;                 }             }         }     } }  void CAIModule::Attack(Node* pEnemy, int step) {     CMonster* pMonster = dynamic_cast<CMonster*>(getParent());     if (!pMonster)     {         return;     }           switch (step)     {     case 0:     {          if (!pEnemy)         {             return;         }         // 立即攻击         if (isFartherThan(pMonster->getPositionX() < pEnemy->getPositionX(), 30))         {             Attack(pEnemy,1);         }         else         {             //  太近,移动远一点             m_nStep =1;             Move2Node(pEnemy,0);         }     }         break;     case 1:     {               if (!pEnemy)               {                   return;               }               // 调整方向准备攻击                pMonster->setScaleX(pMonster->getPositionX() < pEnemy->getPositionX() ? -1 : 1);               ++m_nStep;               std::function<void()> func = [this]()               {                   Attack(nullptr,2);               };               this->runAction(Sequence::create(DelayTime::create(0.3), CallFunc::create(func), NULL));     }         break;     case 2:     {          // 直接攻击          pMonster->Attack();     }         break;     default:     //    m_nThinkTime = THINKTIME;         break;     } }  void CAIModule::Move2Node(Node* pNode, int step) {     if (!pNode)     {         return;     }     CMonster* pMonster = dynamic_cast<CMonster*>(getParent());     if (!pMonster)     {         return;     }          switch (step)     {     case 0:         {             if (pMonster->getPositionX() < pNode->getPositionX())             {                 pMonster->Move(pNode->getPositionX() - 50 - pMonster->getPositionX());             }             else             {                 pMonster->Move(pNode->getPositionX() + 50 - pMonster->getPositionX());             }         }         break;     default:     //    m_nThinkTime = THINKTIME;         break;     } }   void CAIModule::OnActionCallback() {     if (m_stepFunc)     {         ++m_nStep;         m_stepFunc(m_pTarget, m_nStep);     } }  View Code

附上实现后的效果图:

1、这是自动朝着玩家走

cocos2dx - 生成怪物及AI

2、这是在靠近玩家后进行攻击

cocos2dx - 生成怪物及AI

正文到此结束
Loading...