mmofacts.com

Path finding [js] does not work properly

gepostet vor 12 Jahre, 11 Monate von graczykr

Nun, der Titel sagt mehr oder weniger alles aus. Das Problem ist das Folgende:

Der richtige Weg wird gefunden, jedoch nicht für alle Tiles. Folgendes ist der Code (abgewandelt von http://tonypa.pri.ee/tbw/tut22.html):

Das Problem liegt vermutlich an der "cost" Variable, die verwendet wird, um den günstigesten Weg zu finden (nicht unbedingt kürzesten) sofern dieser Schritt nämlich nicht vorgenommen wird und das Script einfach alle Tiles ausprobiert, funktioniert es einwandfrei.

HTML (Javascript Tag funktioniert nicht):

// path finding module
var path = (function () {
    // nodes which still have to be checked, this array is being filled up
    // constantly while processing all the possible tiles for the path
    var toBeChecked = [];
    // this object contains all the nodes which have already been processed
    // the naming convention for the key is as follows: node_y_x
    var checked = {};
    // map reference
    var tiles = [];
    // array containing the ID's of the walkable nodes
    var walkableTiles = [];

    // checks whether it is possible to step (walkable === true) onto a certain tile
    function walkable (y, x) {
        len = walkableTiles.length;

        while (len--) {
            if (tiles[y][x] === walkableTiles[len]) {
                return true;
            }
        }

        return false;
    }

    // adds a node to the to-check list
    function addNode (node, y, x, endY, endX) {
        var name = 'node_' + y + '_' + x;
        var cost = Math.abs(y - endY) + Math.abs(x - endX);

        if (table[y][x] === 0) {
            // check whether the node has not been visited already
            if (checked['node_' + y + '_' + x] === undefined) {
                // check whether there is any node with higher costs within
                // the toBeCheck array, in case there is, replace it because
                // there is a better option now
                var len = toBeChecked.length;
                while (len--) {
                    if (cost < toBeChecked[len].cost) {
                        delete toBeChecked[len];
                        toBeChecked[len] = {
                            y: y,
                            x: x,
                            parentY: node.y,
                            parentX: node.x,
                            cost: cost
                        }

                        break;
                    }
                }

                // this tile is the most expensive to get at now
                if (len) {
                    toBeChecked.push({
                        y: y,
                        x: x,
                        parentY: node.y,
                        parentX: node.x,
                        cost: cost
                    });
                }
            }
        }
    }

    // returns the path as an array
    // note: parameter node is the final node, the path still is returned in
    // correct order
    function generatePath (node) {
        var way = [];

        while (node.parentY) {
           way.push({
              y: node.y,
              x: node.x
           });
           node = checked['node_' + node.parentY + '_' + node.parentX];
        }

        return way.reverse();
    }

    return {
        init: function (tilesRef, walkableRef) {
            tiles = tilesRef;
            walkableTiles = walkableRef;
        },
        find: function (startY, startX, endY, endX, tilesRef, walkableRef) {
            // reset
            toBeChecked = [];
            checked = {};

            // just for (type)safety reasons
            startY *= 1;
            startX *= 1;
            endY *= 1;
            endX *= 1;

            var cost = Math.abs(startY - endY) + Math.abs(startX - endX);

            // new object on the to-check list
            toBeChecked.push({
                y: startY,
                x: startX,
                parentY: null, // marks the end of the path
                parentX: null,
                cost: cost
            });

            // process list
            while (toBeChecked.length > 0) {
                var node = toBeChecked.shift();

                // node has been checked
                checked['node_' + node.y + '_' + node.x] = node;

                if (node.y === endY && node.x === endX) {
                alert('got');
                    return generatePath(node);
                } else {
                   addNode(node, node.y + 1, node.x, endY, endX);
                   addNode(node, node.y, node.x + 1, endY, endX);
                   addNode(node, node.y - 1, node.x, endY, endX);
                   addNode(node, node.y, node.x - 1, endY, endX);
                }
            }

            // no path
            return false;
        }
    };
}());
HTML:
 
  findPath
  
 
 
  
   
  
  http://code.jquery.com/jquery-1.5.1.min.js">
  
  
    // 1 === wall, 0 === ground
    var table = [
        [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
        [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
        [1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
        [1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
        [1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
        [1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
        [1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
        [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
        [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
    ];

    // character
    var character = {
        y: 1,
        x: 1,
        walking: false
    };

    // draw map
    function generateMapGrid () {
        var size = 20, map = '';

        for (var y = 0; y < table.length; y++) {
            for (var x = 0; x < table[y].length; x++) {
                var top = size * y, left = size * x;
                map += '';
            }
        }

        $('#game').append(map);

        // event handlers for path finding
        $('#game').children().click(function () {
            var parts = $(this).attr('id').split('_'), y = parts[1], x = parts[2];
            var way = path.find(character.y, character.x, y, x);

            if (way) {
                markPath(way);
            }
        });
    }

    // generate character and attach event handlers to it
    function generateCharacter () {
        var top = character.y * 20, left = character.x * 20;
        var html = '';
        $('#game').append(html);
    }

    // color path
    function markPath (way) {
        way.forEach(function (node) {
            $('#tile_' + node.y + '_' + node.x).css('background', '#40d510');
        });
    }

    $(function () {
        path.init(table, [0]);
        generateMapGrid();
        generateCharacter();
    });
  
 

CSS:

body {
    margin: 0px;
    padding: 0px;
}
.tile {
    position: fixed;
    height: 20px;
    width: 20px;
}
.tile_0 {
    background: #ffffff;
}
.tile_1 {
    background: #000000;
}
.character {
    background: #32a303;
}
gepostet vor 12 Jahre, 11 Monate von Todi42

Und beim A* ist es wirklich wichtig, dass die geschätzten Kosten nicht überschätzt werden. Wenn Deine Funktion einen A* implementiert, kannst Du das validieren, in dem Du die Kosten einen Knotens bis zum Ziel mit 0 schätzt. Dann ist der Algorithmus langsamer (das ist dann ein Djikstra), wenn er aber dann fehlerfrei ist, liegt es an der Schätzheuristik.

mfg Todi

gepostet vor 12 Jahre, 11 Monate von rami95

Ich hatte dann irgendwie nurnoch wenig Lust, das Tutorial zu lesen. (Als ich das geklickt hab kam der leicht ersichtliche kürzere Weg noch in Frage, ich habs nur nich geschafft, schnell genug einen Screenshot zu machen).

gepostet vor 12 Jahre, 11 Monate von graczykr

Vielen Dank für eure Antworten, ich sehe mir noch mal an, wie ich das Pseudoscript von Wikipdedia umsetzen könnte.

Auf diese Diskussion antworten