當前位置:遊戲中心平台 - 遊戲盒子 - 如何實現基於cocos2dx3.x的A星尋路算法

如何實現基於cocos2dx3.x的A星尋路算法

在學習本教程之前,如果妳有開發COCOS2D-X的經驗會有所幫助,如果沒有也沒關系,因為妳可以把這裏講解的例子移植到其他語言或者框架上。找到到達鍵盤的最短路徑並開始!迷宮貓首先介紹我們將在本教程中開發的簡單遊戲。請下載本教程的工程代碼。編譯並運行項目,您將看到下圖。在這個遊戲中,妳扮演壹個偷貓賊,在由危險的狗守衛的地牢中小心翼翼地行走。如果妳試圖和壹只狗雜交,它會吃了妳——除非妳能用骨頭賄賂它!所以在這個遊戲中,妳的任務就是盡量按照正確的順序撿起骨頭,然後通過狗找到逃跑的方法。註意,貓只能水平或垂直移動(比如不能斜向移動),會從壹個方塊的中心點移動到另壹個方塊。每個方塊可以是可通行的,也可以是不可通行的。試試這個遊戲,看看妳是否能找到出路!我建議妳閱讀代碼來熟悉它的原理。這是壹個相當常見的正方形地圖遊戲,我們將在下壹個教程中修改它,並使用A-star尋路算法。迷宮貓和壹顆星星概述正如妳所看到的,當妳點擊地圖上的某個地方,貓就會跳到妳點擊方向的相鄰方塊。我們想修改程序,讓貓可以壹直朝著妳點擊的方塊方向移動,就像很多RPG或者點擊式冒險遊戲壹樣。讓我們來看看控制觸摸事件的代碼是如何工作的。如果打開HelloWorldScene.cpp文件,會看到觸摸操作是這樣實現的:AutoListener = EventListenerTouchoneByone::Create();監聽器-& gt;setswallowcutches(true);監聽器-& gt;ontouchbegin =[this](Touch * Touch,Event * Event){ if(_ game over){ return false;} PointtouchLocation = _ tile map-& gt;convertTouchToNodeSpace(觸摸);_ cat-& gt;move forward(touch location);returntrue};_ event dispatcher-& gt;addEventListenerWithSceneGraphPriority(監聽器,this);妳可以看到這只是在貓精靈上調用的壹個方法,讓貓移動到妳點擊方塊地圖的地方。我們現在要做的是修改CatSprite.m文件中的以下方法,找到到這個點的最短路徑,開始前進:void catsprite::Move against(const point & amp;Target) {}創建ShortestPathStep類我們開始創建壹個內部類,它表示路徑上的壹個步驟。在這種情況下,它是壹個正方形和由A-star算法計算的F、G和Hscores。classShortestPathStep:public cocos 2d::Object { public:ShortestPathStep();~ ShortestPathStep();staticShortestPathStep * createWithPosition(const cocos 2d::Point & amp;pos);boolinitWithPosition(constcocos 2d::Point & amp;pos);intgetFScore()常量;boolisEqual(constShortestPathStep * other)const;STD::stringgetDescription()const;CC _ synthese(cocos2d::Point,_position,Position);CC _ synthese(int,_gScore,GS core);CC _ synthese(int,_hScore,hs core);CC _ synthese(ShortestPathStep *,_parent,Parent);};現在,將以下代碼添加到CatSprite.cpp文件的頂部。cat sprite::ShortestPathStep::ShortestPathStep():_ position(Point::ZERO)、_gScore(0)、_ parent(nullptr){ } cat sprite::ShortestPathStep::~ ShortestPathStep(){ } cat sprite::ShortestPathStep * cat sprite::ShortestPathStep::createWithPosition(const Point & amp;pos){ ShortestPathStep * pRet = newShortestPathStep();if(pRet & amp;& amppRet->;initWithPosition(pos)){ pRet-& gt;autorelease();returnpRet} else { CC _ SAFE _ DELETE(pRet);returnnullptr} } boolCatSprite::ShortestPathStep::initWithPosition(const point & amp;pos){ boolbRet = false;執行{ this-& gt;設定位置;bRet = true} while(0);returnbRet} intCatSprite::ShortestPathStep::getFScore()const { return this-& gt;getGScore()+this-& gt;geth score();} boolCatSprite::ShortestPathStep::is equal(constcastsprite::ShortestPathStep * other)const { return this-& gt;getPosition()= =其他-& gt;getPosition();} STD::stringCatSprite::ShortestPathStep::get description()const { returnStringUtils::format(" pos =[% . 0f;%.0f]g=%dh=%df=%d ",this-& gt;getPosition()。x,這-& gt;getPosition()。y,這-& gt;getGScore(),this-& gt;getHScore(),this-& gt;getfs core());}妳可以看到,這是壹個非常簡單的類,它記錄了以下內容:-方塊的坐標-G值(記住,這是從起點到當前點的方塊數)-H值(記住,這是從當前點到目標點的估計方塊數)-Parent是它之前的運算-F值,這是平方和(它是G+H的值)。這裏定義了getDescription方法。創建isEquals方法,當且僅當兩個ShortestPathSteps的盒子坐標相同時,它們相等(例如,它們表示同壹個盒子)。創建開放和封閉列表,打開CatSprite.h文件,添加以下代碼:cocos2d::Vector _ spOpenSteps;cocos2d::Vector _ spClosedSteps;檢查起點和終點重新實現move against方法,得到當前盒子坐標和目標盒子坐標,然後檢查是否需要計算路徑,最後測試目標盒子坐標是否可走(這裏只有墻不可走)。打開CatSprite.cpp文件,修改movetower方法如下:Voidcastsprite::move tower(const point & amp;target){ PointfromTileCoord = _ layer-& gt;tileCoordForPosition(this-& gt;getPosition());PointtoTileCoord = _ layer-& gt;tileCoordForPosition(目標);if(fromTileCoord = = toilecoord){ cc log(" You ' reallyreadythere!:P”);返回;}如果(!_ layer-& gt;isvalidilecord(toTileCoord)| | _ layer-& gt;isWallAtTileCoord(toilecoord)){ simple audio engine::getInstance()-& gt;playEffect(" hit wall . wav ");返回;} CCLOG("From:%f,%f ",fromTileCoord.x,fromtilecoord . y);CCLOG("To:%f,%f ",toTileCoord.x,totelecoord . y);}編譯運行,點擊地圖。如果不點擊墻壁,可以在控制臺上看到以下信息:from: 24.000000,0.000000 to: 20.000000,0.00000其中**From**是貓的盒子坐標,**To**是點擊的盒子坐標。根據算法,第壹步是將當前坐標添加到開放列表中。還需要三個輔助方法:-壹個方法用於將ShortestPathStep對象插入適當的位置(有序的F值)-壹個方法用於計算從壹個正方形到相鄰正方形的移動值-壹個方法是通過根據曼哈頓距離算法計算正方形的H值來打開CatSprite.cpp文件。添加以下方法:Voidcatsprite::insertionsteps(cat sprite::shorttestpathstep * step){ intstepscore = step-> getfs core();ssize _ tcount = _ spopensteps . size();ssize _ ti = 0;for(;igetFScore()){ break;} } _spOpenSteps.insert(i,step);} intCatSprite::computehscorefromcoordtocord(const point & amp;fromCoord,constPoint & ampto code){//忽略路上可能出現的各種障礙物。將ABS(返回坐標。x-來自坐標。x)+ABS(坐標。y-來自坐標。y);} INTCATSPRITE::cost to move Fromstead AdjacentStep(恒短測試路徑step * from step,恒短測試路徑step * to step){//因為不能側著走,而且因為地形跟走和不走是壹樣的//如果可以斜著走,或者有沼澤,丘陵等。,那麽壹定是不同的return 1;接下來,我們需要壹種方法來獲得給定正方形的所有相鄰可行走正方形。因為在這個遊戲中,HelloWorld管理地圖,所以在那裏添加方法。打開HelloWorldScene.cpp文件,添加以下方法:point array * hello world::walkableleadjacenttilecoord(const point & amp;tile cord)const { point array * tmp = point array::create(4);//on pointp(tile cord . x,tile cord . y-1);如果(this-& gt;isvalidilecord(p)和amp& amp!這-& gt;isWallAtTileCoord(p)){ tmp-& gt;addControlPoint(p);}//left p . setpoint(tile cord . x-1,tile cord . y);如果(this-& gt;isvalidilecord(p)和amp& amp!這-& gt;isWallAtTileCoord(p)){ tmp-& gt;addControlPoint(p);p.setpoint下(tilecoord.x,tile cord . y+1);如果(this-& gt;isvalidilecord(p)和amp& amp!這-& gt;isWallAtTileCoord(p)){ tmp-& gt;addControlPoint(p);}//right p . setpoint(tile cord . x+1,tile cord . y);如果(this-& gt;isvalidilecord(p)和amp& amp!這-& gt;isWallAtTileCoord(p)){ tmp-& gt;addControlPoint(p);} returntmp}可以在CatSprite.cpp中繼續movetower方法在movetower方法之後,添加以下代碼:boolpathFound = false_ spopensteps . clear();_ spclosedsteps . clear();//首先將貓的盒子坐標添加到開放列表this->;insertInOpenSteps(ShortestPathStep::createWithPosition(fromTileCoord));Do {// Step獲取最小的f值//因為是有序列表,所以第壹步總是最小的f值shorttestpathstep * current Step = _ spopensteps。在(0);//將當前步驟添加到關閉的list _ spclosedsteps.pushback(當前步驟);//從開放列表中移除//需要註意的是,如果要先從開放列表中移除,要小心object _spOpenSteps.erase(0)的內存;//如果當前步是目標方坐標,那麽If(current step->-->;getPosition()= = toilecoord){ path found = true;ShortestPathStep * tmp step = current step;cc log(" path found:");do { CCLOG("%s ",tmpStep-& gt;getDescription()。c _ str());tmpStep=tmpStep->get parent();//Backward } while(tmpStep);//直到沒有之前的step _ spopensteps . clear();_ spclosedsteps . clear();打破;}//獲取當前步驟相鄰方塊的坐標,point array * adj steps = _ layer-& gt;walkableAdjacentTilesCoordForTileCoord(current step-& gt;getPosition());for(ssize _ ti = 0;icount();++ I){ ShortestPathStep * step = ShortestPathStep::createWithPosition(adj steps-& gt;getControlPointAtIndex(I));//檢查該步驟是否已經在封閉列表中,如果(this->;getStepIndex(_spClosedSteps,step)!=-1) {繼續;}//計算從當前步驟到該步驟的開銷intmoveCost = this-& gt;costToMoveFromStepToAdjacentStep(current step,step);//檢查該步驟是否已經在開放列表中ssize _ tindex = this-& gt;getStepIndex(_spOpenSteps,step);//不在開放列表中,添加它if(index==-1) {//將當前步驟設置為上壹步-->;set parent(current step);//G的值等於上壹步G的值+上壹步到此步的代價-->;setGScore(current step-& gt;getGScore()+move cost);//H值是從這壹步到目標方坐標步的移動量估算值-->;Seth score(this-& gt;computeHScoreFromCoordToCoord(步驟-& gt;getPosition()、totelecoord));//在開放列表中添加this-& gt;insertInOpenSteps(步驟);} else {//獲取舊步驟,其值已計算為step = _ spopensteps . at(index);//檢查g的值是否低於if的值((當前步->;getgscore()+move cost)getgscore(){//g的值等於上壹步g的值+上壹步到此步的代價-->;setGScore(current step-& gt;getGScore()+move cost);//因為g的值變了,f的值也會變//所以為了保持開放列表的有序,妳需要去掉這個步驟,然後按順序重新插入//在去掉之前,妳需要保持引用step-& gt;retain();//現在可以放心刪除了,不用擔心被釋放_ spopensteps . erase(index);//重新插入這個-& gt;insertInOpenSteps(步驟);//現在可以釋放了,因為開放列表應該持有它step->;發布();} } } } while(_ spopensteps . size()& gt;0);如果(!path found){ simple audio engine::getInstance()-& gt;playEffect(" hit wall . wav ");}添加以下方法:ssize _ tcatssprite::getstepindex(const cocos 2d::vector &;steps,constcastsprite::ShortestPathStep * step){ for(ssize _ ti = 0;IIS equal(step)){ returni;} } return-1;}編譯運行,點擊地圖,如下圖所示:從:24.000000,0.000000到:23.000000,3.0000000 path found:POS =[23;3]g = 10h = 0f = 10 pos =[22;3]g = 9h = 1f = 10 pos =[21;3]g = 8h = 2f = 10 pos =[20;3]g = 7h = 3f = 10 pos =[20;2]g = 6h = 4f = 10 pos =[20;1]g = 5h = 5f = 10 pos =[21;1]g = 4h = 4f = 8 pos =[22;1]g = 3h = 3f = 6 pos =[23;1]g = 2h = 2f = 4 pos =[24;1]g = 1h = 3f = 4 pos =[24;0]g=0h=0f=0註意,路徑是從後面建立的,所以壹定要從下往上看貓選擇了哪條路徑。跟著小路走既然已經找到了小路,就讓貓跟著走吧。妳需要創建壹個數組來存儲路徑,打開CatSprite.h文件,添加以下代碼:cocos2d::Vector _ shortest path;打開CatSprite.cpp文件,更改moveToward方法,註釋掉語句* * boolpathFound = false * *,如下://boolpath found = false;替換語句* * pathFound = true* *如下://path found = true;這-& gt;construtpathandstartanimationfromstep(current step);並註釋掉下面的調試語句://shorttestpathstep * tmp step = current step;//cc log(" path found:");//do //{ //CCLOG("%s ",tmpStep-& gt;getDescription()。c _ str());//tmp step = tmp step-& gt;get parent();//向後/
  • 上一篇:捏捏鼻子,在潛水裏打個數字。
  • 下一篇:東北春天的釣魚技巧
  • copyright 2024遊戲中心平台