1
\$\begingroup\$

In HaxeFlixel 4 all FlxObjects have a path property which must be a FlxPath instance

class FlxObject extends FlxBasic
{
    ...
    /**
     * The path this object follows.
     */
    public var path(default, set):FlxPath;
    ...

a tilemap can be used to find a path

var points:Array<FlxPoint> = tileMap.findPath(pathStart, pathEnd);

and then an object can walk that path

object.path = new FlxPath();
object.path.start(points);

What I want to do is run some custom code when the path ends, whether it was cancelled or was fully completed

what I see others do is this (player being the object in question)

override public function update(elapsed:Float):Void
{
    if(Std.is(player.path, FlxPath)){
        if (player.path.finished || player.path.nodes==null) {
            trace('finished walking');
        }
    }

But this tends to run indefinitely once the player has finished walking, yet I want it to run once. Secondly I don't even want the PlayState update function to be aware that there was an event where the player finished walking, it's none of it's business unless I tell it that it happened, I want this code block to be self-contained.

I discovered that FlxPath has an onEnd function, which is exactly what I need, but it does not call any callback, neither are there any ways that I know of to attach it, there is also the onComplete property, but I was not able to make use of it.

so here is what I'd ideally like

object.path = new FlxPath();
object.path.start(points, function(cancelled){
    trace((cancelled) ? 'path cancelled': 'path completed');
});

and this would run only once upon the path ending or getting cancelled

any ideas on some way of achieving this?

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

For now I have solved it in the following manner

in the PlayState class I added a function to move objects and an array to track what objects are currently moving

class PlayState extends FlxState
{

    public var TILE_WIDTH:Int = 16;
    public var TILE_HEIGHT:Int = 16;

    // since flixel pathfinding does not have an onComplete callback, lets add it ourselves!
    // this variable will hold the objects that are currently walking a path
    // the update function will track when the path was finished and remove the object from the list
    public var walkingPath:Array<Dynamic> = new Array();


    /**
     * Function that is called once every frame.
     */
    override public function update(elapsed:Float):Void
    {
        // track which objects are currently walking a path
        trackWalkingObjects();

        super.update(elapsed);
    }

    /**
     * Maintain a list of objects that are currently walking a path
     */
    public function trackWalkingObjects(){
        var i:Int = walkingPath.length, data:Array<Dynamic>, object:FlxObject, callback:FlxObject->Dynamic = null;

        // loop over the objects in the walkingPath array
        // each item will contain array with an object and callback variable
        while (i-- > 0) {
            data = walkingPath[i];
            callback = data[1];
            object = data[0];

            // check if there are any path to walk, nodes to walk or if the path has finished
            // if so, then the object is no longer walking and should be removed from the array
            if (!Std.is(object.path, FlxPath) || object.path.nodes == null || object.path.finished) {
                if(callback != null){
                    callback(object);
                }
                walkingPath.splice(i, 1);
            }
        }
    }

    /**
      * Simplify the pathfinding mechanism
      * Use as: walkTo(player, targetPoint, function(player){ trace(player, 'has finished the path'); })
      * @param  object
      * @param  targetPoint
      * @param  callback
      * @return FlxPath
      */
    public function walkTo(object:FlxObject, targetPoint:FlxPoint, ?callback = null)
    {
        // should pass around positions not coordinates
        // should have a function to snap to tile to avoid rounding, best if it's in the Position object?
        var tileCoordX:Int = Math.floor(targetPoint.x / TILE_WIDTH);
        var tileCoordY:Int = Math.floor(targetPoint.y / TILE_HEIGHT);

        if (tileMap.getTile(tileCoordX, tileCoordY) == 2) {
            var pathStart = FlxPoint.get(object.x + TILE_WIDTH / 2, object.y + TILE_HEIGHT/2);
            var pathEnd = FlxPoint.get(tileCoordX * TILE_WIDTH + TILE_WIDTH / 2, tileCoordY * TILE_HEIGHT + TILE_HEIGHT / 2);

            var points:Array<FlxPoint> = tileMap.findPath(pathStart, pathEnd);
            if (points != null) {
                object.path = new FlxPath();
                object.path.start(points);

                // add the object to be tracked for when it finishes walking
                walkingPath.push([object, callback]);
            }
        }

        return object.path;
    }
}

now I can just call this and be done with it

walkTo(player, targetPoint, function(player){
    trace(player, 'has finished the path');
});
player.path.speed = 300;

Since I am a beginner at haxe and flixel (2 days worth), any other answers are still appreciated!

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .