Cocos2d-x《雷電大戰》(6) 智能敵機AI來襲--飛行路徑演算法設計與實現(上),cocos2d

來源:互聯網
上載者:User

Cocos2d-x《雷電大戰》(6) 智能敵機AI來襲--飛行路徑演算法設計與實現(上),cocos2d

           林炳文Evankaka原創作品。轉載請註明出處http://blog.csdn.net/evankaka

       本文要實現飛機類遊戲中的一連串飛機的跟隨出和和並行出出。而網上找了一些Cocos2dx開發的飛行類遊戲,都只找到一些簡單的智能敵機。基本上沒什麼AI,這樣遊戲玩起來就太沒意思了。然後又去找敵機飛行路徑的相關資料,發現相關的也很少。想想還是自己來設計吧!

       飛機類遊戲設計中,智機的飛行路徑設計和智能子彈的設計絕對一個飛行類遊戲好壞是的核心。敵機智能也是分層級的。BOSS機就不說了,而飛行遊戲由於其特殊性,還經常有那種一連串一起出現的敵機。這種又可分為以下兩種:

跟隨:相同的位置,相同的飛行路徑,不同的啟動時間,一般是按時間間隔。

並飛:不同的位置,相同的運行路徑,相同的啟動時間。

效果如下:

   

跟隨,還未做碰撞判斷

 

並飛,還未做碰撞判斷

Cocos2d-x版本:3.4

工程環境:VS30213

一、跟隨飛行

        在跟隨飛行中,簡單一點的跟隨飛行路線就是直線了,比如從左至右,從一個角到另一個角。這種做法都比較簡單,沒什麼難度。實際遊戲開發中,也很少見這種的跟隨飛行,比較多的還是變化的曲線。而這種曲線一般都是貝賽爾曲線。飛機中不僅要飛行,還是進行即時的角度變化,這樣才更加類比真實的遊戲情境!

1.1  貝賽爾曲線簡介
       貝茲路徑是應用於二維圖形應用程式的數學曲線。曲線的定義有四個點:起始點、終止點(也稱錨點)以及兩個相互分離的中間點。滑動兩個中間點,貝茲路徑的形狀會發生變化 .

       P0、P1、P2、P3四個點在平面或在三維空間中定義了三次方貝茲曲線。曲線起始於P0走向P1,並從P2的方向來到P3。一般不會經過P1或P2;這兩個點只是在那裡提供方向資訊。P0和P1之間的間距,決定了曲線在轉而趨進P3之前,走向P2方向的“長度有多長”。


p0起點,p3是終點,p1,p2是控制點

1.2 遊戲應用
       我們可能需要在遊戲中類比飛彈或箭的移動軌跡,用才cocos2d-x下的bezier可以輕鬆的類比出來
cocos2d-x下為我們提供了兩個action BezierBy和BezierTo,使用也很簡單,只需要填充結構體:

//設定貝茲路徑參數ccBezierConfig tr0;tr0.endPosition = Vec2(0, 10);//終點tr0.controlPoint_1 = Vec2(250, 300);//控制點1tr0.controlPoint_2 = Vec2(180, 150);//控制點2ActionInterval* bezierForward = BezierTo::create(3.f, tr0);//建立啟動並執行貝茲路徑

我們只需要提供兩個控制點和一個終點位置就可以了,這裡要注意的是
CCBezier這個action是以當前位置為起始點的,兩個控制點和終點都是相對於起始點的位移值
如:tr0.endPosition = ccp(280,240); 是相對於起始點的位移

1.3 代碼

  這裡只是要驗證演算法,所以代碼還沒有單獨封裝成類,而且也還沒有將映像都打包成plist或用 SpriteBatchNode來最佳化記憶體。筆者打算把敵機飛行路徑和敵機子彈設計完成之後,再統一來最佳化記憶體!

在GameMain.h中添加一個定時器:

void enemyBuild1(float dt);//跟隨
然後就是GameMain.cpp的init()函數開啟定時,這裡設定每隔0.5

//每隔0.5S調用一次schedule(schedule_selector(GameMain::enemyBuild1), 0.5f);
最後就是實現了:

void GameMain::enemyBuild1(float dt){Size winSize = Director::getInstance()->getWinSize();auto spritePlane = Sprite::create("air3.png");spritePlane->setRotation(90);spritePlane->setPosition(Vec2(0,400));spritePlane->setScale(0.25);this->addChild(spritePlane);//設定貝茲路徑參數ccBezierConfig tr0;tr0.endPosition = Vec2(0, 10);//終點tr0.controlPoint_1 = Vec2(250, 300);//控制點1tr0.controlPoint_2 = Vec2(180, 150);//控制點2ActionInterval* bezierForward = BezierTo::create(3.f, tr0);//建立啟動並執行貝茲路徑ActionInterval *forwardBy = RotateBy::create(3.f,180);     // 第二個參數:如果是正數則是順時針,否則逆時針 Spawn* spawn = Spawn::create(bezierForward, forwardBy,NULL);//建立合成動作//飛機執行完動作後進行函數回調,調用移除飛機函數auto actionDone = CallFuncN::create(CC_CALLBACK_1(GameMain::enemyRemove, this));//連續動作Sequence* sequence = Sequence::create(spawn,actionDone, NULL);spritePlane->runAction(sequence);}
別看代碼少,裡面涉及到的內容不少呢!

其中刪除飛機的函數:

void GameMain::enemyRemove(Node* pNode){if (NULL == pNode) {return;}Sprite* plane = (Sprite*)pNode;this->removeChild(plane,true);}

要記得先在GameMain.h中定義

void enemyRemove(Node* pNode);

最後就是運行了,效果如下:



二、並飛飛行

       並飛就比簡單了,因為是相同的路徑方法。而且一般都不考慮到角度旋轉的問題。遊戲中最多出現的是左右並飛或者上下並飛。無非就是設定幾架飛機在一排線上,然後設定飛行路徑。最後執行就是了,下面直接來看看代碼吧,注釋很詳細,有需要的直接拿過去,很方便自己擴充,把映像名改下就好。要記得,這裡還未做記憶體最佳化,如果想做的話,有兩種方法。一種是映像做成plist,另一種是用 SpriteBatchNode來做。在這裡在,我推薦用前者,但是最好等遊戲全開發完了再來弄吧。

首先GameMain.h添加定時器:

void enemyBuild2(float dt);//並飛

開啟定時器:

    //每隔3S調用一次    schedule(schedule_selector(GameMain::enemyBuild2), 3.0f);

最後就是實現了:

void GameMain::enemyBuild2(float dt){Size winSize = Director::getInstance()->getWinSize();Point origin = Director::getInstance()->getVisibleOrigin();//產生精靈auto spritePlane1 = Sprite::create("air4.png");auto spritePlane2 = Sprite::create("air4.png");auto spritePlane3 = Sprite::create("air4.png");//得到精靈寬和高float height = spritePlane1->getContentSize().height;float width = spritePlane1->getContentSize().width;//旋轉的角度spritePlane1->setRotation(180);spritePlane2->setRotation(180);spritePlane3->setRotation(180);//設定縮放//spritePlane1->setScale(0.3);//spritePlane2->setScale(0.3);//spritePlane3->setScale(0.3);//設定位置spritePlane1->setPosition(Vec2(width, winSize.height + height));spritePlane2->setPosition(Vec2(winSize.width / 2, winSize.height - height));spritePlane3->setPosition(Vec2(winSize.width - width, winSize.height + height));//層中加入精靈this->addChild(spritePlane1);this->addChild(spritePlane2);this->addChild(spritePlane3);//計算飛行時間float flyVelocity =200;//運行速度,可以自己控制,每秒所走的像素float flyLen = winSize.height;float realFlyDuration = flyLen / flyVelocity;//實際飛行的時間//子彈啟動並執行距離和時間,從飛機處開始運行到螢幕底部auto actionMove1 = MoveBy::create(realFlyDuration, Point(0, -winSize.height - height));auto actionMove2 = MoveBy::create(realFlyDuration, Point(0, -winSize.height -height));auto actionMove3 = MoveBy::create(realFlyDuration, Point(0, -winSize.height - height));//子彈執行完動作後進行函數回調,調用移除子彈函數auto actionDone = CallFuncN::create(CC_CALLBACK_1(GameMain::enemyRemove, this));//連續動作Sequence* sequence1 = Sequence::create(actionMove1, actionDone, NULL);Sequence* sequence2 = Sequence::create(actionMove2, actionDone, NULL);Sequence* sequence3 = Sequence::create(actionMove3, actionDone, NULL);//飛機開始跑動spritePlane1->runAction(sequence1);spritePlane2->runAction(sequence2);spritePlane3->runAction(sequence3);}

來看看效果:



都還沒做碰撞檢測,可以看到。敵機按照我們的要求產生並運動了。

         這就是群飛飛機群的兩種方式,也可以將並飛和跟隨相結合。就可以產生很多種不同的飛機路徑。這在後頭我將會再來講解,今天就先到這裡了。敵機類最好是自己封裝,這裡還沒有實現。有需要的可以自己把函數改改就OK了!最後,再放張圖!

林炳文Evankaka原創作品。轉載請註明出處http://blog.csdn.net/evankaka

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.