zoukankan      html  css  js  c++  java
  • 如何在MONO 3D寻找最短路路径

    前段时间有个客户说他们想在我们的3D的机房中找从A点到B点的最短路径,然而在2D中确实有很多成熟的寻路算法,其中A*是最为常见的,而这个Demo也是用的A*算法,以下计算的是从左上角到右下角的最短路径:
    左上
    具体的实现方式是,先将地板进行了分割,分成一个数组,然后再计算该点上是否有3D的对象,若是有,就置成该点不能通过的标记,否则就表示该点可以通过(如果你分割的越细那么算的就越精确,但是算的当然也就慢一些,关键看你的要求),以下是分割地板的代码:

    var size = {x: 100, y: 100}; // 100*100
    var topLeft = {x: 228, y: 53};
    var width = 524;
    var height = 400;
    var dw = width / size.x;
    var dh = height / size.y;
    var start;
    var end;
    var graph;
    function to2d() {
        var nodes = [];
        for (var i = 0; i < size.x; i++) {
            var nodeRow = [];
            var x = topLeft.x + dw * i
            for (var j = 0; j < size.y; j++) {
                var y = topLeft.y + dh * j;
                if (isHasObj(x, y)) { //判断该点上是否有物体
                    nodeRow.push(0);
                } else {
                    nodeRow.push(1);
                }
            }
            nodes.push(nodeRow);
        }
        graph = new Graph(nodes, {
            closest: null,
            diagonal: false
        });
    
        //这里是找一条从(0,0)到(79,80)的路径。
        start = graph.grid[0][0];
        drawPath(79, 80);
    }

    分割好地板后就相当于将3D中的寻路转换成了2D中的寻路,此时就可以直接使用A*算法来进行寻路了,这里的A*寻路算法如下:

    function  search(graph, start, end, options) {
            astar.init(graph);
    
            options = options || {};
            var heuristic = options.heuristic || astar.heuristics.manhattan,
                closest = options.closest || false;
    
            var openHeap = getHeap(),
                closestNode = start; // set the start node to be the closest if required
    
            start.h = heuristic(start, end);
    
            openHeap.push(start);
    
            while(openHeap.size() > 0) {
    
                var currentNode = openHeap.pop();
    
                if(currentNode === end) {
                    return pathTo(currentNode);
                }
    
                // Normal case -- move currentNode from open to closed, process each of its neighbors.
                currentNode.closed = true;
    
                // Find all neighbors for the current node.
                var neighbors = graph.neighbors(currentNode);
    
                for (var i = 0, il = neighbors.length; i < il; ++i) {
                    var neighbor = neighbors[i];
    
                    if (neighbor.closed || neighbor.isWall()) {
                        // Not a valid node to process, skip to next neighbor.
                        continue;
                    }
                    var gScore = currentNode.g + neighbor.getCost(currentNode),
                        beenVisited = neighbor.visited;
    
                    if (!beenVisited || gScore < neighbor.g) {
    
                        neighbor.visited = true;
                        neighbor.parent = currentNode;
                        neighbor.h = neighbor.h || heuristic(neighbor, end);
                        neighbor.g = gScore;
                        neighbor.f = neighbor.g + neighbor.h;
    
                        if (closest) {
                           
                            if (neighbor.h < closestNode.h || (neighbor.h === closestNode.h && neighbor.g < closestNode.g)) {
                                closestNode = neighbor;
                            }
                        }
    
                        if (!beenVisited) {
                            // Pushing to heap will put it in proper place based on the 'f' value.
                            openHeap.push(neighbor);
                        }
                        else {
                           openHeap.rescoreElement(neighbor);
                        }
                    }
                }
            }
    
            if (closest) {
                return pathTo(closestNode);
            }
    
            return [];
        }

    看似实现了,如果你细心的话,你可以会发现在3D中存在类似像门那样的可以穿过的物体,或者说有两层楼,那这就不好转换了,确实是存在这样的问题,但是我们可以改进isHasObj这个方法,假如我们寻路的是一个人的话,那么我们人是有高度的,设置高度为man.height,我们判断某点上是否存在物体的话,然后在该点上“发射”一条Ray的方式(具体实现牵涉到一些数学知识,这里不多讲,下次可以单独弄了blog讲解),然后会返回的参数中有一个“距离”的属性,该属性就是我们地板上的点到该点上面那个物体的距离,因此我们可以通过这个距离来和man的身高的关系来确定该点是否可以通过,代码如下:

    function isHasObj(x, y) {
        var obj = getElementsByPosition(x, y);
        if (obj && obj.length > 1) { //length > 1, bc is must a obj that is shapenode
            for (var i = 0; i < obj.length; i++) {
                if (obj[i] && !(obj[i].element instanceof mono.ShapeNode) && obj[i].element != man) {
                    if (isCheckHeight) {
                        console.log("x:" + x + ";y:" + y + ";distance:" + obj[i].distance);
                        if (obj[i].distance < (man.height + 10)) {
                            return true;
                        } else {
                            return false;
                        }
                    } else {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    如下是通过一个ShapePath这样的物体:
    cross a Path

    该Demo主要是想表达这个意思,美化方面还有改进的空间,比如可以考虑用我们的mono创建一个人的模型,还可以去判断该通过物体的宽度等等!
    

  • 相关阅读:
    js文件内部导入引用js文件方法
    CSS3.0动画之hover---Y轴----3D旋转
    静态的html页面想要设置使用浏览器缓存
    opener 属性是一个可读可写的属性,可返回对创建该窗口的 Window 对象的引用
    input获取永久焦点
    修改zepto源代码,使支持wp8的ie10
    EChart
    input属性disabled和readonly的区别
    trigger
    解决jquery mobile的遇到高版本Chrome一直转圈,页面加载不出来的情况。
  • 原文地址:https://www.cnblogs.com/twaver/p/4136883.html
Copyright © 2011-2022 走看看