導航:首頁 > 源碼編譯 > 傳奇a星尋路源碼

傳奇a星尋路源碼

發布時間:2023-01-04 01:01:43

『壹』 A星尋路演算法和Unity自帶的尋路相比有什麼優勢

並沒一種尋路適合所有場合,選擇都是基於需求而定的。

1. A* 演算法與貪婪演算法不一樣,貪婪演算法適合動態規劃,尋找局部最優解,不保證最優解。
A*是靜態網格中求解最短路最有效的方法。也是耗時的演算法,不宜尋路頻繁的場合。一般來說適合需求精確的場合。
與啟發式的搜索一樣,能夠根據改變網格密度、網格耗散來進行調整精確度。
使用的地方:
a. 策略游戲的策略搜索
b. 方塊格子游戲中的格子尋路

2. Unity 自帶的導航網格系統
Unity 內置了NavMesh導航網格系統,一般來說導航網格演算法大多是「拐角點演算法」。
效率是比較高的,但是不保證最優解演算法。
使用的地方:
a.游戲場景的怪物尋路
b.動態規避障礙

『貳』 如何基於Cocos2d-x v3.x實現A星尋路演算法

實現A星演算法
根據演算法,第一步是添加當前坐標到open列表。還需要三個輔助方法:
- 一個方法用來插入一個ShortestPathStep對象到適當的位置(有序的F值)
- 一個方法用來計算從一個方塊到相鄰方塊的移動數值
- 一個方法是根據"曼哈頓距離"演算法,計算方塊的H值

打開CatSprite.cpp文件,添加如下方法:

void CatSprite::insertInOpenSteps(CatSprite::ShortestPathStep *step)
{
int stepFScore = step->getFScore();
ssize_t count = _spOpenSteps.size();
ssize_t i = 0;
for (; i < count; ++i)
{
if (stepFScore <= _spOpenSteps.at(i)->getFScore())
{
break;
}
}
_spOpenSteps.insert(i, step);
}
int CatSprite::computeHScoreFromCoordToCoord(const Point &fromCoord, const Point &toCoord)
{
// 這里使用曼哈頓方法,計算從當前步驟到達目標步驟,在水平和垂直方向總的步數
// 忽略了可能在路上的各種障礙
return abs(toCoord.x - fromCoord.x) + abs(toCoord.y - fromCoord.y);
}
int CatSprite::(const ShortestPathStep *fromStep, const ShortestPathStep *toStep)
{
// 因為不能斜著走,而且由於地形就是可行走和不可行走的成本都是一樣的
// 如果能夠對角移動,或者有沼澤、山丘等等,那麼它必須是不同的
return 1;
}

接下來,需要一個方法去獲取給定方塊的所有相鄰可行走方塊。因為在這個游戲中,HelloWorld管理著地圖,所以在那裡添加方法。打開HelloWorldScene.cpp文件,添加如下方法:

PointArray *HelloWorld::(const Point &tileCoord) const
{
PointArray *tmp = PointArray::create(4);
// 上
Point p(tileCoord.x, tileCoord.y - 1);
if (this->isValidTileCoord(p) && !this->isWallAtTileCoord(p))
{
tmp->addControlPoint(p);
}
// 左
p.setPoint(tileCoord.x - 1, tileCoord.y);
if (this->isValidTileCoord(p) && !this->isWallAtTileCoord(p))
{
tmp->addControlPoint(p);
}
// 下
p.setPoint(tileCoord.x, tileCoord.y + 1);
if (this->isValidTileCoord(p) && !this->isWallAtTileCoord(p))
{
tmp->addControlPoint(p);
}
// 右
p.setPoint(tileCoord.x + 1, tileCoord.y);
if (this->isValidTileCoord(p) && !this->isWallAtTileCoord(p))
{
tmp->addControlPoint(p);
}
return tmp;
}

可以繼續CatSprite.cpp中的moveToward方法了,在moveToward方法的後面,添加如下代碼:

bool pathFound = false;
_spOpenSteps.clear();
_spClosedSteps.clear();
// 首先,添加貓的方塊坐標到open列表
this->insertInOpenSteps(ShortestPathStep::createWithPosition(fromTileCoord));
do
{
// 得到最小的F值步驟
// 因為是有序列表,第一個步驟總是最小的F值
ShortestPathStep *currentStep = _spOpenSteps.at(0);
// 添加當前步驟到closed列表
_spClosedSteps.pushBack(currentStep);
// 將它從open列表裡面移除
// 需要注意的是,如果想要先從open列表裡面移除,應小心對象的內存
_spOpenSteps.erase(0);
// 如果當前步驟是目標方塊坐標,那麼就完成了
if (currentStep->getPosition() == toTileCoord)
{
pathFound = true;
ShortestPathStep *tmpStep = currentStep;
CCLOG("PATH FOUND :");
do
{
CCLOG("%s", tmpStep->getDescription().c_str());
tmpStep = tmpStep->getParent(); // 倒退
} while (tmpStep); // 直到沒有上一步
_spOpenSteps.clear();
_spClosedSteps.clear();
break;
}
// 得到當前步驟的相鄰方塊坐標
PointArray *adjSteps = _layer->(currentStep->getPosition());
for (ssize_t i = 0; i < adjSteps->count(); ++i)
{
ShortestPathStep *step = ShortestPathStep::createWithPosition(adjSteps->getControlPointAtIndex(i));
// 檢查步驟是不是已經在closed列表
if (this->getStepIndex(_spClosedSteps, step) != -1)
{
continue;
}
// 計算從當前步驟到此步驟的成本
int moveCost = this->(currentStep, step);
// 檢查此步驟是否已經在open列表
ssize_t index = this->getStepIndex(_spOpenSteps, step);
// 不在open列表,添加它
if (index == -1)
{
// 設置當前步驟作為上一步操作
step->setParent(currentStep);
// G值等同於上一步的G值 + 從上一步到這里的成本
step->setGScore(currentStep->getGScore() + moveCost);
// H值即是從此步驟到目標方塊坐標的移動量估算值
step->setHScore(this->computeHScoreFromCoordToCoord(step->getPosition(), toTileCoord));
// 按序添加到open列表
this->insertInOpenSteps(step);
}
else
{
// 獲取舊的步驟,其值已經計算過
step = _spOpenSteps.at(index);
// 檢查G值是否低於當前步驟到此步驟的值
if ((currentStep->getGScore() + moveCost) < step->getGScore())
{
// G值等同於上一步的G值 + 從上一步到這里的成本
step->setGScore(currentStep->getGScore() + moveCost);
// 因為G值改變了,F值也會跟著改變
// 所以為了保持open列表有序,需要將此步驟移除,再重新按序插入
// 在移除之前,需要先保持引用
step->retain();
// 現在可以放心移除,不用擔心被釋放
_spOpenSteps.erase(index);
// 重新按序插入
this->insertInOpenSteps(step);
// 現在可以釋放它了,因為open列表應該持有它
step->release();
}
}
}
} while (_spOpenSteps.size() > 0);
if (!pathFound)
{
SimpleAudioEngine::getInstance()->playEffect("hitWall.wav");
}

添加以下方法:

ssize_t CatSprite::getStepIndex(const cocos2d::Vector<CatSprite::ShortestPathStep *> &steps, const CatSprite::ShortestPathStep *step)
{
for (ssize_t i = 0; i < steps.size(); ++i)
{
if (steps.at(i)->isEqual(step))
{
return i;
}
}
return -1;
}

『叄』 lua語言a星尋路演算法路徑怎麼平滑

在項目中遇到了自動尋路的需求,於是決定開始學習一下A星,對於A星我也沒有深究,只能說是勉強搞定了需求,在這和大家分享一下,相互進步,

A星有個公式 f(x) = g(x) + h(x)
,搞清楚這個公式就好辦了,f(x)就是當前位置到下一個位置的總價值,g(x)表示實際價,這是說這一部分代價是確定的,h(x)表示估價值,就是說我
從下一個位置到到終點的代價是未知的,所以叫估價值,如圖中所示,黑色格子表示當前位置,綠色格子表示下一步可能到達的位置,即上、下、左、右這幾個方
向,紅色格子表示終點,褐色表示障礙物,現在要從黑色格子到達紅色格子,那麼黑色格子的下一步肯定是綠色格子當中的一個,黑色格子到綠色格子之間是相挨著
的,所以我們可以很明確的知道它的實際代價為1(移動一步的代價)即g(x),綠色格子到紅色格子之間隔著很長的距離,中間還有障礙物,所以這個代價是未
知的,即h(x),所以總的代價就為f(x) = g(x) +
h(x),我們看到周圍有4個綠色的格子,到底走那一步比較好呢,所以我們要把這4個格子的f(x)值都求出來,然後進行排序,選擇f(x)值最小的,即
總代價最少的那個格子,以此方法繼續下去,直到到達終點 或者 地圖上沒有綠色格子了

下面來看一下這個工具類,g(x)和h(x)要選的比較合適,一般就是採用的曼哈頓演算法,即兩點在x方向和y方向的距離之和,
-- Filename: PathUtil.lua
-- Author: bzx
-- Date: 2014-07-01
-- Purpose: 尋路

mole("PathUtil", package.seeall)

local _map_data -- 地圖數據
local _open_list -- 開放節點
local _open_map -- 開放節點,為了提高性能而加
local _close_map -- 關閉節點
local _deleget -- 代理
local _dest_point -- 目標點
local _start_point -- 起點
local _path -- 路徑

-- 尋找路徑
--[[
deleget = {
g = function(point1, point2)
-- add your code
-- 返回點point1到點point2的實際代價
end
h = function(point1, point2)
-- add your code
-- 返回點point1到點point2的估算代價
end
getValue = function(j, i)
-- 返回地圖中第i行,第j列的數據 1為障礙物,0為非障礙物
end
width -- 地圖寬度
height -- 地圖高度
}
--]]
function findPath(deleget, start_point, dest_point)
_deleget = deleget
_dest_point = dest_point
_start_point = start_point
init()
while not table.isEmpty(_open_list) do
local cur_point = _open_list[1]
table.remove(_open_list, 1)
_open_map[cur_point.key] = nil
if isEqual(cur_point, dest_point) then
return makePath(cur_point)
else
_close_map[cur_point.key] = cur_point
local next_points = getNextPoints(cur_point)
for i = 1, #next_points do
local next_point = next_points[i]
if _open_map[next_point.key] == nil and _close_map[next_point.key] == nil and isObstacle(next_point) == false then
_open_map[next_point.key] = next_point
table.insert(_open_list, next_point)
end
end
table.sort(_open_list, compareF)
end
end
return nil
end

function init()
_open_list = {}
_open_map = {}
_close_map = {}
_path = {}
_map_data = {}
for i = 1, _deleget.height do
_map_data[i] = {}
for j = 1, _deleget.width do
local value = _deleget.getValue(j, i)
_map_data[i][j] = value
end
end
_open_map[getKey(_start_point)] = _start_point
table.insert(_open_list, _start_point)
end

function createPoint(x, y)
local point = {
["x"] = x,
["y"] = y,
["last"] = nil,
["g_value"] = 0,
["h_value"] = 0,
["f_value"] = 0
}
point["key"] = getKey(point)
return point
end

-- 得到下一個可以移動的點
-- @param point 當前所在點
function getNextPoints(point)
local next_points = {}
for i = 1, #_deleget.directions do
local offset = _deleget.directions[i]
local next_point = createPoint(point.x + offset[1], point.y + offset[2])
next_point["last"] = point
if next_point.x >= 1 and next_point.x <= _deleget.width and next_point.y >= 1 and next_point.y <= _deleget.height then
next_point["g_value"] = _deleget.g(point, next_point)
next_point["h_value"] = _deleget.h(point, _dest_point)--math.abs(next_points.x - _dest_point.x) + math.abs(next_points.y - _dest_point.y)
next_point["f_value"] = next_point.g_value + next_point.h_value
table.insert(next_points, next_point)
end
end
return next_points
end

-- 得到路徑
-- @param end_point 目標點
function makePath(end_point)
_path = {}
local point = end_point
while point.last ~= nil do
table.insert(_path, createPoint(point.x, point.y))
point = point.last
end
local start_point = point
table.insert(_path, start_point)
return _path
end

-- 兩個點的代價比較器
function compareF(point1, point2)
return point1.f_value < point2.f_value
end

-- 是否是障礙物
function isObstacle(point)
local value = _map_data[point.y][point.x]
if value == 1 then
return true
end
return false
end

-- 兩個點是否是同一個點
function isEqual(point1, point2)
return point1.key == point2.key
end

-- 根據點得到點的key
function getKey(point)
local key = string.format("%d,%d", point.x, point.y)
return key
end

下面是工具類PathUtil的用法
local deleget = {}
deleget.g = function(point1, point2)
return math.abs(point1.x - point2.x) + math.abs(point1.y - point2.y)
end
deleget.h = deleget.g
deleget.getValue = function(j, i)
local index = FindTreasureUtil.getIndex(j, i)
local map_info = _map_info.map[index]
if map_info.display == 0 and map_info.eid ~= 1 then
return 0
end
return 1
end
deleget.directions = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}} -- 左,上,下,右
deleget.width = _cols
deleget.height = _rows

local dest_row, dest_col = FindTreasureUtil.getMapPosition(tag)
local dest_point = PathUtil.createPoint(dest_col, dest_row)
local start_row, start_col = FindTreasureUtil.getMapPosition(_player_index)
local start_point = PathUtil.createPoint(start_col, start_row)
_path = PathUtil.findPath(deleget, start_point, dest_point)

_path就是我們找到的路徑,起點為最後一個元素,終點為第一個元素

『肆』 如何基於cocos2dx3.x實現A星尋路演算法

在學習本篇教程之前,如果你有cocos2d-x的開發經驗,將會有所幫助。如果沒有也沒關系,因為你可以將這里講解的例子遷移到其他的語言或者框架中。
找到到達你鍵盤的最短路徑,開始吧!
Maze貓
首先介紹下我們將要在本篇教程中開發的簡單游戲。
前往下載本篇教程的 工程代碼 。編譯運行工程,你將看到以下畫面。

在這款游戲中,你扮演著一隻小偷貓,在一個由危險的狗守護著的地牢里小心穿行。如果你試圖穿過一隻狗,他會把你吃掉 – 除非你可以用骨頭去賄賂它!
所以在這款游戲中,你的任務是嘗試以正確的順序撿起骨頭,然後 尋找路線 穿過狗逃離。
注意到貓只能水平或者垂直的移動(例如不能斜線移動),並且會從一個方塊的中心點移動到另一個中心點。每個方塊既可以是可通行的也可以是不可通行的。
嘗試下這款游戲,看看你能否找到出路!建議你閱讀代碼以熟悉它的原理。這是一款相當普通的方塊-地圖式游戲,我們會在接下來的教程中修改它並使用上A星尋路演算法。
Maze貓和A星概覽
正如你所看到的,當你點擊地圖某處時,貓會沿著你點擊的方向跳到相鄰的方塊上。
我們想對程序做修改,讓貓持續的往你點擊的方塊方向前進,就像許多RPGs或者point-and-click冒險類游戲。
讓我們看下控制觸摸事件代碼的工作原理。如果你打開HelloWorldScene.cpp文件,你將看到像下面這樣去實現觸摸操作:
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches( true );
listener->onTouchBegan = [ this ](Touch *touch, Event *event){
if (_gameOver)
{
return false ;
}
Point touchLocation = _tileMap->convertTouchToNodeSpace(touch);
_cat->moveToward(touchLocation);
return true ;
};
_eventDispatcher->(listener, this );
你可以看到這里只是對貓精靈調用了一個方法,讓貓在方塊地圖上往你點擊的地方移動。
我們現在要做的是修改在CatSprite.m文件中的以下方法,尋找到達該點的最短路徑,並且開始前進:
void CatSprite::moveToward( const Point &target)
{
}
創建ShortestPathStep類
我們開始創建一個內部類,代表路徑上的一步操作。在這種情況下,它是一個方塊和由A星演算法計算出來的的F,G和H scores。
class ShortestPathStep : public cocos2d::Object
{
public :
ShortestPathStep();
~ShortestPathStep();
static ShortestPathStep *createWithPosition( const cocos2d::Point &pos);
bool initWithPosition( const cocos2d::Point &pos);
int getFScore() const ;
bool isEqual( const ShortestPathStep *other) const ;
std::string getDescription() const ;
CC_SYNTHESIZE(cocos2d::Point, _position, Position);
CC_SYNTHESIZE( int , _gScore, GScore);
CC_SYNTHESIZE( int , _hScore, HScore);
CC_SYNTHESIZE(ShortestPathStep*, _parent, Parent);
};
現在添加以下代碼到CatSprite.cpp文件的頂部。
CatSprite::ShortestPathStep::ShortestPathStep() :
_position(Point::ZERO),
_gScore(0),
_hScore(0),
_parent(nullptr)
{
}
CatSprite::ShortestPathStep::~ShortestPathStep()
{
}
CatSprite::ShortestPathStep *CatSprite::ShortestPathStep::createWithPosition( const Point &pos)
{
ShortestPathStep *pRet = new ShortestPathStep();
if (pRet && pRet->initWithPosition(pos))
{
pRet->autorelease();
return pRet;
}
else
{
CC_SAFE_DELETE(pRet);
return nullptr;
}
}
bool CatSprite::ShortestPathStep::initWithPosition( const Point &pos)
{
bool bRet = false ;
do
{
this ->setPosition(pos);
bRet = true ;
} while (0);
return bRet;
}
int CatSprite::ShortestPathStep::getFScore() const
{
return this ->getGScore() + this ->getHScore();
}
bool CatSprite::ShortestPathStep::isEqual( const CatSprite::ShortestPathStep *other) const
{
return this ->getPosition() == other->getPosition();
}
std::string CatSprite::ShortestPathStep::getDescription() const
{
return StringUtils::format( "pos=[%.0f;%.0f] g=%d h=%d f=%d" ,
this ->getPosition().x, this ->getPosition().y,
this ->getGScore(), this ->getHScore(), this ->getFScore());
}
正如所見,這是一個很簡單的類,記錄了以下內容:
- 方塊的坐標
- G值(記住,這是開始點到當前點的方塊數量)
- H值(記住,這是當前點到目標點的方塊估算數量)
- Parent是它的上一步操作
- F值,這是方塊的和值(它是G+H的值)
這里定義了getDescription方法,以方便調試。創建了isEquals方法,當且僅當兩個ShortestPathSteps的方塊坐標相同時,它們相等(例如它們代表著相同的方塊)。
創建Open和Closed列表
打開CatSprite.h文件,添加如下代碼:
cocos2d::Vector _spOpenSteps;
cocos2d::Vector _spClosedSteps;
檢查開始和結束點
重新實現moveToward方法,獲取當前方塊坐標和目標方塊坐標,然後檢查是否需要計算一條路徑,最後測試目標方塊坐標是否可行走的(在這里只有牆壁是不可行走的)。打開CatSprite.cpp文件,修改moveToward方法,為如下:
void CatSprite::moveToward( const Point &target)
{
Point fromTileCoord = _layer->tileCoordForPosition( this ->getPosition());
Point toTileCoord = _layer->tileCoordForPosition(target);
if (fromTileCoord == toTileCoord)
{
CCLOG( "You're already there! :P" );
return ;
}
if (!_layer->isValidTileCoord(toTileCoord) || _layer->isWallAtTileCoord(toTileCoord))
{
SimpleAudioEngine::getInstance()->playEffect( "hitWall.wav" );
return ;
}
CCLOG( "From: %f, %f" , fromTileCoord.x, fromTileCoord.y);
CCLOG( "To: %f, %f" , toTileCoord.x, toTileCoord.y);
}
編譯運行,在地圖上進行點擊,如果不是點擊到牆壁的話,可以在控制台看到如下信息:
From: 24.000000, 0.000000
To: 20.000000, 0.000000
其中 **From** 就是貓的方塊坐標,**To**就是所點擊的方塊坐標。
實現A星演算法
根據演算法,第一步是添加當前坐標到open列表。還需要三個輔助方法:
- 一個方法用來插入一個ShortestPathStep對象到適當的位置(有序的F值)
- 一個方法用來計算從一個方塊到相鄰方塊的移動數值
- 一個方法是根據"曼哈頓距離"演算法,計算方塊的H值
打開CatSprite.cpp文件,添加如下方法:
void CatSprite::insertInOpenSteps(CatSprite::ShortestPathStep *step)
{
int stepFScore = step->getFScore();
ssize_t count = _spOpenSteps.size();
ssize_t i = 0;
for (; i < count; ++i)
{
if (stepFScore <= _spOpenSteps.at(i)->getFScore())
{
break ;
}
}
_spOpenSteps.insert(i, step);
}
int CatSprite::computeHScoreFromCoordToCoord( const Point &fromCoord, const Point &toCoord)
{
// 忽略了可能在路上的各種障礙
return abs(toCoord.x - fromCoord.x) + abs(toCoord.y - fromCoord.y);
}
int CatSprite::( const ShortestPathStep *fromStep, const ShortestPathStep *toStep)
{
// 因為不能斜著走,而且由於地形就是可行走和不可行走的成本都是一樣的
// 如果能夠對角移動,或者有沼澤、山丘等等,那麼它必須是不同的
return 1;
}
接下來,需要一個方法去獲取給定方塊的所有相鄰可行走方塊。因為在這個游戲中,HelloWorld管理著地圖,所以在那裡添加方法。打開HelloWorldScene.cpp文件,添加如下方法:
PointArray *HelloWorld::( const Point &tileCoord) const
{
PointArray *tmp = PointArray::create(4);
// 上
Point p(tileCoord.x, tileCoord.y - 1);
if ( this ->isValidTileCoord(p) && ! this ->isWallAtTileCoord(p))
{
tmp->addControlPoint(p);
}
// 左
p.setPoint(tileCoord.x - 1, tileCoord.y);
if ( this ->isValidTileCoord(p) && ! this ->isWallAtTileCoord(p))
{
tmp->addControlPoint(p);
}
// 下
p.setPoint(tileCoord.x, tileCoord.y + 1);
if ( this ->isValidTileCoord(p) && ! this ->isWallAtTileCoord(p))
{
tmp->addControlPoint(p);
}
// 右
p.setPoint(tileCoord.x + 1, tileCoord.y);
if ( this ->isValidTileCoord(p) && ! this ->isWallAtTileCoord(p))
{
tmp->addControlPoint(p);
}
return tmp;
}
可以繼續CatSprite.cpp中的moveToward方法了,在moveToward方法的後面,添加如下代碼:
bool pathFound = false ;
_spOpenSteps.clear();
_spClosedSteps.clear();
// 首先,添加貓的方塊坐標到open列表
this ->insertInOpenSteps(ShortestPathStep::createWithPosition(fromTileCoord));
do
{
// 得到最小的F值步驟
// 因為是有序列表,第一個步驟總是最小的F值
ShortestPathStep *currentStep = _spOpenSteps.at(0);
// 添加當前步驟到closed列表
_spClosedSteps.pushBack(currentStep);
// 將它從open列表裡面移除
// 需要注意的是,如果想要先從open列表裡面移除,應小心對象的內存
_spOpenSteps.erase(0);
// 如果當前步驟是目標方塊坐標,那麼就完成了
if (currentStep->getPosition() == toTileCoord)
{
pathFound = true ;
ShortestPathStep *tmpStep = currentStep;
CCLOG( "PATH FOUND :" );
do
{
CCLOG( "%s" , tmpStep->getDescription().c_str());
tmpStep = tmpStep->getParent(); // 倒退
} while (tmpStep); // 直到沒有上一步
_spOpenSteps.clear();
_spClosedSteps.clear();
break ;
}
// 得到當前步驟的相鄰方塊坐標
PointArray *adjSteps = _layer->(currentStep->getPosition());
for (ssize_t i = 0; i < adjSteps->count(); ++i)
{
ShortestPathStep *step = ShortestPathStep::createWithPosition(adjSteps->getControlPointAtIndex(i));
// 檢查步驟是不是已經在closed列表
if ( this ->getStepIndex(_spClosedSteps, step) != -1)
{
continue ;
}
// 計算從當前步驟到此步驟的成本
int moveCost = this ->(currentStep, step);
// 檢查此步驟是否已經在open列表
ssize_t index = this ->getStepIndex(_spOpenSteps, step);
// 不在open列表,添加它
if (index == -1)
{
// 設置當前步驟作為上一步操作
step->setParent(currentStep);
// G值等同於上一步的G值 + 從上一步到這里的成本
step->setGScore(currentStep->getGScore() + moveCost);
// H值即是從此步驟到目標方塊坐標的移動量估算值
step->setHScore( this ->computeHScoreFromCoordToCoord(step->getPosition(), toTileCoord));
// 按序添加到open列表
this ->insertInOpenSteps(step);
}
else
{
// 獲取舊的步驟,其值已經計算過
step = _spOpenSteps.at(index);
// 檢查G值是否低於當前步驟到此步驟的值
if ((currentStep->getGScore() + moveCost) < step->getGScore())
{
// G值等同於上一步的G值 + 從上一步到這里的成本
step->setGScore(currentStep->getGScore() + moveCost);
// 因為G值改變了,F值也會跟著改變
// 所以為了保持open列表有序,需要將此步驟移除,再重新按序插入
// 在移除之前,需要先保持引用
step->retain();
// 現在可以放心移除,不用擔心被釋放
_spOpenSteps.erase(index);
// 重新按序插入
this ->insertInOpenSteps(step);
// 現在可以釋放它了,因為open列表應該持有它
step->release();
}
}
}
} while (_spOpenSteps.size() > 0);
if (!pathFound)
{
SimpleAudioEngine::getInstance()->playEffect( "hitWall.wav" );
}
添加以下方法:
ssize_t CatSprite::getStepIndex( const cocos2d::Vector &steps, const CatSprite::ShortestPathStep *step)
{
for (ssize_t i = 0; i < steps.size(); ++i)
{
if (steps.at(i)->isEqual(step))
{
return i;
}
}
return -1;
}
編譯運行,在地圖上進行點擊,如下圖所示:

From: 24.000000, 0.000000
To: 23.000000, 3.000000
PATH FOUND :
pos=[23;3] g=10 h=0 f=10
pos=[22;3] g=9 h=1 f=10
pos=[21;3] g=8 h=2 f=10
pos=[20;3] g=7 h=3 f=10
pos=[20;2] g=6 h=4 f=10
pos=[20;1] g=5 h=5 f=10
pos=[21;1] g=4 h=4 f=8
pos=[22;1] g=3 h=3 f=6
pos=[23;1] g=2 h=2 f=4
pos=[24;1] g=1 h=3 f=4
pos=[24;0] g=0 h=0 f=0
注意該路徑是從後面建立的,所以必須從下往上看貓選擇了哪條路徑。
跟隨路徑前進
現在已經找到了路徑,只需讓貓跟隨前進即可。需要創建一個數組去存儲路徑,打開CatSprite.h文件,添加如下代碼:
cocos2d::Vector _shortestPath;
打開CatSprite.cpp文件,更改moveToward方法,注釋掉語句**bool pathFound = false**;,如下:
//bool pathFound = false;
替換語句**pathFound = true;**為如下:
//pathFound = true;
this ->(currentStep);
並且注釋掉下方的調試語句:
//ShortestPathStep *tmpStep = currentStep;
//CCLOG("PATH FOUND :");
//do
//{
// CCLOG("%s", tmpStep->getDescription().c_str());
// tmpStep = tmpStep->getParent(); // 倒退
/

『伍』 如何在使用Cocos2D中實現A星(A*)尋路演算法

實現A星演算法
根據演算法,第一步是添加當前坐標到open列表。還需要三個輔助方法:
- 一個方法用來插入一個ShortestPathStep對象到適當的位置(有序的F值)
- 一個方法用來計算從一個方塊到相鄰方塊的移動數值
- 一個方法是根據"曼哈頓距離"演算法,計算方塊的H值。
ssize_t CatSprite::getStepIndex(const cocos2d::Vector<CatSprite::ShortestPathStep *> &steps, const CatSprite::ShortestPathStep *step)
{
for (ssize_t i = 0; i < steps.size(); ++i)
{
if (steps.at(i)->isEqual(step))
{
return i;
}
}
return -1;
}

『陸』 A星尋路演算法和Unity自帶的尋路相比有什麼優勢

在理解Navigation的時候,首先要明確兩個知識點:

AStar:AStar是路點尋路演算法中的一種,同時AStar不屬於貪婪演算法,貪婪演算法適合動態規劃,尋找局部最優解,不保證最優解。AStar是靜態網格中求解最短路最有效的方法。也是耗時的演算法,不宜尋路頻繁的場合。一般來說適合需求精確的場合。

性能和內存佔用率都還行,和啟發式的搜索一樣,能夠根據改變網格密度、網格耗散來進行調整精確度。

A Star一般使用場景:

Navigation:網格尋路演算法,嚴格意義上它屬於」拐角點演算法」,效率是比較高的,但是不保證最優解演算法。Navigation相對來說消耗內存更大,性能的話還不錯。

Navigation一般使用場景:

它們二者事件的實現方式和原理都不同。


AStar的話,

閱讀全文

與傳奇a星尋路源碼相關的資料

熱點內容
mac壓縮解壓視頻 瀏覽:904
這就是程序員魅力 瀏覽:294
京東java演算法筆試題 瀏覽:178
柱子加密箍筋不準有接頭 瀏覽:199
我的世界伺服器菜單插件如何使用 瀏覽:12
劉毅10000詞pdf 瀏覽:890
剛畢業的程序員會什麼 瀏覽:974
單片機控制64路開關量 瀏覽:982
win10截圖編程 瀏覽:420
怎樣把名字變成文件夾 瀏覽:203
文件怎麼搞成文件夾 瀏覽:730
多線程編程php 瀏覽:606
安卓機越用越卡有什麼辦法 瀏覽:17
高中生解壓操場適合做的游戲 瀏覽:395
程序員java招聘 瀏覽:462
未來之光手機雲伺服器 瀏覽:160
伺服器下載資料為什麼c盤滿了 瀏覽:265
怎麼清除空文件夾 瀏覽:544
如何查看派派伺服器 瀏覽:804
殺手6解壓畫面 瀏覽:671