How to use A* programatically

I want to call something like

gameObject a_star;

private void awake()
{
awaken_a_star();
}

private void awaken_a_star()
{
a_star = new gameObject();
AstarPath as = a_star.AddComponent();
as.AddNewGridGraph();
as.set_grid_graph_properties(x, y, z, asdfasdf, asdfae);
}

but I can’t find any of these commands. Like, I absoultely hate using those silly little UI buttons on the side, and want to make it all programatically. I’m building a procedurally made world, with different sizes, etc… so the grid point density, and size of the grid graph will need to change every time I build a new world.

How can I do this all programatically?

Hi

Maybe you are interested in https://arongranberg.com/astar/docs/runtimegraphs.html

Yup. That’s exactly what I was looking for.

Now I have something like this :slight_smile:
private void awakeAstar()
{
a_star = new GameObject(“A*”);
a_star.AddComponent();
Pathfinding.GridGraph grid = AstarPath.active.data.AddGraph(typeof(Pathfinding.GridGraph)) as Pathfinding.GridGraph;
float sq_size = map.GetComponent<Map_Generation2>().sqsize;
float num_x = map.GetComponent<Map_Generation2>().numx;
float num_y = map.GetComponent<Map_Generation2>().numy;
grid.center = new Vector3(0, -1f, 0);
float nodeSize = sq_size / 6f;
int depth = (int)(sq_size * num_y * 3f);
int width = (int)(sq_size * num_x * 3f);
grid.SetDimensions(width, depth, nodeSize);
grid.cutCorners = true;
}

I just need to figure out how to turn on the 2D physics, and make the grid 2D, but besides that it should work just fine. :slight_smile:

So I understand now how to change the grid, but the Grid Graph UI in unity shows a few things which aren’t actually contained in the grid-graph class.

For instance, the tic box “use2D” is actually a part of the graph collision, which isn’t super obvious how to implement, and the “2D” check box underneath the grid graph UI (right where you change nodes, etc" seems like I can’t change it anywhere? Although maybe this is actually just a rotation of the grid? Not sure.

Hi

You can set it using

gridGraph.collision.use2D = true;

The 2D toggle is, as you suspected, just a shorthand for setting the rotation of the graph. The best 2D rotation is not super intuitive unfortunately:

gridGraph.rotation = new Vector3(-90, 270, 90);

Any rotation that is aligned with the 2D plane will work though.

Okay, so the programmatic creation of the grid is working well, but the pathfinding is providing to be a bit difficult to implement.

I’ve got all the pathfinding running in parallel for multiple entities, which is great, but I’m having an issue with the offset and smoothing features.

If I try to smooth with simple offset, no matter what I try (even in the UI) I can’t get it to work as intended…

If I try something like

List SO_path = obj.GetComponent<Pathfinding.SimpleSmoothModifier>().SmoothOffsetSimple(path);

I get the error “cannot convert from Pathfinding.Path” to “System.Collectiosn.Generlic.List<UnityEngine.Vector3>”

which makes no sense because the SmoothOffsetSimple(path) should return a list

But whatever. I try replacing it with

Pathfinding.Path SO_path = obj.GetComponent<Pathfinding.SimpleSmoothModifier>().SmoothOffsetSimple(path);

and now I get the error " cannot convert from ‘Pathfinding.Path’ to ‘System.Collections.Generic.List<UnityEngine.Vector3>’

which makes even less sense… Because I change nothing but it’s like it wants to output a different value?

Hi

You should not use modifiers manually like that. If you want to post-process a path manually without going through seeker.StartPath, I’d recommend that you use seeker.PostProcess(path).

Hmm…

So in my gameobject that contains a seeker class, I should call

    gameObject.AddComponent<Pathfinding.SimpleSmoothModifier>();
    gameObject.GetComponent<Pathfinding.SimpleSmoothModifier>().smoothType = Pathfinding.SimpleSmoothModifier.SmoothType.OffsetSimple;

and then I should just be able to call the seeker.StartPath((Vector2)current, (Vector2)target); and it should process with the smoothing and offset automatically, right?

I’ve noticed that if I set it to SmoothType.Simple it does the processing automatically, and everything works fine, but if I try for the offset simple it breaks things. It also seems like the simple function returns a totally different value or something?

Not sure.

Maybe it’s because I’m hardcoding the physics into the fixed-update using something like :

            List<Vector3> v_path = path.vectorPath;
            if (currentWaypoint > v_path.Count-2)
            {
                return;
            }
            else
            {
                Vector2 direction = ((Vector2)v_path[currentWaypoint] - rb_2d.position).normalized;
                Vector2 force = direction * speed * Time.deltaTime;
                rb_2d.AddForce(force);
                nextWaypointDistance = Vector2.Distance(v_path[currentWaypoint], v_path[currentWaypoint + 1]);
                float distance = Vector2.Distance(rb_2d.position, v_path[currentWaypoint]);
                if (distance < nextWaypointDistance*3)
                {
                    currentWaypoint++;
                }
            }

Is there instead some way this is already built into the system?

I’ve switched the code to

            GameObject empty_target = new GameObject();
            empty_target.transform.position = (Vector2)target;
            seeker.GetComponent<Pathfinding.AIDestinationSetter>().target = empty_target.transform;
            obj.GetComponent<Moveable_Object>().currentWaypoint = 0;

which I’ll use to produce a little target on the screen (something I was planning to do later anyway), but I still can’t get any of the offsetsimple stuff to work properly.

if I call

    gameObject.AddComponent<Pathfinding.SimpleSmoothModifier>();
    gameObject.GetComponent<Pathfinding.SimpleSmoothModifier>().smoothType = Pathfinding.SimpleSmoothModifier.SmoothType.OffsetSimple;

in the game object which contains the seeker, then it just freaks out back and forth and doesn’t do anything. xD

Is there some kind of fixedupdate method I should be calling inside the pathfinding algorithm instead of hardcoding it with the extract path.vectorpath?

The OffsetSimple can be quite tricky. It has a very narrow range of parameters in which it works. If the offset is too high the path will sort of curl up on itself and look pretty bad. I would recommend testing different parameters in the inspector, or using another mode.

Not quite sure what you mean, but no.

See also https://arongranberg.com/astar/docs/custom_movement_script.html

Interesting… I was reading about people having a similar problem. But I can’t get it to do anything at all! It’s like the offset simple doesn’t actually do anything at all.

Alternatively, if constant looping is common, maybe that’s what it’s doing behind-the-scenes and what is producing the jittery motion?

If it’s producing jittery motion then it must be doing something, no?

Okay so I think I’m on board with most of this, but am struggling with how you’re hardcoding in the nextWaypointDistance.

I’m working on a grid graph, and the distance between waypoints varies depending on if I’m going diagnally or left/right.

The movement script in that tutorial is super simple. So it just moves towards the next waypoint. And when that waypoint is close enough it will start to move towards the one after that.


I got it mostly working, using this code here. The trick seemed to be turning off the clickbox “canMove” on the AIPath. Not sure why it fixed the problem, but it seemed to basically fix all of my issues.

In the end, i never got offset simple to work. No matter what I did it just wouldn’t produce a smooth curve like it does in the tutorials. So I just went with a thick raycast, a funnel modifier, and a simple smooth. It’s not perfect - and the little guys still get stuck on corners / walls sometimes [ the green one got stuck on this path, for example ], but I think what I actually need is the radius modifier from the pro package.

Not sure if it’s worth it though. Any chance you’ve tried it out and know if that would fix the problem? If not, I might try to do some post processing on my own. Because my whole map is divided into these hex cells, which I can approximate as circles, I can probably force some minimum “radius of curvature” or something that would fix the issue too.

Hmm, so the AIPath script does its own movement. It sounds like you want to do all the movement by yourself? In that case you probably shouldn’t use the AIPath script at all.

Not really?

I mostly just want to get the thing to stay away from the hard corners, but I can’t get the offset simple to do the job, so I think I need to just add a strict radius around the corners (or set a minimum radius of curvature).

Idk. Maybe I’ll try a different program. Do you have any experience with the NavMeshPlus project for 2D nav-meshes in Unity? I think it might suit my purposes better.

If you think your agents move too close to the walls you can increase the A* Inspector -> Grid Graph -> Collision -> Diameter setting (or alternatively the erosion setting).
I would also check if you nextWaypointDistance might be too large. If it is too large then the agent might try to move towards a point which is behind the wall, leading to it getting stuck.

Yeah I spent all day on that. In the end the only way I could make it work was by simultaneously cranking up the collision -> diameter setting, while also cranking down the collision circle on my sprite. But then it broke the rest of the game.

I think I’ll just try navmesh plus and see how it goes for a few days.