• AStar法


    AS3 AStar算法(1)

    Flash AS3 2009-12-03 17:25:44 阅读119 评论0 字号:

    最近再次看了一下AStar算法,并把理论转化成了代码。后来在一个2.5D的格子上测试了一把,哈哈,很不错。

    先说理论:
    A-Star算法是一种静态路网中求解最短路最有效的方法。简单的说,就是从起点开始,计算出经过周围节点的代价。找到一条代价最小的通向终点的路径。整个过程就是不断把周围代价最小的节点作为新的起点,最后达终点,同时找到最佳路径。
    上面说的节点,在网格中就是一个方格,不过也可以是其他形状,比如六边形。另外一个就是代价,代价包含两个方面的意思:从起点到当前点的代价和当前点到终点的估计代价。这两个代价值加起来就是当前点的总代价了。
    通常用公式表示为:f = g + h.
    g就是从起点到当前点的代价。
    h是当前点到终点的估计代价,是通过估价函数计算出来的。这个函数可以说是整个算法的关键了,因为算法的不同直接影响最终结果,以及算法的效率。这里有一个简单而有效算法,对于简单的网格来说就是计算当前网格到终点的距离:Math.sqrt(dx*dx+dy*dy);

    搜索过程是这样的:
    有两个数组,openList(带考察表)存放已经估价的节点,其中代价最小的节点是下一次计算的起点。closedList(已考察表)存放从待考察表中取出的代价最小的节点,在对其周围的各个节点进行估价后就将其放入closedList。
    对于每个节点都会有一个父节点,以一个点计算周围节点时,这个点就是其它节点的父节点。到达终点时,就通过每一个点的父节点一直找到起点。路径也就找到了。

    计算代价:
    对于一个不再边上的节点,他周围会有8个节点,可以看成他到周围8个点的代价都是1。精确点,到上下左右4个点的代价是1,到左上左下右上右下的1.414就是“根号2”,这个值就是前面说的g。大概就是下面这个样子
    2.8  2.4  2  2.4  2.8
    2.4  1.4  1  1.4  2.4
      2    1    0    1    2
    2.4  1.4  1  1.4  2.4
    2.8  2.4  2  2.4  2.8
    对于h,需要用一个估价函数来计算,前面有说到一个简单算法就是计算直线距离。假设终点是(50,50),对于点(20,30)来说我们用前面提到的估价函数来计算的话就是这样:
    dx = 50 - 20 = 30;
    dy = 50 - 30 = 20;
    h = Math.sqrt(dx * dx + dy * dy) = 36.1

    理论好像差不多了。接下来就是代码来。
     
     

    AS3 AStar算法(2)

    Flash AS3 2009-12-03 22:31:34 阅读82 评论0 字号:

    前面说了理论,该开始写代码来。首先,构造一个节点类AStarNode:
    package com.cyy.astar 
    {
    /**
    * ...
    * @author Will Chen
    * @version 1.0
    * @email c_youyou@163.com
    * @msn chenyouyou@live.cn
    * @description ...
    */
    public class AStarNode 
    {
    public var x:int; 
    public var y:int; 
    public var f:Number; 
    public var g:Number; 
    public var h:Number; 
    public var parent:AStarNode; 
    public var isEmpty:Boolean = true;
    public function AStarNode(x:int, y:int)
    this.x = x; 
    this.y = y;
    }
    }
    }

    接着是网格类AStarGrid:
    package com.cyy.astar 
    {
    /**
    * ...
    * @author Will Chen
    * @version 1.0
    * @email c_youyou@163.com
    * @msn chenyouyou@live.cn
    * @description ...
    */
    public class AStarGrid 
    {
    public var startNode:AStarNode;
    public var endNode:AStarNode;
    public var nodes:Array;
    public var columnNum:int;
    public var rowNum:int;
    public function AStarGrid(columnNum:int, rowNum:int)
    {
    this.columnNum = columnNum;
    this.rowNum = rowNum;
    nodes = new Array();
    for(var i:int = 0; i < columnNum; i++)
    {
    nodes[i] = new Array();
    for(var j:int = 0; j < rowNum; j++)
    {
    nodes[i][j] = new AStarNode(i, j);
    }
    }
    }
    public function getNode(x:int, y:int):AStarNode
    {
    return nodes[x][y];
    }
    public function setEndNode(x:int, y:int):AStarNode
    {
    if (x < this.columnNum && y < this.rowNum)
    {
    endNode = nodes[x][y];
    }
    else
    {
    endNode = null;
    }
    return endNode;
    }
    public function setStartNode(x:int, y:int):AStarNode
    {
    if (x < this.columnNum && y < this.rowNum)
    {
    startNode = nodes[x][y];
    }
    else
    {
    startNode = null;
    }
    return startNode;
    }
    public function setNodeEmpty(x:int, y:int, value:Boolean):void
    {
    nodes[x][y].isEmpty = value;
    }
    }
    }

    然后就是AStar:
    package com.cyy.astar 
    {
    /**
    * ...
    * @author Will Chen
    * @version 1.0
    * @email c_youyou@163.com
    * @msn chenyouyou@live.cn
    * @description ...
    */
    public class AStar
    {
    private var openList:Array;
    private var closedList:Array;
    private var _path:Array;
    private var grid:AStarGrid;
    private var endNode:AStarNode;
    private var startNode:AStarNode;
    private var costOne:Number = 1;
    private var costSqrt:Number = Math.SQRT2;
    public function AStar() 
    {
    }
    public function findPath(grid:AStarGrid):Boolean 
    this.grid = grid;
    openList = new Array();
    closedList = new Array();
    grid.startNode.g = 0;
    grid.startNode.h = getH(grid.startNode);
    grid.startNode.f = grid.startNode.g + grid.startNode.h;
    return begin();
    }
    private function begin():Boolean
    {
    var node:AStarNode = grid.startNode;
    while (node != grid.endNode)
    {
    var beginX:int = node.x == 0 ? 0 : node.x - 1;
    var endX:int = node.x == grid.columnNum - 1 ? grid.columnNum - 1 : node.x + 1;
    var beginY:int = node.y == 0 ? 0 : node.y - 1;
    var endY:int = node.y == grid.rowNum - 1 ? grid.rowNum - 1 : node.y + 1;
    for (var i:int = beginX; i <= endX; i++) 
    {
    for (var j:int = beginY; j <= endY; j++) 
    {
    var currentNode:AStarNode = grid.getNode(i, j);
    if (currentNode == node || !currentNode.isEmpty
    || (!grid.getNode(node.x, currentNode.y).isEmpty && !grid.getNode(currentNode.x, node.y).isEmpty))
    {
    continue;
    }
    var cost:Number = costOne;
    if (!((node.x == currentNode.x) || (node.y == currentNode.y)))
    {
    cost = costSqrt;
    }
    var g:Number = node.g + cost;
    var h:Number = getH(currentNode);
    var f:Number = g + h;
    if (openList.indexOf(currentNode) == -1 && closedList.indexOf(currentNode) == -1)
    {
    currentNode.f = f;
    currentNode.g = g;
    currentNode.h = h;
    currentNode.parent = node;
    openList.push(currentNode);
    }
    }
    }
    closedList.push(node);
    if (openList.length == 0)
    {
    return false
    }
    openList.sortOn("f", Array.NUMERIC);
    node = openList.shift();
    }
    _path = new Array(); 
    node = grid.endNode;
    _path.push(node);
    while (node != grid.startNode)
    node = node.parent; 
    _path.unshift(node);
    }
    return true;
    }
    private function getH(node:AStarNode):Number 
    var dx:Number = node.x - grid.endNode.x;
    var dy:Number = node.y - grid.endNode.y;
    return Math.sqrt(dx * dx + dy * dy); 
    }
    public function get path():Array { return _path; }
    }
    }

    OK,完成,核心代码就这么多了,不过还有很多地方可以优化。
    下次再写一个测试用的类

    AS3 AStar算法(3)

    Flash AS3 2009-12-04 10:30:32 阅读79 评论0 字号:

    开始测试。。。不多说,看代码:
    package  
    {
    import com.cyy.astar.AStar;
    import com.cyy.astar.AStarGrid;
    import com.cyy.astar.AStarNode;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    /**
    * ...
    * @author Will Chen
    * @version 1.0
    * @email c_youyou@163.com
    * @msn chenyouyou@live.cn
    * @description ...
    */
    public class AStarTest extends Sprite
    {
    private var player:Sprite;
    private var grid:AStarGrid;
    private var index:int;
    private var path:Array;
    private var speed:Number = 0.5;
    public function AStarTest() 
    {
    player = new Sprite();
    player.graphics.beginFill(0x0000ff);
    player.graphics.drawCircle(0, 0, 5);
    player.graphics.endFill();
    player.x = 310;
    player.y = 310;
    addChild(player);
    grid = new AStarGrid(50, 50);
    for (var i:int = 0; i < 500; i++)
    grid.setNodeEmpty(Math.floor(Math.random() * 50), Math.floor(Math.random() * 50), false);
    }
    drawGrid();
    stage.addEventListener(MouseEvent.CLICK, onStageClickHandler);
    }
    private function drawGrid():void
    {
    graphics.clear();
    for (var i:int = 0; i < grid.columnNum; i++) 
    {
    for (var j:int = 0; j < grid.rowNum; j++)
    {
    graphics.lineStyle(0);
    graphics.beginFill(getColor(grid.getNode(i, j)));
    graphics.drawRect(i * 20, j * 20, 20, 20);
    graphics.endFill();
    }
    }
    }
    private function getColor(node:AStarNode):uint 
    {
    if (!node.isEmpty)
    {
    return 0x000000;
    }
    if (node == grid.startNode || node == grid.endNode)
    {
    return 0x00ff00;
    }
    return 0xffffff;
    }
    private function onStageClickHandler(event:MouseEvent):void 
    var posX:int = Math.floor(mouseX / 20); 
    var posY:int = Math.floor(mouseY / 20);
    grid.setEndNode(posX, posY);
    posX = Math.floor(player.x / 20); 
    posY = Math.floor(player.y / 20); 
    grid.setStartNode(posX, posY);
    drawGrid();
    getPath(); 
    }
    private function getPath():void 
    var astar:AStar = new AStar(); 
    if (astar.findPath(grid))
    path = astar.path; 
    index = 1;
    addEventListener(Event.ENTER_FRAME, onEnterFrameHandler);
    }
    else
    {
    trace("not found the path!!!");
    }
    }
    private function onEnterFrameHandler(e:Event):void 
    {
    var pathX:Number = path[index].x * 20 + 20 / 2;
    var pathY:Number = path[index].y * 20 + 20 / 2;
    var dx:Number = pathX - player.x;
    var dy:Number = pathY - player.y;
    var temp:Number = Math.sqrt(dx * dx + dy * dy);
    if (temp < 1)
    {
    index++;
    if (index == path.length)
    {
    removeEventListener(Event.ENTER_FRAME, onEnterFrameHandler);
    }
    }
    else
    {
    player.x += dx * speed;
    player.y += dy * speed;
    }
    }
    }
    }
    直接编译就能跑了,貌似还不错,呵呵
     
  • 相关阅读:
    【好文收藏】家庭
    CSS选择器
    高等数学
    生也有涯而知也无涯,以有涯应无涯,殆矣
    navicat连接MySQL8+时出现2059错误解决方法
    Python 自己常用的方法
    Vue中变量名前加三个点代表什么意思
    Python3 locals函数的妙用
    python元类的应用
    vue + Element UI 之 rules校验
  • 原文地址:https://www.cnblogs.com/shinings/p/1709268.html
Copyright © 2020-2023  润新知