cocos2dx3.2开发 RPG《Flighting》(十二)让怪物智能点——怪物仇恨值

一、前言
人工智能,这是一个很深奥的话题。我们这里的怪物也要智能一点,至少会自动找英雄来打吧。
二、正文
现在我才开始看怪物的头文件

class Monster : public Role{  
public:  
    Monster();  
    static Monster* create(const std::string& name,FlightLayer* layer);  
    void initMonster();  
      
    virtual Point getHpSliderPos();  
    void addHateValue(Role* sender,int HateValue);  
  
    void initWithMessage(const MonsterMessage& msg);  
private:  
    virtual void update(float dt);  
    void updateMonsterAttackTarget();  
    void initHateMap();  
    void refreshHateMap();  
    virtual void injured(int damage);  
    Role** getHatest();  
    bool cmpHate(const pair &x,const pair &y);  
private:  
    std::map hateMap;  
      
    bool debugMode;  
};  

```

同样,Monster也有一个initWithMessage方法来用MonsterMessage来初始化属性。

下面我们讲一讲如何实现关于怪物对英雄的仇恨值
在头文件里面,我们只需要关注一个成员变量
std::map hateMap;
键值就是攻击者的二级指针,值就是仇恨值

还有这几个函数。
1.initHateMap 初始化仇恨值map
void Monster::initHateMap(){  
    std::list temp = m_layer->getRolesArray();  
    for(auto it = temp.begin();it!=temp.end();++it){  
        if((**it)->getRoleType() == Role::ROLE_TYPE_HERO  
            || (**it)->getRoleType() == Role::ROLE_TYPE_NULL){  
                hateMap.insert(make_pair((*it),0));  
        }  
    }  
}  

```

也是通过m_layer获取全部的role,并且将是英雄的放进来

2.updateMonsterAttackTarget 在update函数中被调用
void Monster::updateMonsterAttackTarget(){  
    initHateMap();  
    refreshHateMap();  
    if(hateMap.size()==0){  
        return;  
    }  
    if(getHatest()){  
        this->setAttackTarget(getHatest());  
    }  
    if(m_attackTarget == nullptr){  
        int size = hateMap.size();  
  
        int randnum = rand()%size;  
        CCLOG("SIZE = %d,RAND = %d",size,randnum);  
        int i = 1;  
        map::iterator it;  
        for(it=hateMap.begin();it!=hateMap.end() && i < randnum;++it){  
            ++i;  
        }  
        this->setAttackTarget(it->first);  
        return;  
    }  
  
}  

```

大概就是获取仇恨值最高的(getHatest),设置为攻击目标,如果没有最高的,就随机找一个英雄

3.refreshHateMap
void Monster::refreshHateMap(){  
    for(auto HMit = hateMap.begin();HMit!= hateMap.end();){  
        if(*(*HMit).first == nullptr){  
            HMit = hateMap.erase(HMit);  
        }else{  
            ++HMit;  
        }  
    }  

```

将死了的英雄的仇恨值记录清理掉

4.getHateset
Role** Monster::getHatest(){  
    vector<pair> tempVec;  
    for(auto it = hateMap.begin();it!=hateMap.end();it++){  
        tempVec.push_back(*it);  
    }  
    sort(tempVec.begin(),tempVec.end(),std::bind(&Monster::cmpHate,this,std::placeholders::_1,std::placeholders::_2));  
    if((*tempVec.begin()).second == 0){  
        return nullptr;  
    }  
    Role** ret = (*tempVec.begin()).first;  
    return ret;  
}  

```

获取仇恨值最高的

5.addHateValue
void Monster::addHateValue(Role* sender,int HateValue){  
    auto tempIt = find_if(hateMap.begin(),hateMap.end(),=](const pair& x)->bool{   
        if(*x.first == sender){   
            return true;  
        }else{  
            return false;  
        }});  
    if(tempIt!=hateMap.end()){  
        (*tempIt).second += HateValue;  
    }  
}  

```


有没有发现一个问题?哪里来的仇恨值呢?哪里有调用过addHateValue?
这里我把仇恨值的添加放到子弹里面了,可以说,是一颗颗带着仇恨的子弹
void Bullet::update(float dt){  
    m_target = *m_targetPtr;  
    if(!m_target){  
        this->removeFromParentAndCleanup(true);  
        return;  
    }  
    if(!m_target->getBoundingBox().containsPoint(this->getPosition())){  
        float distance = ccpDistance(getPosition(),m_target->getPosition()+Vec2(0,m_target->getContentSize().height));  
        float t = distance / m_speed;  
        float speed_x = (m_target->getPositionX() - getPositionX()) / t;  
        float speed_y = (m_target->getPositionY()+ m_target->getContentSize().height/2 - getPositionY()) / t;  
        setPositionX(getPositionX() + speed_x);  
        setPositionY(getPositionY() + speed_y);  
    }else{  
        m_target->injured(m_effect,m_damage);  
        if(m_target->getRoleType()==Role::ROLE_TYPE_MONSTER){  
            Monster* m = dynamic_cast(m_target);  
            m->addHateValue(m_sender,m_HateValue);  
        }  
        this->removeFromParentAndCleanup(true);  
    }  
}  

```

新的子弹update函数,除了会触发目标的injured函数之外,如果目标是一个怪物的话,还会为调用其addHateValue()
现在真相大白了。
越攻击一个怪物,怪物对你的仇恨值就会越高,就会先攻击你。

好的,现在我们的怪物是不是有点智能了呢。

我的csdn地址:http://blog.csdn.net/hezijian22
邮箱地址:578690286@qq.com
如有问题或指教,欢迎与我交流,谢谢。