Pathfinding and GameObjects with Velocity

I have an isometric environment in which it is important for my units (gameobjects) to move freely among the tiles and not be constrained to the middle of a tile. I am using velocity, not tweens to move my units around… I am trying to figure out how to get my units to path find properly in this setup, by trying to move to a tile but also be able to collide with non-walkable tiles and other units. I am using easystar so far to accomplish this, but the unit just shoots straight for the destination tile and doesnt move tile to tile around things…

setInterval(function() {	

					if (thisUnit.tileX == targetTileX && thisUnit.tileY == targetTileY) {
					
					thisUnit.setVelocityX(0);
					thisUnit.setVelocityY(0);
					thisUnit.motion = "idle";
					
				}else{

				easystar.findPath(startTileX, startTileY, targetTileX, targetTileY, function( path ) {

                if (path === null) {
        				
	            console.log("No path found. startTileX: "+startTileX+' Y: '+startTileY+' targetTileX: '+targetTileX+' Y: '+targetTileY);
								
    		    }else{
 
			          for (var p = 0; p < path.length; p++)
					  {

							var currentNextPointX = (path[p].y - path[p].x) * tileWidthHalf;
							var currentNextPointY = (path[p].y + path[p].x) * tileHeightHalf;
							var currentCoordX = centerX + currentNextPointX; 
							var currentCoordY = centerY + currentNextPointY; 					
								
							var currentUnitTileX = thisUnit.tileX;
							var currentUnitTileY = thisUnit.tileY;
							
							var angle = Math.atan2(currentCoordX - thisUnit.y, currentCoordY - thisUnit.x);
				
							const direction = Math.atan((currentCoordX - thisUnit.x) / (currentCoordY- thisUnit.y));
							const speed2 = currentCoordY >= thisUnit.y ? speed : -speed;

							var velX = speed2 * Math.sin(direction);
							var velY = speed2 * Math.cos(direction);
								
							var nextTileDistance = Phaser.Math.Distance.Between(thisUnit.x, thisUnit.y, currentCoordX, currentCoordY);
							var intervalCount;	
							
							if (path[p].x == currentUnitTileX && path[p].y == currentUnitTileY) {
								thisUnit.setVelocityX(velX);
								thisUnit.setVelocityY(velY);
								p++; 

							}

							
							
						}
    	
    				}
					
				});
						
				easystar.calculate();

				}
				
					
				},500);

First, why use setInterval? Do you need to recalculate the path twice a second?
Second, the for loop is not very optimal, you’re only interested in 2 tiles. Maybe something like:

create() {
    // create path
    // set unit currentTile and nextTile
}

update() {
    // if unit has a path
    //     check if unit has reached next tile
    //         check if unit has reached last tile
    //             stop
    //         else
    //              p++, set unit currentTile and nextTile, and new direction
}

You’ll have to think of something to determine what ‘reached’ means. You can’t check for an exact x/y match.

So I’ve taken your advice and I think it could work, ive modified my code to suit the suggestion, but its crashing as soon as a movement command is sent, no errors thrown. Maybe you can see what I am doing wrong?

Some more context: I am using EasyStar.js for pathfinding, my iso tiles are based upon matter physics for collisions, and to update my unit’s tile position I am using ‘collisionstart’ once it runs into the tile (this is also how I am handling my depth sorting at the moment, but that is sort of irrelevant here - i think?)

create {

var levelData = [[0,0,1,0,0],
             [1,0,1,0,1],
             [0,0,1,0,0],
             [0,0,1,1,0],
             [0,0,0,0,0]];

var Units = {} //MY COLLECTION OF GAMEOBJECT UNITS
var tileGroup = this.add.group; //MY MATTERJS TILES, OBVIOUSLY

   this.matter.world.on('collisionstart', function (event, tileGroup, Units) {
		
		var currentTileDepth = tileGroup.gameObject.depth; 
		var currentUnitId = Units.gameObject.id;
		var currentUnit = Units.gameObject;
		
		currentUnit.depth = currentTileDepth+64;
		currentUnit.tileX = tileGroup.gameObject.tileX;
		currentUnit.tileY = tileGroup.gameObject.tileY;
		
	}); 

	var easystar = new EasyStar.js();
	easystar.setGrid(levelData);
	easystar.setAcceptableTiles([0]);

    var selectedArray = []; //MY ARRAY OF SELECTED UNITS

    //ATTACK TARGET IS CLICKED
    this.input.setHitArea(tileGroup.getChildren()).on('gameobjectdown', function(pointer, gameObject, scene) {

    	for (var i = 0; i < selectedArray.length; i++)
	    {	
	    const thisUnit = Units[selectedArray[i]];
        thisUnit.motion = "walk";
        thisUnit.path = [];

        startTileX = thisUnit.tileX;
	    startTileY = thisUnit.tileY;
				
		targetTileX = gameObject.tileX;
		targetTileY = gameObject.tileY;

        easystar.findPath(startTileX, startTileY, targetTileX, targetTileY, function( path ) {
				
		  if (path === null) {

          //NO PATH FOUND
		 console.log("No path found. startTileX: "+startTileX+' Y: '+startTileY+' targetTileX: '+targetTileX+' Y: '+targetTileY);
								
    	  }else{
 
		    for (var p = 0; p < path.length; p++)
		    {
            thisUnit.path.push(path[p].x, path[p].y);
            }

        }

    });

    easystar.calculate();

}

}); 

}

update {

for (let q in Units) {

    if (Units[q].motion == "walk") {

    var thisX = Units[q].x;
    var thisY = Units[q].y;
    var tileX = Units[q].tileX;
    var tileY = Units[q].tileY;
    var speed = Units[q].speed;


    //CHECK IF UNIT HAS A PATH
    if (Units[q].path !== null) {

    var currentTile = 0;
				
	    while (currentTile < Units[q].path.length)
	    {
				
	    const centerX = mapWidth * tileWidthHalf;
	    const centerY = 64;

				//CHECK IF UNIT REACHED NEXT TILE
				if (tileX == Units[q].path[currentTile].x && tileY == Units[q].path[currentTile].y) {
					//WE HAVE REACHED THE NEXT TILE, FIND THE NEXT ONE
					currentTile++;
				}else{
					//WE ARE NOT YET AT TILE, SET VELOCITY TO IT
					
					//GET WORLD COORDINATES FROM CURRENT TILE
					var currentNextPointX = (Units[q].path[currentTile].y - Units[q].path[currentTile].x) * tileWidthHalf;
					var currentNextPointY = (Units[q].path[currentTile].y + Units[q].path[currentTile].x) * tileHeightHalf;
					var currentCoordX = centerX + currentNextPointX; 
					var currentCoordY = centerY + currentNextPointY; 					

					var angle = Math.atan2(currentCoordX - thisY, currentCoordY - thisX);

					const direction = Math.atan((currentCoordX - thisX) / (currentCoordY- thisY));
					const speed2 = currentCoordY >= thisY ? speed : -speed;

					var velX = speed2 * Math.sin(direction);
					var velY = speed2 * Math.cos(direction);
					
						Units[q].setVelocityX(velX);
						Units[q].setVelocityY(velY);

				}

        }

    }


    }

}

}

I hope I didn’t miss anything or overwhelm with code. Any advice is appreciated :slight_smile:

var currentTile = 0;			
	    while (currentTile < Units[q].path.length)

This makes no sense. Your code crashes because it never gets out of the while loop. There is no need for a while loop. Store the current and next tile for each unit.
Take a closer look at my advice, and follow it precisely. The biggest problem is your exit condition. As I wrote: ‘You’ll have to think of something to determine what ‘reached’ means. You can’t check for an exact x/y match.’
There is no way that your unit x/y precisely match the tile x/y. So use some sort of range check.

Ok! Some progress, but I am still stuck. I have ditched the while loop, and tried to follow this as closely as I can:

create() {
// create path
// set unit currentTile and nextTile
}

update() {
// if unit has a path
//     check if unit has reached next tile
//         check if unit has reached last tile
//             stop
//         else
//              p++, set unit currentTile and nextTile, and new direction
}

I feel like I am super close, here is where I am at so far:

update () {

//CHECK IF UNIT HAS A PATH
			if (Units[q].path.length > 0) {
				
				var currentTile = 1;
				
				//CHECK IF UNIT REACHED NEXT TILE
				if (tileX == Units[q].path[currentTile].x && tileY == Units[q].path[currentTile].y) {
					
					//WE HAVE REACHED THE NEXT TILE, FIND THE NEXT ONE
					currentTile++;
					console.log('AT SAME TILE');
					
				}else{
					
					//WE ARE NOT YET AT TILE, SET VELOCITY TO IT
					var thisX = Units[q].x;
					var thisY = Units[q].y;

					//GET WORLD COORDINATES FROM CURRENT TILE
					var currentNextPointX = (Units[q].path[currentTile].y - Units[q].path[currentTile].x) * tileWidthHalf;
					var currentNextPointY = (Units[q].path[currentTile].y + Units[q].path[currentTile].x) * tileHeightHalf;
					var currentCoordX = centerX + currentNextPointX; 
					var currentCoordY = centerY + currentNextPointY; 					

					var angle = Math.atan2(currentCoordX - thisY, currentCoordY - thisX);

					const direction = Math.atan((currentCoordX - thisX) / (currentCoordY- thisY));
					const speed2 = currentCoordY >= thisY ? speed : -speed;

					var velX = speed2 * Math.sin(direction);
					var velY = speed2 * Math.cos(direction);

						Units[q].setVelocityX(velX);
						Units[q].setVelocityY(velY);
						
					Units[q].velocityX = velX;
					Units[q].velocityY = velY;
				}
			}
}

The problem now is that it only moves the unit to the first tile in the path array then stops

I still don’t understand how you check for reached, but whatever.

var currentTile = 1; is wrong (and needs to be removed)

In create() you need to store the currentTile for the unit, so something like thisUnit.currentTile = -1; // This is a trick to to start the loop, since you have already reached currentTile + 1.

In update() check if thisUnit has reached thisUnit.currentTile + 1. If not DO NOTHING because it’s moving already! (there is no else in my code).
If you have reached the next tile, check if that happens to be the last tile, then stop.
Otherwise, increase thisUnit.currentTile and set direction.

I am detecting tile collisions with my units to determine reached, like this:

this.matter.world.on('collisionstart', function (event, tileGroup, Units) {
	
	var currentTileDepth = tileGroup.gameObject.depth; 
	var currentUnitId = Units.gameObject.id;
	var currentUnit = Units.gameObject;
	
	currentUnit.depth = currentTileDepth+64;
	currentUnit.tileX = tileGroup.gameObject.tileX;
	currentUnit.tileY = tileGroup.gameObject.tileY;
	
}); 

this updates the unit with tileX and tileY, then I grab this in my update with:

var tileX = Units[q].tileX;
var tileY = Units[q].tileY;

Does that change how this should be implemented? Should I not be doing it this way?

I guess it works, if tileX/Y is the center of the tile,
You can’t stop moving or change course as soon as you collide though, so you’ll still need some more precise check,

ok! my unit is pathfinding, BUT, I error out when I reach the last tile, I cannot seem to figure out why, but I think it has to do with the currentTile count. I think as you said it is something to do with my exit. Here’s where I am at:

create() {

easystar.findPath(startTileX, startTileY, targetTileX, targetTileY, function( path ) {

if (path === null) {

//NO PATH FOUND, LOG IT
console.log("No path found");
					
}else{
						
thisUnit.motion = "walk";
thisUnit.currentTile = -1;
						
    for (var p = 0; p < path.length; p++)
    {
    //PUSH THE PATH STEPS TO AN ARRAY IN UNIT GAMEOBJECT
    thisUnit.path.push(path[p]);	 
    }
						
}
					
});
easystar.calculate();

//DETECT WALKABLE TILE COLLISIONS
this.matter.world.on('collisionstart', function (event, tileGroup, Units) {
		
	var currentTileDepth = tileGroup.gameObject.depth; 
	var currentUnitId = Units.gameObject.id;
	var currentUnit = Units.gameObject;		
		
	if (typeof currentUnit.path == 'undefined') { 
		var nextTileCount = 0;  
	}else{	
			
	//IF AT LAST IN PATH, RESET CURRENT TILE
	if (currentUnit.currentTile+1 == currentUnit.path.length) {
		currentUnit.currentTile = null;
	}
			
	console.log('PATH STARTED!');
	var nextTileCount = currentUnit.currentTile+1;
	var thisPathX = currentUnit.path[nextTileCount].x;
	var thisPathY = currentUnit.path[nextTileCount].y;
			
	if (thisPathX == tileGroup.gameObject.tileX && thisPathY == tileGroup.gameObject.tileY) {
				currentUnit.currentTile++;
	}
			
    }
		
		currentUnit.depth = currentTileDepth+64;
		currentUnit.tileX = tileGroup.gameObject.tileX;
		currentUnit.tileY = tileGroup.gameObject.tileY;
		
		currentUnit.update();
		
	});

}

update () {

for (let q in Units) {
	
		//PREVENT SPRITE ROTATION TO PRESERVE ISO
		Units[q].body.angle = 0;
		
		if (Units[q].motion == "walk") {
			
			var tileX = Units[q].tileX;
			var tileY = Units[q].tileY;
			var theTargetX = Units[q].targetX;
			var theTargetY = Units[q].targetY;
			var currentVelX = Units[q].velocityX;
			var currentVelY = Units[q].velocityY;
			var thisX = Units[q].x;
			var thisY = Units[q].y;
			
			var speed = Units[q].speed;

			const tileWidthHalf = tileWidth / 2;
			const tileHeightHalf = tileHeight / 2;
			const centerX = mapWidth * tileWidthHalf;
			const centerY = 64;
			
			var theCurrentTile = Units[q].currentTile;

			//CHECK IF UNIT HAS A PATH
			if (Units[q].path.length > 0) {
				
				if (typeof theCurrentTile == 'undefined') { 
						//PATH NOT YET DEFINED, STOP
						Units[q].setVelocityX(0);
						Units[q].setVelocityY(0);
						Units[q].motion = 'idle';
						console.log(theCurrentTile);
				
				}else{
					//GET ISO WORLD COORDINATES FROM CURRENT TILE
					var currentNextPointX = (Units[q].path[theCurrentTile+1].y - Units[q].path[theCurrentTile+1].x) * tileWidthHalf;
					var currentNextPointY = (Units[q].path[theCurrentTile+1].y + Units[q].path[theCurrentTile+1].x) * tileHeightHalf;
					var currentCoordX = centerX + currentNextPointX; 
					var currentCoordY = centerY + currentNextPointY; 					
					var angle = Math.atan2(currentCoordX - thisY, currentCoordY - thisX);
					const direction = Math.atan((currentCoordX - thisX) / (currentCoordY- thisY));
					const speed2 = currentCoordY >= thisY ? speed : -speed;

					var velX = speed2 * Math.sin(direction);
					var velY = speed2 * Math.cos(direction);

					Units[q].setVelocityX(velX);
					Units[q].setVelocityY(velY);
					Units[q].velocityX = velX;
					Units[q].velocityY = velY;
			
				}
				
			}
			
		}
	}

}

I have also included a video demonstrating what happens in browser. I am so close to solving this I can taste it! One last attempt at solving this and then I will leave the good people of this forum alone lol

pathfindingerror.mkv (2.1 MB)

I see several problems.

The logging shows 'PATH STARTED!" for ‘CURRENT TILE 4’ twice.
I guess the error is because Units[q].path[theCurrentTile+1].y is 1 too high.

You need an else when you set ’currentUnit.currentTile = null;'

You’re setting the speed and direction 60 times a second. Since you’re not following my example, you’re better off moving everything back to ‘collisionstart’, and not use update(). Only set speed and direction once, and wait for your next collision.

What if you collide with a tile that is not on the path?

I have all but ditched the update () method for this, and found an easier solution that seems to be working thus far (for the most part):

First, I set the unit in motion towards the targeted world coordinates:

			//ATTACK TARGET IS CLICKED
			this.input.setHitArea(tileGroup.getChildren()).on('gameobjectdown', function(pointer, gameObject, scene) {

				var attackX = pointer.worldX;
			    var attackY = pointer.worldY;

				var thisX = thisUnit.x;
				var thisY = thisUnit.y;

				//SET UNIT IN WALKING MOTION
				thisUnit.motion = "walk";

				//SET UNIT'S INITIAL MOTION
				var angle = Math.atan2(attackX - thisY, attackY - thisX);

				const direction = Math.atan((attackX - thisX) / (attackY- thisY));
				const speed2 = attackY >= thisY ? speed : -speed;

				var velX = speed2 * Math.sin(direction);
				var velY = speed2 * Math.cos(direction);

				thisUnit.setVelocityX(velX);
				thisUnit.setVelocityY(velY);
				thisUnit.velocityX = velX;
				thisUnit.velocityY = velY;	

            });

Second, I wait for the unit to collide with a tile, then path find every time a collision occurs. If no path is found, it redirects unit towards the stored target world coordinates. If the unit gets stuck at a tile for more than 5 seconds, it triggers itself stuck, and waits random time between 1-5 seconds to redirect towards target again in attempt to un-stuck itself:

		//DETECT WALKABLE TILE COLLISIONS
	this.matter.world.on('collisionstart', function (event, tileGroup, Units) {
		
		var currentTileDepth = tileGroup.gameObject.depth; 
		var currentUnitId = Units.gameObject.id;
		var currentUnit = Units.gameObject;
		
		currentUnit.depth = currentTileDepth+129;
		currentUnit.tileX = tileGroup.gameObject.tileX;
		currentUnit.tileY = tileGroup.gameObject.tileY;		

		console.log('COLLISION. TILE DEPTH: '+currentTileDepth);
		
		if (currentUnit.tileX == currentUnit.targetTileX && currentUnit.tileY == currentUnit.targetTileY) {
			//REACHED TARGET TILE, STOP UNIT
			currentUnit.motion = "idle";
			currentUnit.setVelocityX(0);
			currentUnit.setVelocityY(0);
			currentUnit.update();
			console.log("REACHED DESTINATION");
		}
		
		if (currentUnit.stuckTrigger == true) {
		//UNIT IS STUCK, WAIT RANDOM TIME BETWEEN 1-5 SECONDS FOR IT TO CLEAR TRIGGER
		var randomSeconds = Math.floor(Math.random() * 4999) + 1000;
		var randomWait = currentUnit.speed * randomSeconds;
		
			setTimeout(function() {
				console.log('UNIT STUCK, WAITING FOR REVERSE MOVEMENT. RANDOM WAIT: '+randomWait);
				currentUnit.stuckTrigger = false;
				
			}, randomWait);
			
		}else{
		
		if (currentUnit.motion == "walk" && currentUnit.groundType == true) {
		
			//STORE TILE TO CHECK AGAIN
			let lastTileX = currentUnit.tileX;
			let lastTileY = currentUnit.tileY;
			
		setTimeout(function() {
		//UNIT IS STUCK WALKING ON TILE FOR MORE THAN 5 SECONDS, REDIRECT
			if (lastTileX == currentUnit.tileX && lastTileY == currentUnit.tileY) {
			//UNIT IS ON SAME TILE, SEND OPPOSITE DIRECTION OF TARGET
				
				var attackX = currentUnit.targetX;
				var attackY = currentUnit.targetY;
				var thisX = currentUnit.x;
				var thisY = currentUnit.y;
				var speed = currentUnit.speed;
				
				var angle = Math.atan2(attackX - thisY, attackY - thisX);

				const direction = Math.atan((attackX - thisX) / (attackY- thisY));
				const speed2 = attackY >= thisY ? speed : -speed;
				
				//var randomVelocity = Math.random() * -1;

				//REVERSED VELOCITY
				var velX = (speed2 * Math.sin(direction)) * -1;
				var velY = (speed2 * Math.cos(direction)) * -1;

				currentUnit.setVelocityX(velX);
				currentUnit.setVelocityY(velY);
				currentUnit.velocityX = velX;
				currentUnit.velocityY = velY;
				
				currentUnit.stuckTrigger = true;
				
				currentUnit.update();
			}
			
		}, 5000);
		
		currentUnit.path = [];
					
		easystar.findPath(currentUnit.tileX, currentUnit.tileY, currentUnit.targetTileX, currentUnit.targetTileY, function( path ) {
			
			if (path === null) {
			
			//NO PATH FOUND, SEND TOWARDS TARGET AGAIN
			console.log("NO PATH, REDIRECT TO TARGET. Current X: "+currentUnit.tileX+' Y: '+currentUnit.tileY+' targetTileX: '+currentUnit.targetTileX+' Y: '+currentUnit.targetTileY);
				
				var attackX = currentUnit.targetX;
				var attackY = currentUnit.targetY;
				var thisX = currentUnit.x;
				var thisY = currentUnit.y;
				var speed = currentUnit.speed;
				
				var angle = Math.atan2(attackX - thisY, attackY - thisX);

				const direction = Math.atan((attackX - thisX) / (attackY- thisY));
				const speed2 = attackY >= thisY ? speed : -speed;

				var velX = speed2 * Math.sin(direction);
				var velY = speed2 * Math.cos(direction);

				currentUnit.setVelocityX(velX);
				currentUnit.setVelocityY(velY);
				currentUnit.velocityX = velX;
				currentUnit.velocityY = velY;	
				
				

			}else{

				currentUnit.motion = "walk";

				for (var p = 0; p < path.length; p++)
				{
					currentUnit.path.push(path[p]);	
				}

				//PATH SET UP, MOVE TO FIRST TILE
				var thisX = currentUnit.x;
				var thisY = currentUnit.y;

				var nextTargetX = currentUnit.path[1].x;
				var nextTargetY = currentUnit.path[1].y;

				var speed = currentUnit.speed;

				const tileWidthHalf = tileWidth / 2;
				const tileHeightHalf = tileHeight / 2;
				const centerX = mapWidth * tileWidthHalf;
				const centerY = 64;

					//GET WORLD COORDINATES FROM CURRENT TILE
					var currentNextPointX = (nextTargetY - nextTargetX) * tileWidthHalf;
					var currentNextPointY = (nextTargetY + nextTargetX) * tileHeightHalf;
					var currentCoordX = centerX + currentNextPointX; 
					var currentCoordY = centerY + currentNextPointY; 					

					var angle = Math.atan2(currentCoordX - thisY, currentCoordY - thisX);

					const direction = Math.atan((currentCoordX - thisX) / (currentCoordY- thisY));
					const speed2 = currentCoordY >= thisY ? speed : -speed;

					var velX = speed2 * Math.sin(direction);
					var velY = speed2 * Math.cos(direction);

					currentUnit.setVelocityX(velX);
					currentUnit.setVelocityY(velY);
					currentUnit.velocityX = velX;
					currentUnit.velocityY = velY;	

			}

		});

		easystar.calculate();

		console.log('Target Tile X: '+currentUnit.targetTileX+' Y: '+currentUnit.targetTileY);

		currentUnit.update();
			
		}
			
		}
			
		
	});

The only thing I am doing in the update() section is maintaining the unit’s velocity so that it doesnt slow down, like this:

 update () {

		for (let q in Units) {
	
		//PREVENT SPRITE ROTATION TO PRESERVE ISO
		Units[q].body.angle = 0;
		
		if (Units[q].motion == "walk") {
			
			if (Units[q].velocityX !== 'undefined' && Units[q].velocityY !== 'undefined') {
			
			var currentVelX = Units[q].velocityX;
			var currentVelY = Units[q].velocityY;
			
			Units[q].setVelocityX(currentVelX);
			Units[q].setVelocityY(currentVelY);
				
		}
	}

}

My EasyStar config:

	//EASYSTAR PATHFINDING
	var easystar = new EasyStar.js();
	easystar.setGrid(levelData);
	easystar.setAcceptableTiles([0, 1, 2, 4, 5, 6, 7, 8]);

(My grass tiles are 1-8)

This seems to work fine in most cases, and it’s the best I’ve got so far, but occasionally the unit gets stuck in corners in strange loops.

What I am wondering is why the unit gets stuck at all… Isn’t the purpose of pathfinding to avoid tiles that will get it stuck in the first place? It’s as if the unit is trying to cut through corners in it’s path, and sometimes it just bounces around in the same tile.

Here it is working as intended:
pathfindingworking.mkv (2.2 MB)

And here it is looping:
pathfindingbadloop.mkv (1.8 MB)

Is there a feature of EasyStar that I can enable to prevent what is happening or am I still missing something entirely?

Also the live demo is at astralforge.net

You’ve lost me completely. Try to show your code in written language (pseudocode), similar to my first suggestion. There is no way I can make sense of this flow.
Use graphical debugging to show your path and which tiles are colliding.

Yes, but you’re not avoiding them. If you would move your unit only on exact tile positions it would not get stuck.

Here’s the Phaser pathfinding tutorial using velocity instead of tweens. The changes are trivial.

Is that example not from this tutorial?

They use tweens here…

Yeah, if you look at the source you’ll see I changed it to velocity. It would need some work to make clicking a new path a bit smoother, but it’s just to show my approach.

I liked your example script, looks great, but under further investigation I think the issue is with the pathfinding itself… I threw together a little script that highlights the path tiles in red, and as you can see in this video, its as if my pathfinding is ignoring the setAcceptableTiles i’ve set and going right through my water tiles:

pathfindinghighlighting.mkv (2.2 MB)

	var easystar = new EasyStar.js();
	easystar.setGrid(levelData);
	easystar.setAcceptableTiles([0, 1, 2, 4, 5, 6, 7, 8]);

(my water type tiles are 9 and above)

More debugging :slight_smile: Show the tile types on the map. See if water actually shows up as 9.

So I have added more debugging to check the tiletype, and indeed, the tiletypes are as they should be… video here:
pathfindwithtiletype.mkv (2.9 MB)

I even limited the acceptable tiles to only the plain grass type:

easystar.setAcceptableTiles([0]);

And pathfinding appears to ignore that as well…

I don’t see it. I meant more like this. Actually show the tile type on the tile.
Obviously there is a problem because your path keeps changing. That shouldn’t happen.

Maybe put your project on github? If we get the whole thing it’s easier to point out what’s going wrong…

I will work on getting it up on github today (first timer here lol) so link to follow, but in regards to your pseudocode suggestion, this is sort of where things are at (forgive me, this is my first stab as pseudocode too):

create () {

// target clicked, target coords stored in unit object, store velocity in game object as target
// if tile collision occurs
//     check if path to target found
//        velocity stored in game object as 1st tile in path
//     else
//        velocity stored in game object as target tile (in hopes of new collision)

}


update() {
// constantly set velocity as unit gameobject's stored velocity
}

this will require additional tweaking, but in this way my hope is that a new path is recalculated after each tile collision, a play on Starcraft’s pathfinding algo (sort of) an idea I got from this blog where the best path is recalculated constantly