Making an entity follow pathfinding path array

Hey folks!

So I have an entity at 10, 5 (middle of the map) and want him to follow my already generated path of values ([10, 4], …, [10, 0], [9, 0], …, [0, 0]) but seem to be getting stuck with axis-fighting.

The entity will go to one side and then ping-pong between points and so on. I can get the entity to go to say 0,0 as an end point, but putting it at 20, 0 will make it still go to the left side as if the point was 0, 0.

Any help on making an entity follow a 2D pre-generated path would be appreciated.

could you please give us a code to understand ?

Basic procedural code as mine is useless and doesn’t seem to work…

I am using simple if/ifelse statements to check if the next path value is greater/less than.


for (int p = 0; p < path.length; p++) {
    if (path[p][0] < this.currentX) {
        // move direction
    }

    if (path[p][1] < this.currentY) {
        // move direction
    }
}

path[p] == current path being looped through (1, 0 for example)

path[p][0] == x value of path (1)
path[p][1] == y value of path (0)

If that represents your actual code, maybe you should check …[1] against y and not against x.

My bad, a typo when typing up the procedural code. Not actual code :slight_smile:

Here is an generic entity which follows a set of waypoints:


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import pojahn.game.core.Collisions;
import pojahn.game.core.MobileEntity;
import pojahn.game.events.Event;

import com.badlogic.gdx.math.Vector2;

public class PathDrone extends MobileEntity {

    public static class Waypoint {

        public final float targetX, targetY;
        public final int frames;
        public final boolean jump;
        public final Event event;

        public Waypoint(float targetX, float targetY, int frames, boolean jump, Event event) {
            this.targetX = targetX;
            this.targetY = targetY;
            this.frames = frames;
            this.jump = jump;
            this.event = event;
        }

        public Waypoint(float targetX, float targetY) {
            this(targetX, targetY, 0, false, null);
        }
    }

    private List < Waypoint > waypoints;
    private int dataCounter, stillCounter;
    private boolean playEvent;

    public PathDrone(float x, float y) {
        move(x, y);
        waypoints = new ArrayList < > ();
        dataCounter = stillCounter = 0;
    }

    public void appendPath(float x, float y, int frames, boolean jump, Event event) {
        waypoints.add(new Waypoint(x, y, frames, jump, event));
    }

    public void appendPath(Vector2 loc, int frames, boolean jump, Event event) {
        waypoints.add(new Waypoint(loc.x, loc.y, frames, jump, event));
    }

    public void appendPath(Waypoint pd) {
        waypoints.add(pd);
    }

    public void appendPath(Waypoint[] list) {
        waypoints.addAll(Arrays.asList(list));
    }

    public void appendPath(float x, float y) {
        appendPath(x, y, 0, false, null);
    }

    public void appendPath() {
        waypoints.add(new Waypoint(x(), y(), 0, false, null));
    }

    public void appendReversed() {
        List < Waypoint > reversed = new ArrayList < > (waypoints);
        reversed.remove(reversed.size() - 1);
        Collections.reverse(reversed);

        waypoints.addAll(reversed);
    }

    public void clearData() {
        waypoints.clear();
        rollback();
    }

    public void rollback() {
        dataCounter = stillCounter = 0;
    }

    @Override
    public void logistics() {
        if (!waypoints.isEmpty() && getMoveSpeed() > 0) {
            if (dataCounter >= waypoints.size())
                dataCounter = 0;

            Waypoint wp = waypoints.get(dataCounter);

            if (reached(wp)) {
                if (++stillCounter > wp.frames)
                    dataCounter++;

                x = wp.targetX;
                y = wp.targetY;

                if (playEvent && wp.event != null) {
                    wp.event.eventHandling();
                    playEvent = false;
                }
            } else {
                playEvent = true;
                stillCounter = 0;

                if (wp.jump) {          
                    x = wp.targetX;          
                    y = wp.targetY;        
                } else
                    moveTowards(wp.targetX, wp.targetY);
            }
        }
    }

    protected boolean reached(Waypoint pd) {
        return getMoveSpeed() > Collisions.distance(pd.targetX, pd.targetY, x(), y());
    }

    protected void moveTowards(float targetX, float targetY) {  
        float fX = targetX - x();  
        float fY = targetY - y();  
        float dist = (float) Math.sqrt(fX * fX + fY * fY);  
        float step = movespeed / dist;

          
        x += fX * step;
        y += fY * step);
}
}

You can use it like this:

PathDrone pd = new PathDrone();
pd.appendPath(10, 4);
pd.appendPath(10, 0);
pd.appendPath(9, 0);
pd.appendPath(0, 0);

logictics should you call every frame in your game loop.

What about the other directions?


    if (path[p][0] < this.currentX) {
        // move direction
    } else if (path[p][0] > this.currentX) {

    }

    if (path[p][1] < this.current) Y{
        // move direction
    } else if (path[p][1] > this.currentY) {

    }

Only included them directions as an example, if I can get 2 directions working out of 4, the other 2 won’t be any harder to implement than the first 2.

Well I don´t assume anything. I have seen too many times that a simple mistake was the cause of a bug. :wink:
Could you show us some more code or debug values?

Sure thing: Click here

cube.x = Math.max(cube.x - 0.5, path[ x ][1]);

cube.x = Math.min(cube.x + 0.5, path[ x ][1]);

If I’m understanding that correctly, it would instantly put the entity at said position and not gradually. The position is also divided by 10 to keep it within the walls of the level.

No it won’t if placed correctly.
if (path’s x < entityx)
decrease entityx by 0.5 (still bigger than path’s x)
or
if entityx-0.5 is smaller than path’s x then use path’s x
This is to prevent the ping pong effect.

Oh I see, thank you! :slight_smile: