AS3 高级动画教程学习之:寻路(A*算法)
2012-06-29 14:53
609 查看
A_star运算法则
相关专业术语。
节点(node):本质上就是方形网格里的某一个方格(yujjj注:为什么不把他们描述为方格?因为在一些时候划分的节点不一定是方形的,矩形、六角形、或其它任意形状,本书中只讨论方格)。由此可以看出,路径将会由起点节点,终点节点,还有从起点到终点经过的节点组成。
代价(cost):这是对节点优劣分级的值。代价小的节点肯定比代价大节点更好。代价由两部分组成:从起点到达当前点的代价和从这个点到终点的估计代价。代价一般由变量f,g和h,具体如下。
f:特定节点的全部代价。由g+h决定。
g:从起点到当前点的代价。它是确定的,因为你肯定知道从起点到这一点的实际路径。
h:从当前点到终点的估计代价。是用估价函数(heuristic function)计算的。它只能一个估算,因为你不知道具体的路线——你将会找出的那一条。
估价函数(heuristic):计算从当前点到终点估计代价的公式。通常有很多这样的公式,但他们的运算结果,速度等都有差异(yujjj注:估价公式计算的估计值越接近实际值,需要计算的节点越少;估价公式越简单,每个节点的计算速度越快)。
待考察表(open list):一组已经估价的节点。表里代价最小的节点将是下一次的计算的起点。
已考察表(closed list):从待考察表中取代价最小的节点作为起点,对它周围8个方向的节点进行估价,然后把它放入“已考察表”。
父节点(parent node):以一个点计算周围节点时,这个点就是其它节点的父节点。当我们到达终点节点,你可以一个一个找出父节点直到起点节点。因为父节点总是带考察表里的小代价节点,这样可以确保你找出最佳路线。
现在我们来看以下具体的运算方法:
1. 添加起点节点到待考察表
2. 主循环
a. 找到待考察表里的最小代价的节点,设为当前节点。
b. 如果当前点是终点节点,你已经找到路径了。跳到第四步。
c. 考察每一个邻节点(直角坐标网格里,有8个这样的节点 )对于每一个邻节点: (1).如果是不能通过的节点,或者已经在带考察表或已考察表中,跳过,继续下一节点,否则继
续。
(2).计算它的代价
(3).把当前节点定义为这个点的父节点添加到待考察表
(4).添加当前节点到已考察表
3. 更新待考察表,重复第二步。
4. 你已经到达终点,创建路径列表并添加终点节点
5. 添加终点节点的父节点到路径列表
6. 重复添加父节点直到起点节点。路径列表就由一组节点构成了最佳路径
*上边内容摘自:《Flash actionScript 3.0高级动画教程》第四章 寻路
结合
AS3 高级动画教程学习之:等角投影笔记 的所创建的地图信息,学习A*算法 寻找最佳路径。首先得添加 Node, Grid , AStar三个类
Node类
Node 类网格节点数据对象,相比《AS3 高级动画教程》我们添加 _object属性,用于记录此节点的图形。
Grid类:
Grid类使用二维数据(_grid )保存所有网格节点的数据信息。
AStar类
主角登场,AStar类, 从开始节点开始,一次一次的循环,查询当前节点的相领节点。当当前节点为终点节点时,整个计算结束,退出循环。
当前节点的相邻节点
修改IsoWorld类:
在IsoWorld添加 createGrid,findPath函数.
并在makeWorld 调用 createGrid访求,并通过grid.setNodeObject( )访使得网格节点与图形关联.
修改IsoWorldTest类
修改测试类IsoWorldTest,在onMapComplete中添加
一行代码,定义的开始节点,终点节点。调用findPath开始寻路.
最后运行结果: 红色为起始节点,黄色为终点节点,蓝色为路径过程节点。
相关专业术语。
节点(node):本质上就是方形网格里的某一个方格(yujjj注:为什么不把他们描述为方格?因为在一些时候划分的节点不一定是方形的,矩形、六角形、或其它任意形状,本书中只讨论方格)。由此可以看出,路径将会由起点节点,终点节点,还有从起点到终点经过的节点组成。
代价(cost):这是对节点优劣分级的值。代价小的节点肯定比代价大节点更好。代价由两部分组成:从起点到达当前点的代价和从这个点到终点的估计代价。代价一般由变量f,g和h,具体如下。
f:特定节点的全部代价。由g+h决定。
g:从起点到当前点的代价。它是确定的,因为你肯定知道从起点到这一点的实际路径。
h:从当前点到终点的估计代价。是用估价函数(heuristic function)计算的。它只能一个估算,因为你不知道具体的路线——你将会找出的那一条。
估价函数(heuristic):计算从当前点到终点估计代价的公式。通常有很多这样的公式,但他们的运算结果,速度等都有差异(yujjj注:估价公式计算的估计值越接近实际值,需要计算的节点越少;估价公式越简单,每个节点的计算速度越快)。
待考察表(open list):一组已经估价的节点。表里代价最小的节点将是下一次的计算的起点。
已考察表(closed list):从待考察表中取代价最小的节点作为起点,对它周围8个方向的节点进行估价,然后把它放入“已考察表”。
父节点(parent node):以一个点计算周围节点时,这个点就是其它节点的父节点。当我们到达终点节点,你可以一个一个找出父节点直到起点节点。因为父节点总是带考察表里的小代价节点,这样可以确保你找出最佳路线。
现在我们来看以下具体的运算方法:
1. 添加起点节点到待考察表
2. 主循环
a. 找到待考察表里的最小代价的节点,设为当前节点。
b. 如果当前点是终点节点,你已经找到路径了。跳到第四步。
c. 考察每一个邻节点(直角坐标网格里,有8个这样的节点 )对于每一个邻节点: (1).如果是不能通过的节点,或者已经在带考察表或已考察表中,跳过,继续下一节点,否则继
续。
(2).计算它的代价
(3).把当前节点定义为这个点的父节点添加到待考察表
(4).添加当前节点到已考察表
3. 更新待考察表,重复第二步。
4. 你已经到达终点,创建路径列表并添加终点节点
5. 添加终点节点的父节点到路径列表
6. 重复添加父节点直到起点节点。路径列表就由一组节点构成了最佳路径
*上边内容摘自:《Flash actionScript 3.0高级动画教程》第四章 寻路
结合
AS3 高级动画教程学习之:等角投影笔记 的所创建的地图信息,学习A*算法 寻找最佳路径。首先得添加 Node, Grid , AStar三个类
Node类
package com.hope.isometric { /** * Represents a specific node evaluated as part of p pathfinding algorithm. * @author huilin * */ public class Node { public var x:Number; public var y:Number; public var f:Number; public var g:Number; public var h:Number; public var walkable: Boolean; public var parent:Node; public var costMultiplier:Number = 1.0; private var _object: IsoObject = null; public function Node( x: int, y: int ) { this.x = x; this.y = y; } static public function create( x: int, y: int ): Node { return new Node( x, y ); } public function set object( value: IsoObject ): void { _object = value; } public function get object(): IsoObject { return _object; } } }
Node 类网格节点数据对象,相比《AS3 高级动画教程》我们添加 _object属性,用于记录此节点的图形。
Grid类:
package com.hope.isometric { import mx.utils.object_proxy; /** * Holds a two-dimensional array of Nodes method to manipulate them start node and end node for * find a path. * * @author huilin * */ public class Grid { private var _startNode: Node; private var _endNode: Node; [ArrayElementType("Node")] private var _grid: Array; private var _numCols: int; private var _numRows: int; public function Grid( numCols: int, numRows: int) { _numCols = numCols; _numRows = numRows; init(); } static public function create( numCols: int, numRows: int ): Grid { return new Grid( numCols, numRows ); } /** * Init Grid with Nodes * */ private function init(): void { _grid = new Array(); for( var i: int = 0; i < _numCols; i++ ) { _grid[ i ] = new Array(); for( var j:int = 0; j < _numRows; j++ ) { _grid[i][j] = Node.create( i, j ); } } } /** * * @param x The x coordinate. * @param y The y coordinate. * @return The Node at the given coordinate. * */ public function getNode( x: int, y:int ): Node { return _grid[x][y] as Node; } /** * Sets the Node at the given coordinate as startNode. * @param x The x coordinate. * @param y The y coordinate. * */ public function setStartNode( x: int, y: int ): void { _startNode = _grid[x][y]; } /** * Sets the Node at the given coordinate as endNode. * @param x The x coordinate. * @param y The y coordinate. * */ public function setEndNode( x: int, y: int ): void { _endNode = _grid[x][y]; } /** * Sets the node at the given coords as walkable or not. * @param x The x coord. * @param y The y coord. */ public function setWalkable(x:int, y:int, value:Boolean):void { _grid[x][y].walkable = value; } //////////////////////////////////////// // getters / setters //////////////////////////////////////// /** * Returns the start node. */ public function get startNode():Node { return _startNode; } /** * Returns the end node. */ public function get endNode():Node { return _endNode; } /** * Returns the number of columns in the grid. */ public function get numCols():int { return _numCols; } /** * Returns the number of rows in the grid. */ public function get numRows():int { return _numRows; } public function setNodeObject( x: int, y: int, value: IsoObject ): void { setWalkable( x, y, value.walkable ); _grid[x][y].object = value; } } }
Grid类使用二维数据(_grid )保存所有网格节点的数据信息。
AStar类
package com.hope.isometric { /** * A*算法 * @author huilin * */ import com.hope.isometric.Node; public class AStar { [ArrayElementType("Node")] private var _openList: Array; //待考察表 [ArrayElementType("Node")] private var _closedList: Array; //已考察表 private var _grid: Grid; private var _startNode: Node; private var _endNode: Node; [ArrayElementType("Node")] private var _path: Array; private var _heuristic: Function = diagonal; private var _straightCost: Number = 1.0; private var _diagCost: Number = Math.SQRT2; public function AStar() { } static public function create(): AStar { return new AStar(); } public function findPath( grid: Grid ): Boolean { _grid = grid; _openList = new Array(); _closedList = new Array(); _startNode = _grid.startNode; _endNode = _grid.endNode; _startNode.g = 0; _startNode.h = _heuristic( _startNode ); _startNode.f = _startNode.g + _startNode.h; return search(); } private function search(): Boolean { var currentNode: Node = _startNode; while( currentNode != _endNode ) { //_openList = []; //当前待考察列表 var startX: int = Math.max( 0, currentNode.x - 1 ); var endX: int = Math.min( _grid.numCols - 1, currentNode.x + 1 ); var startY: int = Math.max( 0, currentNode.y -1 ); var endY: int = Math.min( _grid.numRows - 1, currentNode.y + 1 ); //check Nodes from ( startX, startY ) to (endX, endY ); for( var i:int = startX; i <= endX; i++ ) { trace( "...................................." + i ); for( var j:int = startY; j <= endY; j++ ) { var node: Node = _grid.getNode( i, j ); trace( "node: " + node.x + " " + node.y ) if ( validNode( node, currentNode ) ) { var cost: Number = _diagCost; if ( currentNode.x == node.x || currentNode.y == node.y ) { cost = _straightCost; } var g: Number = currentNode.g + cost * node.costMultiplier; var h: Number = _heuristic( node ); var f: Number = g + h; if( isOpen( node ) || isClosed( node ) ) { if ( node.f > f ) { node.f = f; node.g = g; node.h = h; node.parent = currentNode } }else { node.f = f; node.g = g; node.h = h; node.parent = currentNode; _openList.push( node ); } } } } _closedList.push( currentNode ); //已考察列表 if ( _openList.length == 0 ) { trace( "no path found!" ); return false; } _openList.sortOn( "f", Array.NUMERIC ); currentNode = _openList.shift() as Node; trace( "find node: " + currentNode.x + " " + currentNode.y + " f:" + currentNode.f ) } buildPath(); return true; } private function validNode( node: Node, currentNode: Node ): Boolean { if( currentNode == node || !node.walkable ) return false; if ( !_grid.getNode( currentNode.x, node.y ).walkable ) return false; if ( !_grid.getNode( node.x, currentNode.y ).walkable ) return false; return true; } private function isOpen( node: Node ): Boolean { return _openList.indexOf( node ) > 0 ? true : false; } private function isClosed( node: Node ): Boolean { return _closedList.indexOf( node ) > 0 ? true : false; } private function buildPath(): void { trace( "buildPath" ); _path = new Array(); var node: Node = _endNode; _path.push( node ); while( node != _startNode ) { node = node.parent; _path.unshift( node ); } } private function manhattan( node: Node ): Number { return Math.abs( _endNode.x - node.x )*_straightCost + Math.abs( _endNode.y - node.y )*_straightCost; } private function euclidian( node: Node ): Number { var dx: Number = _endNode.x - node.x; var dy: Number = _endNode.y - node.y; return Math.sqrt(dx*dx + dy*dy ) * _straightCost; } private function diagonal( node: Node ): Number { var dx: Number = Math.abs( _endNode.x - node.x ); var dy: Number = Math.abs( _endNode.y - node.y ); var diag: Number = Math.min( dx, dy ); var straight: Number = dx + dy; return _diagCost * diag + _straightCost * ( straight - 2*diag ); } ////////////////////// ///setter / getter //////////////////// public function get grid(): Grid { return _grid; } public function set grid( value: Grid ): void { _grid = value; } public function get openList() : Array { return _openList; } public function set openList( value: Array ): void { _openList = value; } public function get closedList() : Array { return _closedList; } public function set closedList( value: Array ): void { _closedList = value; } public function get path(): Array { return _path; } } }
主角登场,AStar类, 从开始节点开始,一次一次的循环,查询当前节点的相领节点。当当前节点为终点节点时,整个计算结束,退出循环。
当前节点的相邻节点
修改IsoWorld类:
package com.hope.isometric { import flash.display.DisplayObject; import flash.display.Sprite; import flash.events.MouseEvent; import flash.geom.Point; import flash.utils.Dictionary; // http://www.java3z.com/cwbwebhome/article/article2/2825.html public class IsoWorld extends Sprite { private var grid: Grid; private var cellSize: Number; private var floor: Sprite; private var world: Sprite; [ArrayElementType("IsoObject")] private var objectList: Array; private var numCols: int = 10; private var numRows: int = 10; public function IsoWorld() { } static public function create(): IsoWorld { return new IsoWorld(); } /** * * @param size The tile size to user when making the world * @return A fully populated IsoWorld instance * */ public function makeWorld( size: Number, mapGrid: Array, tileTypes: Dictionary ): void { //cellSize = size; numCols = mapGrid.length; numRows = mapGrid[0].length; createGrid( size ); for( var i:int = 0; i < mapGrid.length; i++ ) { for( var j:int = 0; j < mapGrid[i].length; j++ ) { var cellType: String = mapGrid[i][j] as String; var cell: Object = tileTypes[ cellType ]; var tile: IsoObject = IsoObject.create( cell.type ); tile.draw(size, parseInt(cell.color), parseInt(cell.height)); tile.walkable = cell.walkable == "true" ? true:false; tile.position = new Point3D( j * 20, 0, i * 20 ); grid.setNodeObject( j, i, tile ); addChild( tile ); //trace( "tile type:" + cell.type + " x:" + i + " y:" + j + " walkable:" + tile.walkable + " " + grid.getNode(j,i).walkable ); } } } private function createGrid( size: Number ): void { cellSize = size; grid = Grid.create( numCols, numRows ); } public function setPosition( x: Number, y: Number ): void { this.x = x; this.y = y; } public function findPath( startNode: Node, endNode: Node ): void { var astar: AStar = AStar.create(); grid.setStartNode( startNode.x, startNode.y ); grid.setEndNode( endNode.x, endNode.y ); if ( astar.findPath( grid )) { trace( "find Path..." ); for( var i:int = 0; i < astar.path.length; i++ ) { var node: Node = astar.path[i] as Node; trace( "node " + i + " [ " + node.x + "," + node.y + " ]" ); var tile: IsoObject = node.object; var color: uint = 0x0000ff; if ( i == 0 ) //startNode color = 0xff0000; else if( i == astar.path.length - 1 ) //endNode color = 0xffff00; tile.draw( tile.size, color, tile.height ); } } else { trace( "not found path..." ); } } } }
在IsoWorld添加 createGrid,findPath函数.
并在makeWorld 调用 createGrid访求,并通过grid.setNodeObject( )访使得网格节点与图形关联.
修改IsoWorldTest类
package com.hope.isometric { import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Point; import flash.net.URLRequest; public class IsoWorldTest extends Sprite { private var world: IsoWorld; private var mapLoader: MapLoader; private var astar: AStar; public function IsoWorldTest() { if( stage ) init(); else addEventListener( Event.ADDED_TO_STAGE, init ); } private function init( event: Event = null ): void { removeEventListener( Event.ADDED_TO_STAGE, init ); stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; loadMap(); } private function loadMap(): void { mapLoader = new MapLoader(); mapLoader.addEventListener( Event.COMPLETE, onMapComplete ); mapLoader.loadMap( "map.txt" ); } private function onMapComplete( event: Event ): void { trace( "load complete" ); world = IsoWorld.create(); world.makeWorld( 20, mapLoader.mapGrid, mapLoader.tileTypes ); addChild( world ); world.setPosition( 500, 200 ); world.findPath( new Node( 18, 15 ), new Node( 6, 6) ); } } }
修改测试类IsoWorldTest,在onMapComplete中添加
world.findPath( new Node( 18, 15 ), new Node( 6, 6) );
一行代码,定义的开始节点,终点节点。调用findPath开始寻路.
最后运行结果: 红色为起始节点,黄色为终点节点,蓝色为路径过程节点。
相关文章推荐
- AS3 高级动画教程学习之:等角投影笔记
- “AS3.0高级动画编程”学习:第四章 寻路(AStar/A星/A*)算法 (上)
- Flash动画教程学习(三)--高级运动
- “AS3.0高级动画编程”学习:第四章 寻路(AStar/A星/A*)算法 (下)
- “AS3.0高级动画编程”学习:第四章 寻路(AStar/A星/A*)算法 (上)
- “AS3.0高级动画编程”学习:第四章 寻路(AStar/A星/A*)算法 (上)
- “AS3.0高级动画编程”学习:第四章 寻路(AStar/A星/A*)算法 (中)
- Flash动画教程学习(四)--高级动画2
- “AS3.0高级动画编程”学习:第四章 寻路(AStar/A星/A*)算法 (中)
- “AS3.0高级动画编程”学习:第四章 寻路(AStar/A星/A*)算法 (下)
- “AS3.0高级动画编程”学习:第四章 寻路(AStar/A星/A*)算法 (下)
- “AS3.0高级动画编程”学习:第四章 寻路(AStar/A星/A*)算法 (中)
- cocos2d-x学习笔记(二)浅入动画教程。
- Unity3D之Mecanim动画系统学习笔记(十一):高级功能应用
- 学习笔记:axure 高级教程 6 使用技巧集锦
- “AS3.0高级动画编程”学习:第三章等角投影(上)
- [AndEngine学习教程] 第3节 使用Modifier修改动画
- Flash ActionScript 3.0 动画高级教程 (高清PDF中文版下载)
- Flex高级动画教程中所讲的寻找行为
- jQuery学习教程七: jQuery 效果 - 动画 animate