Use with non-terrain?

I have a 2D campaign map texture similar to this
https://assetstore.unity.com/packages/2d/textures-materials/world-map-high-quality-hand-drawn-100561

The player clicks where they want to move, and I move a sprite to that area.

I want to move slower through trees and mountains, faster on plains, fastest on roads. Certain areas may be impassible.

Can I use A* Pathfinding Project with something like this, that is entirely in 2D UI, but still needs pathfinding? If so, how should I define movement speeds in a way that A* Pathfinding Project can use them?

Hi

Yes, you could for example use the texture feature of the grid graph.

1 Like

Awesome! I wasn’t expecting support for this so it’s great you already have something ready to go.

The interface is not the best though. I wrote that a looong time ago and very few users use it.

So this is a 2D UI - I wasn’t planning on having any objects in the scene besides the UI. But it looks like I need to in order to use the texture with the Grid Graph

  1. I should create a plane that matches the dimensions of the screen?
  2. Turn off collision and height testing, as they are not relevant?
  3. Should I check 2D physics?
  4. Under advanced, what does Generate Reference do?
  5. Any other settings you recommend for this use case?

Hi

You can turn off collision and height testing, 2D physics will not matter as you are not using collision/height testing.
Generate reference creates a reference image with the current position/walkability etc. of the graph color coded so that if you are creating the texture manually, you have somewhere to start from.

Generally the ‘factor’ preference for penalty should likely be higher than you think it should be initially :stuck_out_tongue:

Lots of deleting and restoring the message going on here :stuck_out_tongue:

Are you caching the texture in some way? I’m getting issues related to it not updating after I change the texture. I was just about to upload a bug report to you, changed the texture in photoshop, and suddenly the graph changed although it didn’t change the last 10 times I rescanned it. I don’t have the screenshot anymore but it was zoomed in on the texture and I couldn’t get it to zoom out

I don’t do any caching. Scanning the graph should read everything from scratch. Unless Unity does some caching, but I don’t think so (or at least it knows when to reload it).
Very few users use this feature though, so it is possible it has been subtly broken at some point, but I haven’t seen any reports of it.

I got a screenshot this time, after reloading the unity client. It was showing a more zoomed in graph the prior time when I shut it down.

Note that in this screenshot it’s still wrong

  • EDIT *

I think I understand now. The width and depth have to match the resolution of the texture.

Yes, each pixel corresponds to one node.

This took a lot of effort so here are instructions in case it helps anyone else

How to create a world map with pathfinding

Create a camera with projection Orthographic
Set the size to half as high as you want the world to be. For example, if the world is 2048 high, then size should be 1024
Set the camera position to 0,0,-1

Create a Unity plane. Set the rotation to -270,-90,90.
The Unity plane is 10x10. So set the scale to 1/10th as large as the world should be. In this case I made the world the same size as the source texture. The source texture is 4096x2048, so I set scale to 409.6,1,204.8
Drag the source texture onto the Unity Plane.
Use shader Unlit/Texture

Create a pathfinding texture. The pathfinding texture match the resolution that you want the pathfinding to work at. The source texture size of 2048x1024 is too large, as it slows down the system by too much. So I downsized it to 512x256.
Using red as walkable
In Photoshop, go to select / color range. Click on the areas that should be walkable, which presumably have a similar color.
In Photoshop, go to layer / new adjusment layer / color balance. Change midtones / highlights / shadows to red (there may be a better way to do this)
Save this to Resources.

Create a Grid Graph with AStar Path.
Select 2D.
Set width to the width of the pathfinding texture (512 in my case)
Set height to the height of the pathfinding texture (256 in my case)
Set node size to the source texture size divided by the pathfinding texture size. In my case this is 4096/512 = 8. Obviously you have to divide by the same factor for both width and height in this case.
Turn off collision testing and height testing.
Under advanced, click Penalty Modifications.
Select Use Texture
Select your pathfinding texture
Set source to R,G, or B
Select Walkability and Penalty
Set factor to 1 (DON’T FORGET THIS)
To check if it worked, click settings, debug, graph coloring, and then penalty.

Scan.

2 Likes

Some quick questions if you don’t mind.

“If channel ‘R’ is 0 the node is unwalkable. Otherwise the node is applied penalty multiplied with factor.”

My interpretation of that sentence is using a factor of 1, that would mean 0 is unwalkable, 1/256 has a very small penalty, and 256/256 has the full penalty. And my interpretation seems seems to be correct if you look at the coloring of the graph, if you assume green means more walkable.

Shouldn’t it be the inverse of that? If I’m painting in photoshop and I’m using (black / no red) to mean unwalkable, then a value of 1/256 (almost black / barely red) should mean almost full penalty, not full walkability.

In other words:
Current: penalty = factor * pixel/256
Expected: penalty = factor * (1 - pixel/256)

The image in photoshop, where the outer areas have 0 red, and the most walkable areas have 256 red.

Secondly, I want the units’ maximum speed to be whatever their normal maximum speed is, multiplied by the walkability of wherever they happen to be standing. However, the penalty value seems to be stored in the graph node itself, which isn’t publicly accessible through AIPath. Suggestions?

Hi

The formula that is used is roughly

if (value == 0) make node unwalkable;
else node.penalty = value * factor;

Where value is the raw pixel value (i.e from 0 to 255). I really should reword that to make it easier to understand.

Well, there is some benefit to be able to easily differentiate between a lot of penalty and completely unwalkable as they behave very differently pathfinding wise.

You can get the penalty from the nearest node using AstarPath.active.GetNearest for example.

Right, so basically I’m saying this is inverted from where it should be. The penalty is basically 100% at a value of 0 (I can’t move), but only 1/256 at a value of 1.

True, in theory it does make more sense, as an unwalkable node could be seen as a node with an infinite penalty.
However unwalkable nodes are not really comparable to nodes with an infinite penalty because the agent can still walk over nodes with a high penalty if necessary. I’d prefer making a clear distinction between nodes with a high penalty and nodes which are unwalkable, but that’s debatable if it is the best choice.

If this is annoying when you are painting the penalty you can use one channel for only penalty and another one for only walkability.

What if there was a new category just called “Walkability” “If channel ‘R’ is 255, the node is made unwalkable?” You wouldn’t lose the generality, but at least then I could tell the artists “White moves slower, black moves faster”

Alternate explanation “If channel ‘R’ is 0, the node is fully walkable. If 254, the node has the full penalty. If 255, the node is unwalkable”