ProceduralGridMover with Procedural tiles?

Pretty much what the title says; I’ve been trying to figure out how to set walkable and penalty with ProceduralGridMover for the past 3 hours. Havn’t really gotten anything that works.

I also have some weird issue where the graph tiles are like 0.5 tiles higher up than they should be.

Hi

This is particularly tricky because with a ProceduralGridMover the nodes may be recalculated at any time as the graph moves.

The most robust solution is to use the beta version and implement a custom grid graph rule.
See https://www.arongranberg.com/astar/documentation/dev_4_3_26_4629f2f4/gridrules.html

However, I’m not sure if your graph updates are easy to translate to a global rule.

Hmm… It could work. I will try it.

1 Like

Having a problem with the GridMover itself now.

It says “‘GridGraph’ does not contain a definition for ‘UpdateRegion’ and no accessible extension method ‘UpdateRegion’ accepting a first argument of type ‘GridGraph’ could be found (are you missing a using directive or an assembly reference?)”

If it matters, I have copied a lot of the code from the ProceduralGridMover to my own class.

Managed to fix that, though I need to be able to know the target position in the Job. And I don’t know how to do that.

What do you mean by “target position” in this case?

The GridMover’s target position.

Why do you need that? Only the nodes positions should be required I think.

My world is divided into chunks. I need to get the correct chunk in my array from a position. And the node positions are just in the dimensions of the grid right? So I cant get the correct chunk with just those values, I need world positions too.

And no matter what I put into the walkable array it always looks weird on the actual grid.

Hi

The nodePositions array is in world space, you can use that.

An example of it being used (copy pasted from the documentation)

using UnityEngine;
using Unity.Collections;
using Pathfinding;
using Pathfinding.Jobs;
using Unity.Jobs;
using Unity.Burst;

[Pathfinding.Util.Preserve]
public class RuleExampleNodes : GridGraphRule {
    public float perlinNoiseScale = 10.0f;
    public float perlinNoiseThreshold = 0.4f;

    public override void Register (GridGraphRules rules) {
        rules.Add(Pass.BeforeConnections, context => {
            new JobExample {
                bounds = context.data.bounds,
                nodeWalkable = context.data.nodeWalkable,
                nodePositions = context.data.nodePositions,
                perlinNoiseScale = perlinNoiseScale,
                perlinNoiseThreshold = perlinNoiseThreshold,
            }.Schedule(context.tracker);
        });
    }

    [BurstCompile]
    struct JobExample : IJob, INodeModifier {
        public IntBounds bounds;
        public float perlinNoiseScale;
        public float perlinNoiseThreshold;

        [WriteOnly]
        public NativeArray<bool> nodeWalkable;
        [ReadOnly]
        public NativeArray<Vector3> nodePositions;

        public void Execute () {
            ForEachNode(bounds, ref this);
        }

        public void ModifyNode (int dataIndex, int dataX, int dataZ) {
            var position = nodePositions[dataIndex];

            nodeWalkable[dataIndex] = Mathf.PerlinNoise(position.x / perlinNoiseScale, position.z / perlinNoiseScale) > perlinNoiseThreshold;
        }
    }
}

You can also access context.graph.center inside the rule callback to get the center of the graph.
This will be the position of the grid mover (rounded to the nearest grid coordinate).

That seems to work fine but looks it’s really weird, it’s like this no matter what I put into the nodeWalkable array. https://gyazo.com/608a51eb6d4c4a97251a02bcb254d985

Do you think you could post the exact code you are using?

Yeah, sure.

Here is my GridGraph creation code

void Awake() {
        wc = GameManager.worldController;

        AstarData data = AstarPath.active.data;
        
        gg = (GridGraph)data.AddGraph(typeof(GridGraph));
        
        gg.rotation = new Vector3(-90, 0, 0);

        gg.SetDimensions(wc.chunkSize, wc.chunkSize, wc.tileSize);

        gg.cutCorners = false;

        gg.collision.heightCheck = false;
        gg.collision.collisionCheck = false;
        gg.collision.use2D = true;
        
        gridMover = GetComponent<ProceduralGridMover>();

		gg.rules.rules.Clear();
		gg.rules.rules.Add(new RuleExampleNodes());

        gg.Scan();
        
        gridMover.graph = gg;
    }

And heres the code for the rule.

[Pathfinding.Util.Preserve]
public class RuleExampleNodes : GridGraphRule {

    public override void Register(GridGraphRules rules) {
        rules.Add(Pass.BeforeConnections, context => {
            new JobExample {
                bounds = context.data.bounds,
                nodeWalkable = context.data.nodeWalkable,
                nodePositions = context.data.nodePositions,
            }.Schedule(context.tracker);
        });
    }

    //[BurstCompile]
    struct JobExample : IJob, INodeModifier {
        public IntBounds bounds;

        [WriteOnly]
        public NativeArray<bool> nodeWalkable;
        [ReadOnly]
        public NativeArray<Vector3> nodePositions;

        public void Execute() {
            ForEachNode(bounds, ref this);
        }

        public void ModifyNode(int dataIndex, int dataX, int dataZ) {
            Chunk chunk = GameManager.worldController.world.GetChunkAt((int)nodePositions[dataIndex].x, (int)nodePositions[dataIndex].y);
            
            if (chunk != null) {
                Tile t = chunk.chunkTiles[dataIndex];

                nodeWalkable[dataIndex] = t.terrainType.isWalkable && t.buildingType.isNull; 
            }
        }
    }
}

I’ve had to disable Burst in this case because some of my code is not compatiable with it yet.

Chunk chunk = GameManager.worldController.world.GetChunkAt((int)nodePositions[dataIndex].x, (int)nodePositions[dataIndex].y);

Are you sure you want to use x, y and not x, z?

Tile t = chunk.chunkTiles[dataIndex];

You probably don’t want to do this. There is no guarantee that the dataIndex lines up with what your chunk uses internally. The data index is inside the smaller rectangle which is being updated, not the whole grid.

You can get the node’s coordinates in the whole grid by doing:

int gridX = bounds.min.x + dataX;
int gridZ = bounds.min.z + dataZ;

Changing the first line you mentioned to use z instead of y seems to make it not make any tile unwalkable.
Changing the second line didn’t seem to make any difference at all.

How is your chunk data laid out?

Well I would get a correct Tile from the chunkTiles array by doing x * chunkSize + y (x and y would be in chunk coordinates). I have another method that turns world coordinates into chunk coordinates. In this case each chunk is 25x25, the same size as the gridMover area. Not sure if this was the information you were looking for but yeah.

And inside each chunk? Are they laid out row by row or column by column?

I.e. are they indexed

chunk[x*25 + y] or chunk[y*25 + x]?

it would be chunk[x * 25 + y]