游戏寻路算法A*的实现

原创 2007年09月21日 13:51:00

[测试平台] Celeron 2.4GHZ + 1G内存

[演示]

 

(1)    地图大小(size)假设地图都是正方形size <= 1000

(2)    障碍百分比(rate):用于设置障碍点数,障碍数=size*size*rate/100

(3)    测试软件的目标是用A*算法在地图中找到最短路径

(4)    图示中size = 1000的地图用了624ms,这是比较好的情况,如果在比较差的情况下size=1000时可能需要3s的时间;当一般情况size=300时,一般需要100ms左右的时间,应该还是属于高效的。

(5)    起点坐标(00),终点坐标(size-1,size-1

(6)    地图文件map.in,寻路输出文件map.out,最好用写字版打开.

(7)    本文的目标在于介绍A*的具体实现方法,不打算介绍A*的原理,也不会对h(n)进行过多的探讨,h(n)使用最简单的dx+dy形式。从算法效率角度来说针对总体效率的把握,而没有对程序本身进行过多无谓的优化,否则如果用汇编实现一些关键运算的话效率就可以提高N多。

 


[寻路结果示例] size=30,rate = 60,.’表示可以通行,‘*’表示障碍

→↘ . * . . . * * * . * * * * * . . . . * . . * . . . * . *

 . * . * . . * * * . . * * * . . . . * . * . . . . . * * *

 . * * * * * . * . . . . * * . * . * * * . * . . . * . * .

 * * . . * . * . * . * * * . . . * . . . * . . * . . * . *

 . . . * * * * . * . * . . . * * . * . . . * . . . . * * .

 . . . * * . . . . * * . * . * * . * * * . . * . . . * . .

 . . . . .→→→↘ * . . * * . * * . . . * * . . * . * . . *

 * * . . * . . * . . * . . * * * * . . * * * . . * * . * *

 . . * . * . * . * * . * . * * * * * . * . . . . . * * . .

 . . . * . * . . * * * * . * . . * * . * . . * . * . . * *

 . * * * * . . . * * . * * . . . . . * * * . * . . . . . .

 . * * * * * . . . . * * * * * * . . * * * * . . * . . * .

 * . . . * . . * . * * *↘ . . * * * * . . . * . * . . . * .

 . . * . . . * * * . * . *↙ * * * * * . . . * . . * . . * .

 . * * * * * . . . . * *↘ * * * . * * . . . * . . * . . * .

 * * . * . * * * . * * . .→→↘ * . * * . * . * * * . * . .

 . . . . * * . . . * * * . * * *→↘ * * . * . * * * * . . .

 * * . . . . * * * . . . * . * . . .↘ * . * . . . * * * . .

 . * . * . . . . . * * . . . * . * * .→↘ * * . * . . * * *

 . * * . . . . . . * * . * * * . * . . . *↓ * * . * . * . *

 . * . * * * . . . * . * . * . . * . . * *↘ . * . * . * * *

 . * * * . * . . * . . * . . * * * . . . . .↘ * . * * * . *

 . * * * * . * * . . . . . * . . . * . * * . .↘ * . . * * *

 * . . . * * * * . . . . . . . * . * . * * . * *↘ . * * * .

 . * . . . . . * . * * . * . . . * * . * * * * . *↘ . * . *

 * . * * * . * * . . . . . . . . * . . * . * . * . *↘ . * *

 . * . . . . . * . * . * * . * * . . * . * . * . . * .↘ . *

 * . . . * . . * . * * * . . * * . * . * . . . * . . * .↘ *

 . . . . . . . * * . * * . * * . * * . * . * . . * * * * *↓

 . . * . * . . . . . . . . . * . . . . . . * . . * * * . * .

 

一、A*算法实现过程中的存储结构

(1)    八个方向

int dir[8][2] = {{-1,0},{-1,1},{0,1},{1,1},{-1,-1},{0,-1},{1,-1},{1,0}} ;

char dir_ch[8][3] = { "","","","","","","","" } ;

这样存储8个方向的好处是,当知道AàB的方向为x时,就可以直接得到BàA的方向为(7-x)

 

 

 

(2)    地图储存结构MAP

typedef struct _MAP {

     int type ;             // 0:可行 1:障碍

     int status ;            // 0:未访问1:OPEN 2:CLOSE

     int dir_parent ;        // 指向前一结点dir ( 07)

     int g ;                // g(n),起点到当前结点的代价

     int h ;                // h(n),当前结点到终点的估价值

     int index ;            // heap中的结点索引号

} MAP ;

 

着重介绍2个参数:

<1>status:当前结点的状态,由于这个参数的存在可以节约CLOSE列表

<2>indexA*中需要对结点进行不断的更新,这个参数可以直接定位到当前结点在OPEN队列中的位置,不需要额外的查找。

 

(3)    OPEN列表的结点

typedef struct _NODE {

     int x, y ;    // 结点坐标

     int value ;   // f = g + h

} NODE, *PNODE ;

 

二、A*算法实现

bool  AStar_GetShortestPath ()
{
    
int lx = CUR_LEN, ly =
 CUR_LEN ;
    
int nStartX = 0, nStartY = 0
 ;
    
int nEndX = lx-1, nEndY = ly-1
 ;

    OPEN.BHAddNew ( nStartX, nStartY, 
3
 ) ;
    map[nStartX][nStartY].status 
= 1
 ;
    map[nStartX][nStartY].index 
= 0
 ;

    
while ( OPEN.BHGetNum() > 0
 )
    {
        NODE TopNode 
=
 OPEN.BHGetTop () ;
        
// 如果堆顶元素为终点时,直接返回true

        if ( TopNode.x == nEndX && TopNode.y == nEndY )
            
return true
 ;

        
// 修改结点状态,OPEN-->CLOSE

        map[TopNode.x][TopNode.y].status = 2 ;
        OPEN.BHDelTop () ;

        
for ( int i = 0; i < 8; i++
 )
        {
            
int a = TopNode.x + dir[i][0
] ;
            
int b = TopNode.y + dir[i][1
] ;
            
// 检测坐标是否有效,且该结点是否为障碍

            if ( IsValidPos(a,b) == false || map[a][b].type == 0 )
                
continue
 ;

            
// 计算当前消费g(n)

            int cur_cost = map[TopNode.x][TopNode.y].g + cost[i] ;

            
// 若该结点首次被访问

            if ( map[a][b].status == 0 )
            {
                map[a][b].status 
= 1
 ;
                map[a][b].dir_parent 
= 7 -
 i ;
                map[a][b].g 
=
 cur_cost ;
                map[a][b].h 
= ( nEndX - a ) + ( nEndY - b ) ;    // 只在首次访问时估价h(n)

                OPEN.BHAddNew ( a, b, map[a][b].g + map[a][b].h ) ;
            }
            
// 如果该结点需要更新

            else if ( cur_cost < map[a][b].g )
            {
                map[a][b].dir_parent 
= 7-
i ;
                map[a][b].g 
=
 cur_cost ;

                
// 如果该结点已经在OPEN,那么只需要BinaryHeap进行修改操作

                if ( map[a][b].status == 1 )
                {
                    OPEN.BHAdjustByIndex ( map[a][b].index, map[a][b].g 
+
 map[a][b].h ) ;
                }
                
// 如果该结点在CLOSE中,那么只需要BinaryHeap进行添加操作

                else if ( map[a][b].status == 2 )
                {
                    OPEN.BHAddNew ( a, b, map[a][b].g 
+
 map[a][b].h ) ;        
                }
                map[a][b].status 
= 1
 ;
            }
        } 
// for

    } // while 
    
    
return false
 ;
}

 

 

 

三、二插堆(Binary Heap)A*中的应用

BinaryHeap的来实现OPEN,有这么几个优点:

(1)    快速定位OPEN中最小元素,O(1)

(2)    能够实现对结点的快速插入/删除/修改,O(long(n))

BinaryHeap本身对结点的修改操作支持不好,因为除了已知堆顶元素最小/大之外,对其他元素一无所知,因而一般情况下非暴力搜索不可行。在地图存储结构MAP中有index项,就可以直接定位当前结点在OPEN中的位置。

 

BinaryHeap3种操作方式:插入/删除/修改 

 

 

    bool BHAddNew ( int x, int y, int value )
    {
        NODE node ( x, y, value ) ;
        
this->pHeap[this->count++= node ;
        
this->BHFilterUp ( this->count-1 ) ;
        
return true ;
    }

    
bool BHDelTop ()
    {
        
if ( this->count <= 0 )
            
return false ;

        
this->count-- ;
        
this->pHeap[0= this->pHeap[this->count] ;
        
this->BHFilterDown ( 0 ) ;
        
return true ;
    }

    
bool BHAdjustByIndex ( int index, int nNewValue )
    {
        
this->pHeap[index].value = nNewValue ;
        
if ( this->BHFilterDown ( index ) == index )
            
this->BHFilterUp ( index ) ;
        
return true ;
    }

 

BinaryHeap2种更新方式:向下/向上更新

int BHFilterDown ( int index )
    {
        NODE TempNode 
= this->
pHeap[index] ;
        
int cur =
 index ;
        
int son = 2 * cur + 1
 ;
        
while ( son < this->
count )
        {
            
if ( son+1 < this->count && this->pHeap[son].value > this->pHeap[son+1
].value )
                son
++
 ;

            
if ( TempNode.value < this->
pHeap[son].value )
                
break
 ;
            
else

            {
                
this->pHeap[cur] = this->pHeap[son] ;
                
this->BHUpdatePos ( this->pHeap[son].x, this->
pHeap[son].y, cur ) ;
                cur 
=
 son ;
                son 
= 2 * cur + 1
 ;
            }
        }
        
this->pHeap[cur] =
 TempNode ;
        
this->
BHUpdatePos ( TempNode.x, TempNode.y, son ) ;
        
return
 son ;
    }

    
int BHFilterUp ( int
 index )
    {
        NODE TempNode 
= this->
pHeap[index] ;
        
int cur =
 index ;
        
int parent = ( cur - 1 ) / 2
 ;
        
while ( cur != 0
 )
        {
            
if ( this->pHeap[parent].value <=
 TempNode.value )
                
break
 ;

            
this->pHeap[cur] = this->
pHeap[parent] ;
            
this->BHUpdatePos ( this->pHeap[parent].x, this->
pHeap[parent].y, cur ) ;
            cur 
=
 parent ;
            parent 
= ( cur - 1 ) / 2
 ;
        }
        
this->pHeap[cur] =
 TempNode ;
        
this->
BHUpdatePos ( TempNode.x, TempNode.y, cur ) ;
        
return
 cur ;
    }

 

 

node在堆中改变位置时需要修改MAP中所对应[node.x,node.y]中的index

void BHUpdatePos ( int x, int y, int pos )

     {

         map[x][y].index = pos ;

     }

 

A*算法的实现(c++优先队列)

A*算法的理解 对于A*算法,网上已经有了很详尽的描述,这里不再重复,如果想去看的话,我看了很多博客,最后看到这个博客的时候成功实现了A*算法。 在我看来,A*算法的实质其实就是BFS,只不过BF...
  • a854500070
  • a854500070
  • 2017年09月14日 17:59
  • 143

A*算法实现

1.A*基本流程图 2.扩展节点方法 3.A*最短路径条件 代码: 1.main.lua require "Lib" --create scene local gameScen...
  • themagickeyjianan
  • themagickeyjianan
  • 2016年09月07日 01:50
  • 801

A*算法实现

  • 2012年11月18日 14:40
  • 171KB
  • 下载

探索小游戏(三):A*算法实现自动寻路

关于A*算法,推荐一篇博客: 这里写链接内容博客中介绍了A*算法的原理,通过这个探索小游戏实现自动寻路,结合代码加深对A*算法的理解。首先定义了一个Point类:local Point = clas...
  • forestsenlin
  • forestsenlin
  • 2016年03月30日 21:00
  • 2163

Unity3D实现A*寻路算法

目录(?)[+] A算法复习实现NodePriorityQueueGridManagerAStarTestCode ClassScene setupTesting总结 ...
  • IT_faquir
  • IT_faquir
  • 2015年05月05日 15:55
  • 2585

A*算法实现

A*算法实现一、 算法思想      搜索中利用启发式信息,对当前未扩展结点根据设定的估价函数值选取离目标最近的结点进行扩展,从而缩小搜索空间,更快的得到最优解,提高效率。二、 启发函数1、 不在位数...
  • fifan
  • fifan
  • 2005年01月25日 11:51
  • 5607

A*算法实现及讲解

  • 2016年09月13日 08:29
  • 12KB
  • 下载

A*寻路算法的C#实现

详细讲述了A*寻路算法,有下列地方值得学习1. 不要用AStarPathNode来构造PathFinder的Matrix,Matrix仅仅是byte[,],需要对Matrix中某个元素进行处理时再构造...
  • kenkao
  • kenkao
  • 2010年04月13日 12:34
  • 6008

我的游戏框架基础构建篇(A* 寻路算法实现 )

一、控件功能描述         本控件主要是实现游戏地图中寻路算法的一个助手,帮助寻找二维地图上从一个点到另一个点的最优路线0 二、实现策略          实现的策略我主要是参考的 htt...
  • xzben
  • xzben
  • 2015年01月09日 11:59
  • 469

A*算法实现

       在游戏编程中广泛使用了A*算法。 就比如红警里面你框一辆坦克然后在目的地上点一下鼠标,不管多远坦克都会自动跑到目标点上(前提是目标点是可以到达的畅通路径)。在这个过程中坦克起始位置和终点...
  • sunday168
  • sunday168
  • 2007年10月23日 21:42
  • 626
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:游戏寻路算法A*的实现
举报原因:
原因补充:

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