zoukankan      html  css  js  c++  java
  • cocos2dx

    接上一节内容:cocos2dx - tmx地图分层移动处理

     本节怪物及简单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、这是自动朝着玩家走

      

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

      

  • 相关阅读:
    BZOJ-3211花神游历各国 并查集+树状数组
    HDU-1754I Hate It 线段树区间最值
    POJ-2777Count Color 线段树+位移
    BZOJ-1012[JSOI2008]最大数maxnumber 线段树区间最值
    HDU-1394 Minimum Inversion Number 线段树+逆序对
    HDU-1698 JUST A HOOK 线段树
    学习笔记 --- 线段树
    poj 2155 Matrix---树状数组套树状数组
    hdu 1166 敌兵布阵--BIT
    学习笔记 BIT(树状数组)
  • 原文地址:https://www.cnblogs.com/stratrail/p/5057745.html
Copyright © 2011-2022 走看看