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

本节怪物及简单AI实现

一、怪物

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

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

相对玩家主要添加以下:

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

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

  1. void CMonster::Move(float delta)
  2. {
  3. if (isFloatZero(delta))
  4. {
  5. PlayAction(enAction::ACT_DEFAULT);
  6. if (m_pAIModule)
  7. {
  8. // 移动结束回调
  9. m_pAIModule->OnActionCallback();
  10. }
  11. }
  12. else
  13. {
  14. float fspeed = ; // px/fps
  15. float dx = delta;
  16. if (isFartherThan(dx, fspeed))
  17. {
  18. dx = dx > ? fspeed : -fspeed;
  19. }
  20. setPositionX(getPositionX() + dx);
  21. m_deltaX = delta - dx;
  22. PlayAction(ACT_RUN);
  23. // 设置当前的方向
  24. setScaleX(delta >? - : );
  25. }
  26. }
    // 攻击结束动作处理
          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时间后判断当前最优行动,并执行动作。

如下:

  1. void CAIModule::update(float dt)
  2. {
  3. m_nThinkTime += int(dt*);
  4. if (m_nThinkTime>THINKTIME)
  5. {
  6. if (CMonster* pMonster = dynamic_cast<CMonster*>(getParent()))
  7. {
  8. m_stepFunc = nullptr;
  9. if (CPlayer* pPlayer = CBattleMgr::getInstance()->GetPlayer())
  10. {
  11. if (m_pTarget)
  12. {
  13. m_pTarget->release();
  14. m_pTarget = nullptr;
  15. }
  16. m_pTarget = pPlayer;
  17. m_pTarget->retain();
  18.  
  19. m_nStep = ;
  20. m_nThinkTime = ;
  21. float dis = pMonster->getPosition().distance(pPlayer->getPosition());
  22. if (dis <)
  23. {
  24. m_stepFunc = std::bind(&CAIModule::Attack, this, std::placeholders::_1, std::placeholders::_2);
  25. Attack(pPlayer, m_nStep);
  26. //attack
  27. }
  28. else
  29. {
  30. m_stepFunc = std::bind(&CAIModule::Move2Node, this, std::placeholders::_1, std::placeholders::_2);
  31. Move2Node(pPlayer, m_nStep);
  32. //move to pos ;
  33. }
  34. }
  35. }
  36. }
  37. }

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

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

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

  1. void CAIModule::OnActionCallback()
  2. {
  3. if (m_stepFunc)
  4. {
  5. ++m_nStep;
  6. m_stepFunc(m_pTarget, m_nStep);
  7. }
  8. }

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

  1. #ifndef __CAIModule_H__
  2. #define __CAIModule_H__
  3. #include "IGameDef.h"
  4. #include "cocos2d.h"
  5. USING_NS_CC;
  6. class CAIModule : public Node
  7. {
  8. public:
  9. // implement the "static create()" method manually
  10. CREATE_FUNC(CAIModule);
  11.  
  12. virtual bool init();
  13.  
  14. void update(float dt);
  15.  
  16. void OnActionCallback();
  17. private:
  18.  
  19. void Attack(Node* pEnemy, int step);
  20.  
  21. void Move2Node(Node* pNode,int step);
  22.  
  23. CAIModule();
  24. ~CAIModule();
  25.  
  26. int m_nStep; // 当前操作的步骤数
  27. float m_nThinkTime; // 操作的间隔事件
  28.  
  29. Node* m_pTarget;
  30.  
  31. std::function<void(Node* node, int step)> m_stepFunc;
  32. };
  33.  
  34. #endif __CAIModule_H__
  35.  
  36. #include "AIModule.h"
  37. #include "Monster.h"
  38. #include "BattleMgr.h"
  39. #define THINKTIME (1000) // 决策时间
  40. CAIModule::CAIModule() :m_nThinkTime(THINKTIME), m_pTarget(nullptr), m_stepFunc(nullptr), m_nStep()
  41. {
  42. }
  43.  
  44. CAIModule::~CAIModule()
  45. {
  46. if (m_pTarget)
  47. {
  48. m_pTarget->release();
  49. m_pTarget = nullptr;
  50. }
  51. }
  52.  
  53. bool CAIModule::init()
  54. {
  55. scheduleUpdate();
  56. return true;
  57. }
  58.  
  59. void CAIModule::update(float dt)
  60. {
  61. m_nThinkTime += int(dt*);
  62. if (m_nThinkTime>THINKTIME)
  63. {
  64. if (CMonster* pMonster = dynamic_cast<CMonster*>(getParent()))
  65. {
  66. m_stepFunc = nullptr;
  67. if (CPlayer* pPlayer = CBattleMgr::getInstance()->GetPlayer())
  68. {
  69. if (m_pTarget)
  70. {
  71. m_pTarget->release();
  72. m_pTarget = nullptr;
  73. }
  74. m_pTarget = pPlayer;
  75. m_pTarget->retain();
  76.  
  77. m_nStep = ;
  78. m_nThinkTime = ;
  79. float dis = pMonster->getPosition().distance(pPlayer->getPosition());
  80. if (dis <)
  81. {
  82. m_stepFunc = std::bind(&CAIModule::Attack, this, std::placeholders::_1, std::placeholders::_2);
  83. Attack(pPlayer, m_nStep);
  84. //attack
  85. }
  86. else
  87. {
  88. m_stepFunc = std::bind(&CAIModule::Move2Node, this, std::placeholders::_1, std::placeholders::_2);
  89. Move2Node(pPlayer, m_nStep);
  90. //move to pos ;
  91. }
  92. }
  93. }
  94. }
  95. }
  96.  
  97. void CAIModule::Attack(Node* pEnemy, int step)
  98. {
  99. CMonster* pMonster = dynamic_cast<CMonster*>(getParent());
  100. if (!pMonster)
  101. {
  102. return;
  103. }
  104.  
  105. switch (step)
  106. {
  107. case :
  108. {
  109. if (!pEnemy)
  110. {
  111. return;
  112. }
  113. // 立即攻击
  114. if (isFartherThan(pMonster->getPositionX() < pEnemy->getPositionX(), ))
  115. {
  116. Attack(pEnemy,);
  117. }
  118. else
  119. {
  120. // 太近,移动远一点
  121. m_nStep =;
  122. Move2Node(pEnemy,);
  123. }
  124. }
  125. break;
  126. case :
  127. {
  128. if (!pEnemy)
  129. {
  130. return;
  131. }
  132. // 调整方向准备攻击
  133. pMonster->setScaleX(pMonster->getPositionX() < pEnemy->getPositionX() ? - : );
  134. ++m_nStep;
  135. std::function<void()> func = [this]()
  136. {
  137. Attack(nullptr,);
  138. };
  139. this->runAction(Sequence::create(DelayTime::create(0.3), CallFunc::create(func), NULL));
  140. }
  141. break;
  142. case :
  143. {
  144. // 直接攻击
  145. pMonster->Attack();
  146. }
  147. break;
  148. default:
  149. // m_nThinkTime = THINKTIME;
  150. break;
  151. }
  152. }
  153.  
  154. void CAIModule::Move2Node(Node* pNode, int step)
  155. {
  156. if (!pNode)
  157. {
  158. return;
  159. }
  160. CMonster* pMonster = dynamic_cast<CMonster*>(getParent());
  161. if (!pMonster)
  162. {
  163. return;
  164. }
  165.  
  166. switch (step)
  167. {
  168. case :
  169. {
  170. if (pMonster->getPositionX() < pNode->getPositionX())
  171. {
  172. pMonster->Move(pNode->getPositionX() - - pMonster->getPositionX());
  173. }
  174. else
  175. {
  176. pMonster->Move(pNode->getPositionX() + - pMonster->getPositionX());
  177. }
  178. }
  179. break;
  180. default:
  181. // m_nThinkTime = THINKTIME;
  182. break;
  183. }
  184. }
  185.  
  186. void CAIModule::OnActionCallback()
  187. {
  188. if (m_stepFunc)
  189. {
  190. ++m_nStep;
  191. m_stepFunc(m_pTarget, m_nStep);
  192. }
  193. }

附上实现后的效果图:

1、这是自动朝着玩家走

  

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

  

cocos2dx - 生成怪物及AI的更多相关文章

  1. 【cocos2d-x 手游研发----怪物智能AI】

    原创文章,转载请注明出处:http://www.cnblogs.com/zisou/p/cocos2d-xARPG4.html 谈到怪物AI,我觉得就比较话多了,首先理解一下(Artificial I ...

  2. Demo_塔防(自动生成怪物,导航,炮塔攻击,怪物掉血死忙)

    using UnityEngine; using System.Collections; public struct WaveMsg { //该波次生成的怪物 public GameObject mo ...

  3. Cocos2d-x 生成真正的随机数

    关于随机数 cocos2d-x 定义了一个宏 CCRANDOM_0_1 生成的是 [0, 1] 之间的值 因此,要生成  [0-100] 之间的数    CCRANDOM_0_1 * 100 生成 [ ...

  4. cocos2d-x生成随机数

            //获取系统时间         //time_t是long类型,精确到秒,通过time()函数可以获得当前时间和1970年1月1日零点时间的差         time_t tt; ...

  5. 随机生成文章的AI(C++)

    #include <iostream> #include <cstdlib> #include <ctime> #include <fstream> u ...

  6. cocos2dx - 伤害实现

    接上一节内容:cocos2dx - 生成怪物及AI 本节主要讲如何通过创建简单的矩形区域来造成伤害 在小游戏中简单的碰撞需求应用box2d等引擎会显得过于臃肿复杂,且功能不是根据需求定制,还要封装,为 ...

  7. 《MFC游戏开发》笔记九 游戏中的碰撞判定初步&怪物运动简单AI

    本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9374935 作者:七十一雾央 新浪微博:http:// ...

  8. 七夕节来啦!AI一键生成情诗,去发给你的女朋友吧!

    [摘要] Hello大家好,今天就是七夕节了,为了增进和女朋友之间的情感,我写了一个自动生成情诗的AI: 大家可以在ModelArts尝试复现模型,然后快去发给你们的女朋友吧- 大家好,我是b站up主 ...

  9. 【cocos2d-x 手游研发----地图活起来了】

    谈到地图不少人都说要做地图编辑器了,但是我暂时绕过这一步,如果不用寻路地图就不能移动?寻路就是会绕过障碍物的算法. 我做了一个简单的地图的思想,就是地图分层3层:背景层.可行区域层.遮罩层,但是地图就 ...

随机推荐

  1. 《Java程序设计》终极不改版【下】

    package 大学生信息管理系统; import java.awt.event.*; import javax.swing.*; import java.awt.*; import java.uti ...

  2. 【★】KMP算法完整教程

    KMP算法完整教程 全称:                               Knuth_Morris_Pratt Algorithm(KMP算法) 类型:                 ...

  3. html5 javascript 小型计算器

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  4. 5th-个人总结(Alpha阶段)

    一. 总结自己的Alpha过程 1.团队的整体情况 在团队中这次担任队长的职务. alpha阶段完成情况还算理想,大家都完成了指定的任务.但是也少不了犯错,一些需求没有划分的足够细致,后来功能完成后发 ...

  5. bean的单例

    通过改变中的scope属性,默认是singleton单例.而prototype则指定每getbean得到的都是不同实例. 验证代码: ①:验证默认singleton //验证<bean id=& ...

  6. 201521123106《java程序设计》第一周学习总结

    1.本章学习总结 认识了java语言,了解了java的历史,学习了各种java相关文件的使用,能够进行基本的程序操作,学会了使用博客.码云. 2.书面作业 1.为什么java程序可以跨平台运行?执行j ...

  7. Java多线程高并发学习笔记(二)——深入理解ReentrantLock与Condition

    锁的概念 从jdk发行1.5版本之后,在原来synchronize的基础上,增加了重入锁ReentrantLock. 本文就不介绍synchronize了,有兴趣的同学可以去了解一下,本文重点介绍Re ...

  8. Python爬虫1-----------placekitten 入门

    常用的urllib库有三个类:request,parse,error,request主要完成对url的请求,如proxy,opener,urlopen,parse主要完成对html的解析,error负 ...

  9. Intellij IDEA WEB结构目录说明【转载】

    https://my.oschina.net/lujianing/blog/186737?p=1#OSC_h2_1

  10. 解决在Ubuntu终端下使用cURL获取GBK格式的页面出现乱码问题

    问题描述 在Ubuntu下使用终端使用cURL去拿一个GBK的页面,发现返回来的内容里面中文都是乱码 解决方法 通过iconv来处理乱码拿到的内容,进行转码,示例如下: $curl http://ww ...