Jul 9, 2013

Goal based vector field pathfinding in Haxe

Here is nothing to say. Everything was clearly described here.
Here is jus my code in haxe implementing GBVF pathfinding class.
package com.nailedgames;

import flash.geom.Point;


typedef PathTile = {
    var x:Int;
    var y:Int;
    var step:Int;
}

class GBVF_pathfinding
{
    private var _tile_width:Int;
    private var _tile_height:Int;
    private var _field_width:Int;
    private var _field_height:Int;
    private var _field_wtiles:Int;
    private var _field_htiles:Int;

    private var _distances:Array<Int>;
    private var _vectors:Array<Point>;

    public var vectors(get,null):Array<Point>;

    public function new()
    {

    }

    function get_vectors():Array<Point>
    {
        return _vectors;
    }

    public function Init(tile_width:Int, tile_height:Int, field_width:Int, field_height:Int)
    {
        _tile_width = tile_width;
        _tile_height = tile_height;
        _field_width = field_width;
        _field_height = field_height;
        _field_wtiles = Std.int(field_width/tile_width);
        _field_htiles = Std.int(field_height/tile_height);
        _distances = new Array();
        for(i in 0..._field_htiles)
            for(j in 0..._field_wtiles)
                _distances.push(-1);

    }

    public function Calculate_field(walls_map:Array<Int>, x_block:Int, y_block:Int):Array<Point>
    {
        for(i in 0..._distances.length)
            if(walls_map[i] == 1)
                _distances[i] = -3;
            else
                _distances[i] = -1;
        Mark_tiles([{x:x_block, y:y_block, step:0}]);
        return _vectors;
    }

    private function Mark_tiles(points:Array<Pathtile>):Void
    {
        if(Lambda.empty(points))
            return;
        var neighbours:Array<Pathtile> = new Array<Pathtile>();
        for(point in points)
        {
            _distances[point.x + point.y*_field_wtiles] = point.step;
            if(point.x > 0)
            {
                if(_distances[(point.x-1) + point.y*_field_wtiles] == -1)
                {
                    neighbours.push({x:point.x-1, y:point.y, step:point.step+1});
                    _distances[(point.x-1) + point.y*_field_wtiles] = -2;
                }
            }
            if(point.x < (_field_wtiles-1))
            {
                if(_distances[(point.x+1) + point.y*_field_wtiles] == -1)
                {
                    neighbours.push({x:point.x+1, y:point.y, step:point.step+1});
                    _distances[(point.x+1) + point.y*_field_wtiles] = -2;
                }
            }
            if(point.y > 0)
            {
                if(_distances[point.x + (point.y-1)*_field_wtiles] == -1)
                {
                    neighbours.push({x:point.x, y:point.y-1, step:point.step+1});
                    _distances[point.x + (point.y-1)*_field_wtiles] = -2;
                }
            }
            if(point.y < (_field_htiles-1))
            {
                if(_distances[point.x + (point.y+1)*_field_wtiles] == -1)
                {
                    neighbours.push({x:point.x, y:point.y+1, step:point.step+1});
                    _distances[point.x + (point.y+1)*_field_wtiles] = -2;
                }
            }
        }
        Mark_tiles(neighbours);
        Assign_vectors();
    }

    private function Assign_vectors():Void
    {
        _vectors = new Array<Point>();
        for(y_tile in 0..._field_htiles)
        {
            for(x_tile in 0..._field_wtiles)
            {
                if(_distances[x_tile + y_tile*_field_wtiles] > 0)
                {
                    var left_dist:Int   = _distances[x_tile + y_tile*_field_wtiles]+1;
                    var right_dist:Int  = _distances[x_tile + y_tile*_field_wtiles]+1;
                    var up_dist:Int     = _distances[x_tile + y_tile*_field_wtiles]+1;
                    var down_dist:Int   = _distances[x_tile + y_tile*_field_wtiles]+1;

                    if((x_tile > 0) && (_distances[(x_tile-1) + y_tile*_field_wtiles] >= 0)) 
                        left_dist = _distances[(x_tile-1) + y_tile*_field_wtiles];

                    if((x_tile < (_field_wtiles-1)) && (_distances[(x_tile+1) + y_tile*_field_wtiles] >= 0)) 
                        right_dist = _distances[(x_tile+1) + y_tile*_field_wtiles];

                    if((y_tile > 0) && (_distances[x_tile + (y_tile-1)*_field_wtiles] >= 0))
                        up_dist = _distances[x_tile + (y_tile-1)*_field_wtiles];

                    if((y_tile < (_field_htiles-1)) && (_distances[x_tile + (y_tile+1)*_field_wtiles] >= 0))
                        down_dist = _distances[x_tile + (y_tile+1)*_field_wtiles];

                    _vectors.push(new Point(
                        left_dist - right_dist,
                        up_dist - down_dist));
                }else{
                    _vectors.push(new Point(0,0));
                }
            }
        }

    }
}
Here is usage example:
var tile_width:Int = 40;
var tile_height:Int = 40;
var field_width:Int = 800;
var field_height:Int = 600;
gbvf = new GBVF_pathfinding();
walls_map = [
 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,
 0,0,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,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,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,0,0,0,0,0,1,0,0,0,0,0,0,
 0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,
 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,
 0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,
 ];
gbvf.Init(tile_width, tile_height, field_width, field_height);
var vectors:Array<Point> = gbvf.Calculate_field(walls_map, x_block, y_block);
As a result you will have array of vectors coordinates relative to the center of tiles.

No comments:

Post a Comment