https://blog.csdn.net/zhanghefu/article/details/27588955

这一篇要为英雄创造一些小伙伴了,并且需要让机器人会巡逻,会偷懒,会行走,还会攻击英雄,当然也能受伤。其实机器人和英雄有一些共同的属性:攻击力、生命值和行走速度。但机器人是由电脑控制,状态是随机切换的,所以还需要指定巡逻区域、攻击区域、行走方向、决策时间等。

1. 添加机器人

首先更新BaseSprite类,添加攻击力和生命值属性,在BaseSprite.h中添加:

1

2

CC_SYNTHESIZE(unsigned int, m_hp, HP);

CC_SYNTHESIZE(unsigned int, m_attack, Attack);

创建Enemy类,代表敌方机器人,这里需要实现简单的AI,让机器人能自动思考,根据具体环境切换自己的状态:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

Enemy.h

typedef enum {

 AI_IDLE = 0,

 AI_PATROL,

 AI_ATTACK,

 AI_PURSUIT

}AiState;

class Enemy : public BaseSprite

{

public:

 Enemy();

 ~Enemy();

 bool init();

 CREATE_FUNC(Enemy);

 CC_SYNTHESIZE(cocos2d::Point, m_moveDirection, MoveDirection);

 CC_SYNTHESIZE(float, m_eyeArea, EyeArea);

 CC_SYNTHESIZE(float, m_attackArea, AttackArea)

 CC_SYNTHESIZE(AiState, m_aiState, AiState);

 void execute(const cocos2d::Point& target, float targetBodyWidth);

private:

 void decide(const cocos2d::Point& target, float targetBodyWidth);

 unsigned int m_nextDecisionTime;

};

AiState表示机器人的四种状态:休闲、巡逻、攻击、跟随。机器人还有几个变量,分别表示:行走方向、巡逻范围、攻击范围、当前AI状态。
m_nextDecisionTime表示机器人距离下一次决策的时间,execute函数是在GameLayer.cpp中update函数调用的,定期执行更新机器人状态。decide函数实现机器人怎么决策,是机器人的内心世界。
这里重点分析机器人AI该怎么实现,因为只是一个demo,所以就尽可能的简单些吧。首先机器人需要根据自己的朝向和英雄的位置来思考,如果机器人背对着英雄或者英雄处于机器人巡逻范围之外,那么此时机器人是看不到英雄的,机器人就会随机的选择继续巡逻或者站着偷懒。如果英雄在机器人的巡逻范围内,且被机器人看到了,则机器人需要判断英雄是否处于自己的攻击范围,来决策是攻击还是追过去。每种状态下的思考时间最好设置成随机的,这样更真实。看源码实现:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

Enemy.cpp

Enemy::Enemy():

 m_nextDecisionTime(0)

{}

 

Enemy::~Enemy()

{}

 

bool Enemy::init()

{

 bool ret = false;

 do {

  this->initWithSpriteFrameName("robot_idle_00.png");

  Animation *pIdleAnim = this->createAnimation("robot_idle_%02d.png", 5, 12);

  this->setIdleAction(RepeatForever::create(Animate::create(pIdleAnim)));

  Animation *pWalkAnim = this->createAnimation("robot_walk_%02d.png", 6, 12);

  this->setWalkAction(RepeatForever::create(Animate::create(pWalkAnim)));

 

  Animation *pAttackAnim = this->createAnimation("robot_attack_%02d.png", 5, 20);

  this->setAttackAction(Sequence::create(Animate::create(pAttackAnim), BaseSprite::createIdleCallbackFunc(), NULL));

  Animation *pHurtAnim = this->createAnimation("robot_hurt_%02d.png", 3, 20);

  this->setHurtAction(Sequence::create(Animate::create(pHurtAnim), BaseSprite::createIdleCallbackFunc(), NULL));

  Animation *pDeadAnim = this->createAnimation("robot_knockout_%02d.png", 5, 12);

  this->setDeadAction(Sequence::create(Animate::create(pDeadAnim), Blink::create(3, 9), NULL));

  ret = true;

 while(0);

 return ret;

}

 

void Enemy::execute(const Point& target, float targetBodyWidth)

{

 if(m_nextDecisionTime == 0)

 {

  this->decide(target, targetBodyWidth);

 }else {

  -- m_nextDecisionTime;

 }

}

 

void Enemy::decide(const Point& target, float targetBodyWidth)

{

 Point location = this->getPosition();

 float distance = location.getDistance(target);

 distance = distance - (targetBodyWidth / 2 + this->getDisplayFrame()->getRect().size.width / 2) + 30;

 //log("distance=%f, m_fVelocity=%f", distance, m_fVelocity);

 bool isFlippedX = this->isFlippedX();

 bool isOnTargetLeft = (location.x < target.x ? true false);

 if((isFlippedX && isOnTargetLeft) || (!isFlippedX && !isOnTargetLeft)) {

  this->m_aiState = CCRANDOM_0_1() > 0.5f ? AI_PATROL : AI_IDLE;

 }else {

  if(distance < m_eyeArea)

  {

   this->m_aiState = distance < m_attackArea ? AI_ATTACK : AI_PURSUIT;

  }else {

   this->m_aiState = CCRANDOM_0_1() > 0.5f ? AI_PATROL : AI_IDLE;

  }

 }

 switch(m_aiState)

 {

 case AI_ATTACK:

  {

   this->runAttackAction();

   this->attack();

   this->m_nextDecisionTime = 50;

  }

  break;

 case AI_IDLE:

  {

   this->runIdleAction();

   this->m_nextDecisionTime = CCRANDOM_0_1() * 100;

  }

  break;

 case AI_PATROL:

  {

   this->runWalkAction();

   this->m_moveDirection.x = CCRANDOM_MINUS1_1();

   this->m_moveDirection.y = CCRANDOM_MINUS1_1();

   m_moveDirection.x = m_moveDirection.x > 0 ? (m_moveDirection.x + m_fVelocity.x) : (m_moveDirection.x - m_fVelocity.x);

   m_moveDirection.y = m_moveDirection.y > 0 ? (m_moveDirection.y + m_fVelocity.y) : (m_moveDirection.y - m_fVelocity.y);

   this->m_nextDecisionTime = CCRANDOM_0_1() * 100;

  }

  break;

 case AI_PURSUIT:

  {

   this->runWalkAction();

   //v.normalize() function return the unit vector of v

   this->m_moveDirection = (target - location).normalize();

   this->setFlippedX(m_moveDirection.x < 0 ? true false);

   m_moveDirection.x = m_moveDirection.x > 0 ? (m_moveDirection.x + m_fVelocity.x) : (m_moveDirection.x - m_fVelocity.x);

   m_moveDirection.y = m_moveDirection.y > 0 ? (m_moveDirection.y + m_fVelocity.y) : (m_moveDirection.y - m_fVelocity.y);

   this->m_nextDecisionTime = 10;

  }

  break;

 }

}

当机器人思考接下来该做什么时,就会执行相应的操作和动画。
机器人创造完成了,现在把它添加到游戏中去,修改GameLayer.h,添加下面的代码:

1

2

3

4

5

6

7

#define MIN_ENEMY_COUNT 5

 

 void updateEnemies(float dt);

 void addEnemy();

 void onEnemyAttack(BaseSprite *pSprite);

 

 cocos2d::Array *m_pEnemies;

updateEnemies表示每一次循环都会更新每个机器人的状态,onEnemyAttack是机器人攻击英雄时执行的函数,暂时不实现。m_pEnemies为保存机器人的容器。
修改GameLayer.cpp,添加下面的函数:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

void GameLayer::addEnemy()

{

 Size winSize = Director::getInstance()->getWinSize();

 Point location = Point::ZERO;

 Enemy *pEnemy = Enemy::create();

 //log("m_pTiledMap->getMapSize() mapSize=%f", m_pTiledMap->getMapSize().width);

 float halfEnemyFrameHeight = (pEnemy->getDisplayFrame()->getRect().size.height) / 2;

 float heroPosX = m_pHero->getPositionX();

 float halfWinWidth = (winSize.width / 2);

 while(fabsf(heroPosX - location.x) < 150)

 {

  if(heroPosX < halfWinWidth)

  {

   location.x = m_pHero->getPositionX() + CCRANDOM_0_1() * halfWinWidth;

  }else if(heroPosX > (m_pTiledMap->getMapSize().width * m_fTileWidth - halfWinWidth)) {

   location.x = m_pHero->getPositionX() - CCRANDOM_0_1() * halfWinWidth;

  }else {

   location.x = m_pHero->getPositionX() + CCRANDOM_MINUS1_1() * halfWinWidth;

  }

 }

 float maxY = m_fTileHeight * 3 + halfEnemyFrameHeight;

 location.y = CCRANDOM_0_1() * maxY;

 if(location.y < halfEnemyFrameHeight)

 {

  location.y = halfEnemyFrameHeight;

 }

 pEnemy->attack = CC_CALLBACK_0(GameLayer::onEnemyAttack, this, pEnemy);

 pEnemy->setPosition(m_origin + location);

 pEnemy->setZOrder(m_fScreenHeight - pEnemy->getPositionY());

 pEnemy->runIdleAction();

 pEnemy->setAttack(5);

 pEnemy->setHP(30);

 pEnemy->setVelocity(Point(0.5f, 0.5f));

 pEnemy->setEyeArea(200);

 pEnemy->setAttackArea(25);

 m_pEnemies->addObject(pEnemy);

 m_pSpriteNodes->addChild(pEnemy);

}

 

void GameLayer::updateEnemies(float dt) {

    Object *pObj = NULL;

 Point distance = Point::ZERO;

 

 Point heroLocation = m_pHero->getPosition();

 Array *pRemovedEnemies = Array::create();

    CCARRAY_FOREACH(m_pEnemies, pObj)

 {

  Enemy *pEnemy = (Enemy*)pObj;

  pEnemy->execute(heroLocation, m_pHero->getDisplayFrame()->getRect().size.width);

  if(pEnemy->getCurrActionState() == ACTION_STATE_WALK)

  {

   Point location = pEnemy->getPosition();

   Point direction = pEnemy->getMoveDirection();

 

   Point expect = location + direction;

   float halfEnemyFrameHeight = (pEnemy->getDisplayFrame()->getRect().size.height) / 2;

   if(expect.y < halfEnemyFrameHeight || expect.y > (m_fTileHeight * 3 + halfEnemyFrameHeight) )

   {

    direction.y = 0;

   }

   pEnemy->setFlippedX(direction.x < 0 ? true false);

   pEnemy->setPosition(location + direction);

   pEnemy->setZOrder(pEnemy->getPositionY());

  }

 }

 CCARRAY_FOREACH(pRemovedEnemies, pObj)

 {

  Enemy *pEnemy = (Enemy*)pObj;

  m_pEnemies->removeObject(pEnemy);

  m_pSpriteNodes->removeChild(pEnemy, true);

 }

 pRemovedEnemies->removeAllObjects();

}

 

void GameLayer::onEnemyAttack(BaseSprite *pSprite)

{

}

在GameLayer.cpp的update函数中添加:

1

this->updateEnemies(dt);

在init函数中添加:

1

2

3

4

5

6

m_pEnemies = Array::createWithCapacity(MIN_ENEMY_COUNT);

 m_pEnemies->retain();

 for(int i = 0; i < MIN_ENEMY_COUNT; ++ i)

 {

  this->addEnemy();

 }

OK,现在编译运行项目,就可以看到屏幕上有5个机器人追着英雄打了,效果如下图:


目前机器人和英雄都没有攻击效果,都是无敌状态,不过他们好日子快到头了,下一篇我们就来让他们接受现实的残酷吧。

cocos2d-x横版格斗游戏教程3相关推荐

  1. cocos2d-x横版格斗游戏教程4

    上一篇我们已经可以看到英雄和机器人都处于无敌状态,现在让他们互相残杀吧,所以接下来将要实现碰撞检测功能.先来看看下面这张图: 这里碰撞检测采用比较简单的矩形,可以看到英雄和机器人在攻击的时候会把拳头伸 ...

  2. cocos2d-x横版格斗游戏教程1

    转载:https://blog.csdn.net/zhanghefu/article/details/27586421 马上就要放假回家了,最近几天也比较闲,所以抽空来学习一下cocos2d-x 3. ...

  3. cocos2d-x 3 0 制作横版格斗游戏

    转自:http://philon.cn/post/cocos2d-x-3.0-zhi-zuo-heng-ban-ge-dou-you-xi cocos2d-x: v3.0-alpha-pre Wind ...

  4. Cocos2d-x 3.0 制作横版格斗游戏2

    转载:https://blog.csdn.net/bridge001/article/details/18882575 git:https://github.com/pj2933/fight2d co ...

  5. cocos2d-x 3.0 制作横版格斗游戏

    cocos2d-x: v3.0-alpha-pre Windows环境: Windows8 + Visual Studio 2012 Linux环境: Ubuntu12.04 + gcc 4.7.2 ...

  6. Beat #39;Em Up Game Starter Kit (横版格斗游戏) cocos2d-x游戏源代码

    浓缩精华.专注战斗! 游戏的本质是什么?界面?养成?NoNo!    游戏来源于对实战和比赛的模拟,所以它的本源就是对抗.就是战斗! 是挥洒热血的一种方式! 一个游戏最复杂最难做的是什么?UI?商城? ...

  7. Beat 'Em Up Game Starter Kit (横版格斗游戏) cocos2d-x游戏源码

    浓缩精华,专注战斗!    游戏的本质是什么?界面?养成?NoNo!    游戏来源于对实战和比赛的模拟,所以它的本源就是对抗!就是战斗!是挥洒热血的一种方式!    一个游戏最复杂最难做的是什么?U ...

  8. java 横版游戏开发_用MyEclipse的Java Project开发仿DNF横版格斗游戏

    这些天,我正在用MyEclipse的Java Project开发一款仿DNF 横版格斗游戏. http://v.youku.com/v_show/id_XMTI5MTE0NDg4MA==.html 这 ...

  9. 横版java_Project4 自己用java写的横版格斗游戏 功能还不是很复杂 可以作为参考~ Other Games 其他 238万源代码下载- www.pudn.com...

    文件名称: Project4下载 收藏√  [ 5  4  3  2  1 ] 开发工具: Java 文件大小: 5963 KB 上传时间: 2013-07-17 下载次数: 4 提 供 者: lyk ...

最新文章

  1. 《R语言游戏数据分析与挖掘》一导读
  2. 几个经典的TCP通信函数
  3. 13.PHP_ThinkPHP
  4. js 默认的参数、可变的参数、变量作用域
  5. matlab 中的dir函数使用
  6. C语言文件读写(5)-文件位置相关
  7. C#中Bitmap类实现对图像操作的一些方法(转)
  8. TransactionScrope 2
  9. 网站点赞 评论 回复 数据库设计
  10. 用python做数学题_「文山玩Python做测试」用python做算术题,很简单
  11. 利用FGSM实现对抗样本攻击
  12. ae去闪插件deflicker使用_AE去闪烁插件|RevisionFX DEFlicker(AE视频去闪烁插件) V1.4.12 官方版 下载_当下软件园_软件下载...
  13. GameFi市值飙升,详解N.Fans目前的发展现状以及未来前景
  14. 关于绩效考核及绩效面谈
  15. Photoshop设置图片的背景色为透明
  16. 2015年4月21日---开始写自己的专业博客啦
  17. html 调用es2015模块,在浏览器中懒加载ES2015模块
  18. python实现word文档合并
  19. 无人机编队飞行技术 pdf_无人机教师李刚:无人机飞行中最重要的六个要点
  20. 戴尔笔记本提示“您已插入低瓦数电源适配器 在bios设置中可以禁用此警告”

热门文章

  1. 夫妻分居期间一方的债务应该如何处理?
  2. 芯片后端开发基础知识(一)
  3. 二进制转十进制速记方法
  4. 《儿童教育心理学》读书笔记
  5. 掌握14种UML图,清晰图示
  6. 打开计算机网络自动连接,怎么让电脑一开机就自动连接到自己的wifi
  7. 干货|APP开发的需求分析步骤
  8. Go语言自学系列 | golang中的if else语句
  9. java我的世界1.7.2怎么下载模组_我的世界龙骑士mod下载1.7.2 完美版【附安装使用教程】下载...
  10. 关于新博弈论与新系统论的胡思乱想