Cocos2d-x《雷电大战》(6) 智能敌机AI来袭--飞行路径算法设计与实现(上)

转载 2015年04月22日 07:22:59
林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka

       本文要实现飞机类游戏中的一连串飞机的跟随出和和并行出出。而网上找了一些Cocos2dx开发的飞行类游戏,都只找到一些简单的智能敌机。基本上没什么AI,这样游戏玩起来就太没意思了。然后又去找敌机飞行路径的相关资料,发现相关的也很少。想想还是自己来设计吧!

       飞机类游戏设计中,智机的飞行路径设计和智能子弹的设计绝对一个飞行类游戏好坏是的核心。敌机智能也是分级别的。BOSS机就不说了,而飞行游戏由于其特殊性,还经常有那种一连串一起出现的敌机。这种又可分为以下两种:

跟随:相同的位置,相同的飞行路径,不同的启动时间,一般是按时间间隔。

并飞:不同的位置,相同的运行路径,相同的启动时间。

效果如下:

   

跟随,还未做碰撞判断

 

并飞,还未做碰撞判断

Cocos2d-x版本:3.4

工程环境:VS30213

一、跟随飞行

        在跟随飞行中,简单一点的跟随飞行路线就是直线了,比如从左到右,从一个角到另一个角。这种做法都比较简单,没什么难度。实际游戏开发中,也很少见这种的跟随飞行,比较多的还是变化的曲线。而这种曲线一般都是贝赛尔曲线。飞机中不仅要飞行,还是进行实时的角度变化,这样才更加模拟真实的游戏场景!

1.1  贝赛尔曲线简介
       贝塞尔曲线是应用于二维图形应用程序的数学曲线。曲线的定义有四个点:起始点、终止点(也称锚点)以及两个相互分离的中间点。滑动两个中间点,贝塞尔曲线的形状会发生变化 .

       P0P1P2P3四个点在平面或在三维空间中定义了三次方贝塞尔曲线。曲线起始于P0走向P1,并从P2的方向来到P3。一般不会经过P1P2;这两个点只是在那里提供方向资讯。P0P1之间的间距,决定了曲线在转而趋进P3之前,走向P2方向的“长度有多长”。


p0起点,p3是终点,p1,p2是控制点

1.2 游戏应用
       我们可能需要在游戏中模拟导弹或箭的移动轨迹,用才cocos2d-x下的bezier可以轻松的模拟出来
cocos2d-x下为我们提供了两个action BezierBy和BezierTo,使用也很简单,只需要填充结构体:

  1. //设置贝塞尔曲线参数  
  2. ccBezierConfig tr0;  
  3. tr0.endPosition = Vec2(0, 10);//终点  
  4. tr0.controlPoint_1 = Vec2(250, 300);//控制点1  
  5. tr0.controlPoint_2 = Vec2(180, 150);//控制点2  
  6. ActionInterval* bezierForward = BezierTo::create(3.f, tr0);//创建运行的贝塞尔曲线  

我们只需要提供两个控制点和一个终点位置就可以了,这里要注意的是
CCBezier这个action是以当前位置为起始点的,两个控制点和终点都是相对于起始点的偏移值
如:tr0.endPosition = ccp(280,240); 是相对于起始点的偏移

1.3 代码

  这里只是要验证算法,所以代码还没有单独封装成类,而且也还没有将图像都打包成plist或用 SpriteBatchNode来优化内存。笔者打算把敌机飞行路径和敌机子弹设计完成之后,再统一来优化内存!

在GameMain.h中添加一个定时器:

  1. void enemyBuild1(float dt);//跟随  
然后就是GameMain.cpp的init()函数打开定时,这里设置每隔0.5
  1. //每隔0.5S调用一次  
  2. schedule(schedule_selector(GameMain::enemyBuild1), 0.5f);  
最后就是实现了:
  1. void GameMain::enemyBuild1(float dt){  
  2.     Size winSize = Director::getInstance()->getWinSize();  
  3.     auto spritePlane = Sprite::create("air3.png");  
  4.     spritePlane->setRotation(90);  
  5.     spritePlane->setPosition(Vec2(0,400));  
  6.     spritePlane->setScale(0.25);  
  7.     this->addChild(spritePlane);  
  8.       
  9.     //设置贝塞尔曲线参数  
  10.     ccBezierConfig tr0;  
  11.     tr0.endPosition = Vec2(0, 10);//终点  
  12.     tr0.controlPoint_1 = Vec2(250, 300);//控制点1  
  13.     tr0.controlPoint_2 = Vec2(180, 150);//控制点2  
  14.   
  15.   
  16.     ActionInterval* bezierForward = BezierTo::create(3.f, tr0);//创建运行的贝塞尔曲线  
  17.     ActionInterval *forwardBy = RotateBy::create(3.f,180);     // 第二个参数:如果是正数则是顺时针,否则逆时针   
  18.     Spawn* spawn = Spawn::create(bezierForward, forwardBy,NULL);//创建合成动作  
  19.   
  20.     //飞机执行完动作后进行函数回调,调用移除飞机函数  
  21.     auto actionDone = CallFuncN::create(  
  22.         CC_CALLBACK_1(GameMain::enemyRemove, this));  
  23.   
  24.     //连续动作  
  25.     Sequence* sequence = Sequence::create(spawn,actionDone, NULL);  
  26.     spritePlane->runAction(sequence);  
  27.   
  28. }  
别看代码少,里面涉及到的内容不少呢!

其中删除飞机的函数:

  1. void GameMain::enemyRemove(Node* pNode){  
  2.     if (NULL == pNode) {  
  3.         return;  
  4.     }  
  5.     Sprite* plane = (Sprite*)pNode;  
  6.     this->removeChild(plane,true);  
  7. }  

要记得先在GameMain.h中定义
  1. void enemyRemove(Node* pNode);  

最后就是运行了,效果如下:



二、并飞飞行

       并飞就比简单了,因为是相同的路径方法。而且一般都不考虑到角度旋转的问题。游戏中最多出现的是左右并飞或者上下并飞。无非就是设置几架飞机在一排线上,然后设置飞行路径。最后执行就是了,下面直接来看看代码吧,注释很详细,有需要的直接拿过去,很方便自己扩展,把图像名改下就好。要记得,这里还未做内存优化,如果想做的话,有两种方法。一种是图像做成plist,另一种是用 SpriteBatchNode来做。在这里在,我推荐用前者,但是最好等游戏全开发完了再来弄吧。

首先GameMain.h添加定时器:

  1. void enemyBuild2(float dt);//并飞  

打开定时器:

  1. //每隔3S调用一次  
  2. schedule(schedule_selector(GameMain::enemyBuild2), 3.0f);  

最后就是实现了:
  1. void GameMain::enemyBuild2(float dt){  
  2.     Size winSize = Director::getInstance()->getWinSize();  
  3.     Point origin = Director::getInstance()->getVisibleOrigin();  
  4.   
  5.     //生成精灵  
  6.     auto spritePlane1 = Sprite::create("air4.png");  
  7.     auto spritePlane2 = Sprite::create("air4.png");  
  8.     auto spritePlane3 = Sprite::create("air4.png");  
  9.     //得到精灵宽和高  
  10.     float height = spritePlane1->getContentSize().height;  
  11.     float width = spritePlane1->getContentSize().width;  
  12.   
  13.     //旋转的角度  
  14.     spritePlane1->setRotation(180);  
  15.     spritePlane2->setRotation(180);  
  16.     spritePlane3->setRotation(180);  
  17.   
  18.     //设置缩放  
  19.     //spritePlane1->setScale(0.3);  
  20.     //spritePlane2->setScale(0.3);  
  21.     //spritePlane3->setScale(0.3);  
  22.   
  23.     //设置位置  
  24.     spritePlane1->setPosition(Vec2(width, winSize.height + height));  
  25.     spritePlane2->setPosition(Vec2(winSize.width / 2, winSize.height - height));  
  26.     spritePlane3->setPosition(Vec2(winSize.width - width, winSize.height + height));  
  27.   
  28.   
  29.     //层中加入精灵  
  30.     this->addChild(spritePlane1);  
  31.     this->addChild(spritePlane2);  
  32.     this->addChild(spritePlane3);  
  33.   
  34.     //计算飞行时间  
  35.     float flyVelocity =200;//运行速度,可以自己控制,每秒所走的像素  
  36.     float flyLen = winSize.height;  
  37.     float realFlyDuration = flyLen / flyVelocity;//实际飞行的时间  
  38.   
  39.     //子弹运行的距离和时间,从飞机处开始运行到屏幕底部  
  40.     auto actionMove1 = MoveBy::create(realFlyDuration, Point(0, -winSize.height - height));  
  41.     auto actionMove2 = MoveBy::create(realFlyDuration, Point(0, -winSize.height -height));  
  42.     auto actionMove3 = MoveBy::create(realFlyDuration, Point(0, -winSize.height - height));  
  43.   
  44.     //子弹执行完动作后进行函数回调,调用移除子弹函数  
  45.     auto actionDone = CallFuncN::create(  
  46.         CC_CALLBACK_1(GameMain::enemyRemove, this));  
  47.   
  48.     //连续动作  
  49.     Sequence* sequence1 = Sequence::create(actionMove1, actionDone, NULL);  
  50.     Sequence* sequence2 = Sequence::create(actionMove2, actionDone, NULL);  
  51.     Sequence* sequence3 = Sequence::create(actionMove3, actionDone, NULL);  
  52.   
  53.     //飞机开始跑动  
  54.     spritePlane1->runAction(sequence1);  
  55.     spritePlane2->runAction(sequence2);  
  56.     spritePlane3->runAction(sequence3);  
  57.   
  58. }  

来看看效果:



都还没做碰撞检测,可以看到。敌机按照我们的要求生成并运动了。

         这就是群飞飞机群的两种方式,也可以将并飞和跟随相结合。就可以生成很多种不同的飞机路径。这在后头我将会再来讲解,今天就先到这里了。敌机类最好是自己封装,这里还没有实现。有需要的可以自己把函数改改就OK了!最后,再放张图!

林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka

Cocos2d-x《雷电大战》(6) 智能敌机AI来袭--飞行路径算法设计与实现(下)

此文接上文Cocos2d-x《雷电大战》(6) 智能敌机AI来袭--飞行路径算法设计与实现(上) ,还是对游戏中的敌机路径进行一个设计和实现。这里笔者又实现了两种敌机路线。分别如下: (1)敌机朝着英...
  • Evankaka
  • Evankaka
  • 2015-05-01 18:03:37
  • 5356

Cocos2d-x《雷电大战》(6) 智能敌机AI来袭–飞行路径算法设计与实现(上)

好象掉了单例 算了与cocos2d-x也没关系 最后我加上消灭敌人算补偿? 有两种敌人会定期的循环出现,现个调试器实现 1 资源var res = { //... AIR3:'res/air3...
  • blackant2
  • blackant2
  • 2017-07-18 11:03:58
  • 307

Android 游戏雷电

  • 2012年10月09日 16:16
  • 291KB
  • 下载

[cocos2d-x] 打飞机子弹敌机碰撞检测

自己做了一个简单的打飞机游戏,比较粗糙,下面把子弹和敌人的产生,移动,碰撞的代码拿出来给大家参考参考...
  • u011784589
  • u011784589
  • 2013-10-17 10:58:21
  • 2831

智能寻路贪吃蛇 AI

  • 2014年02月04日 10:56
  • 1.78MB
  • 下载

人工智能--打飞机游戏

代码下载:Here。很久以前微信流行过一个小游戏:打飞机,这个游戏简单又无聊。在2017年来临之际,我就实现一个超级弱智的人工智能(AI),这货可以躲避从屏幕上方飞来的飞机。本帖只使用纯Python实...
  • wang2425559
  • wang2425559
  • 2017-12-09 17:10:16
  • 746

Cocos2d-x游戏《雷电大战》开源啦!要源码要资源快快来~~

写在前面的话:这是笔者开发的第二个小游戏《雷电大战》,之前就过这个游戏和《赵云要格斗》一样,最终将会开源。由于自己的一些个人原因。这个游戏还没有完成,但是许多网友都过来寻求代码或资源,本着开源的精神,...
  • Evankaka
  • Evankaka
  • 2016-01-23 13:42:25
  • 5894

Cocos2d-x《雷电大战》(3)-子弹无限发射

本文要实现雷电游戏中,游戏一开始,英雄飞机就无限发射子弹的功能。这里的思想是单独给子弹弄一个层,在这个层不设置一个定时器,每隔一个时间,根据当前英雄飞机传入的位置,生成子弹,并设置子弹的移动事件,和移...
  • Evankaka
  • Evankaka
  • 2015-03-15 16:50:10
  • 6261

java 仿雷电射击小游戏 java GUI、java Graphics、多线程

  • 2013年11月26日 23:21
  • 2.81MB
  • 下载

Cocos2d-x《雷电大战》(1)-双层地图无限滚动

本文要实现飞机射击游戏中的地图无限滚动的功能,这里分为两个层,一个层无限向下滚动,一个层无限向上滚动,这样子结合起来效果就非常有层次感,也非常逼真,这里我把地图层都写成一个类,自己把地图改下,就可以成...
  • Evankaka
  • Evankaka
  • 2015-02-27 21:08:52
  • 7004
收藏助手
不良信息举报
您举报文章:Cocos2d-x《雷电大战》(6) 智能敌机AI来袭--飞行路径算法设计与实现(上)
举报原因:
原因补充:

(最多只允许输入30个字)