Hello!
So im trying to add a custom GridGraphRule where if a directonal-block tilemap has a tile, it would remove the connection going in that direction. Ive tried several things and there is no helpful example that I could find for how to achieve something like this. Ive pasted my code below and I have a few questions about it.
- Is using the Pass.AfterConnections correct?
- I cant access nodes through context.graph.nodes because its null in this pass. How can i access the nodes? Should I even access them?
- Assuming I cant access them, I tried using GetNeighbourDataIndex passing in the values you see below and it always returns null. It should never be null because i dont have a directional block that goes off the map, so all neighbors should be in bounds.
- Does a value of 0 mean no connection when accessing context.data.nodeConnections?
I mainly want to know how to remove a connection in one of these custom rules. Id appreciate any help!
public class DirectionalBlockGridRule : GridGraphRule
{
public Tilemap[] FunctionalTilemaps;
// if you wanna add 1-way connections:
// https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
// https://forum.arongranberg.com/t/bug-with-one-way-links-floodfill-areas-and-abpath/1794
public override void Register(GridGraphRules rules)
{
base.Register(rules);
if (!FunctionalTilemaps.Any())
{
Debug.LogWarning("Must have functional tilemap assigned");
return;
}
rules.AddMainThreadPass(Pass.AfterConnections, context =>
{
NativeArray<Vector3> nodePositions = context.data.nodePositions;
NativeArray<int> nodeConns = context.data.nodeConnections;
for (int i = 0; i < nodePositions.Length; i++)
{
foreach (Tilemap fnMap in FunctionalTilemaps)
{
Vector3Int tilePos = Vector3Int.FloorToInt(nodePositions[i]);
TileBase tile = fnMap.GetTile(tilePos);
if (tile == null) continue;
// Z
// |
// 6 2 5
// 3 x 1 - X
// 7 0 4
if (tile.name.ToLower().Contains("up"))
{
int? neighborIndex = GetNeighbourDataIndex(
context.data.bounds, context.data.nodeConnections, context.data.layeredDataLayout,
tilePos.x, tilePos.y, tilePos.z, 2);
context.data.nodeConnections[neighborIndex.Value] = 0;
}
}
}
});
}
}
#if UNITY_EDITOR
[CustomGridGraphRuleEditor(typeof(DirectionalBlockGridRule), "Directional Block Grid Rule")]
public class DirectionalBlockGridRuleEditor : IGridGraphRuleEditor
{
public void OnInspectorGUI(GridGraph graph, GridGraphRule rule)
{
DirectionalBlockGridRule target = rule as DirectionalBlockGridRule;
if (!target.FunctionalTilemaps.Any() || target.FunctionalTilemaps[0] == null)
target.FunctionalTilemaps = GameObject.FindGameObjectsWithTag("FunctionMap").Select(x => x.GetComponent<Tilemap>()).ToArray();
if (target.FunctionalTilemaps.Any())
for (int i = 0; i < target.FunctionalTilemaps.Length; i++)
target.FunctionalTilemaps[i] = (Tilemap)EditorGUILayout.ObjectField("Fn Tilemap "+i, target.FunctionalTilemaps[i], typeof(Tilemap), true);
}
public void OnSceneGUI(GridGraph graph, GridGraphRule rule)
{
}
}
#endif
hopefully this image will help illustrate what Im trying to do, which is remove the connections going in the direction each arrow is pointing