Extending GridGraph to include my game logic data. Best approach?

I’m making a 2D based game. I need a structure to save my grid data, so I thought about using the GridGraph provided in this project for both pathfinding and for saving other useful data I need for my game.

Suppose I need to keep for each node (or tile) which game entity is in it (monster, player, a door, …), and other parameters (e.g. height, actions/events, …). Is such a crazy thing to think about extending GridGraph and GridNode (to, let’s say, TileGraph and TileNode) to be able to get my game logic processed at pathfinding time? If that sounds crazy, how will you manage to have a TileSet structure containing al my Tiles with my game data to be connected with pathfinding’s GridGraph/GridNodes?

Thanks!

Hi

It is actually not a bad idea at all.
And it is quite easy, follow me here:

`
using Pathfinding;
public class TileGraph : GridGraph {
public Node[] CreateNodes (int n) {
TileNode[] nodes = new TileNode[n];
for (int i=0;i<nodes.Length;i++) nodes[i] = new TileNode ();
}
}

class TileNode : GridNode {
public int monsterCount;
}`

//in editor folder [CustomGraphEditor(typeof(TileGraph), "Tile Graph")] public class TileGraphEditor : GridGraphEditor { }

public void Start () { TileNode node = (TileNode)AstarPath.active.GetNearest (transform.position).node; int monsters = node.monsterCount; if (monsters > 1) Debug.Log ("A powerful monster emerged from the shadows and killed you, Game Over."); }

The above code was typed directly in the browser, so I might have forgotten something or made some mistakes, but hopefully it will work.

You should find your custom graph type in the Add New Graph menu.

Works like a charm!

I want to save the GameObject that is positioned on each node into my new class (TileNode). I thought about overriding GridGraph.Scan, but I saw collision testing is done at GraphCollision.Check (where raycasts are thrown), so I’m a bit puzzled here. Is there a non-obtrusive way of getting the GameObject you’re colliding with (hopefully without modifying your library)?

I’m thinking on something like this:

class TileNode : GridNode { public GameObject entity; }

void Start () { AstarPath.active.Scan (); TileNode node = (TileNode)AstarPath.active.GetNearest (transform.position).node; if (node.entity != null) { GameObject.Destroy (node.entity); Debug.Log ("You killed the monster!"); } }

Do you want to add a reference to the GameObject which the height testing hits when scanning the graph?
Since raycasts are relatively fast, it is probably easier to just do another raycast.
public override void Scan () { base.Scan (); for (all nodes) { if (raycast) { node.entity = hit.gameObject } } }

Thanks again. Now that I see that there’s finally a 3.2 version (that I have to say I’m waiting for some months :D), I see some changes that can affect the CreateNodes function:

Initial node penalty per graph can now be set. Custom graph types implementing CreateNodes must update their implementations to properly assign this value.

How will then the overrided function be implemented to keep track of those new changes?

Sure, no problem. It only requires that you add one line of code to set the initial node penalty.

After upgrading to 3.2.x I’m having some troubles with my new TileNode and TileGraph classes. Before, it was working properly, but now, it throws me this:

Exception: No graph of type 'Pathfinding.Nodes.TileGraph' could be created, type does not exist Pathfinding.Serialization.GraphMeta.GetGraphType (Int32 i) (at Assets/AstarPathfindingProject/Core/Serialization/JsonSerializer.cs:654)

Reproduction steps:

  1. Create a GO with AstarPath behavior on it.
  2. Add a graph of type Tile Graph (following the implementation you just hint me before)
  3. Click on another GO in the hierarchy.
  4. Click again on AstarPath’s GO.
  5. When you play the game, you also get a warning
    Caught exception while deserializing data. System.Exception: No graph of type 'Pathfinding.Nodes.TileGraph' could be created, type does not exist at Pathfinding.Serialization.GraphMeta.GetGraphType (Int32 i) [0x0006a] in /Users/frarees/Documents/xmap-client/Assets/AstarPathfindingProject/Core/Serialization/JsonSerializer.cs:654

Full stacktrace:
Exception: No graph of type 'Pathfinding.Nodes.TileGraph' could be created, type does not exist Pathfinding.Serialization.GraphMeta.GetGraphType (Int32 i) (at Assets/AstarPathfindingProject/Core/Serialization/JsonSerializer.cs:654) Pathfinding.Serialization.AstarSerializer.DeserializeGraphs () (at Assets/AstarPathfindingProject/Core/Serialization/JsonSerializer.cs:363) Pathfinding.AstarData.DeserializeGraphsPart (Pathfinding.Serialization.AstarSerializer sr) (at Assets/AstarPathfindingProject/Core/AstarData.cs:304) AstarPathEditor.DeserializeGraphs (System.Byte[] bytes) (at Assets/AstarPathfindingProject/Editor/AstarPathEditor.cs:2032) AstarPathEditor.DeserializeGraphs () (at Assets/AstarPathfindingProject/Editor/AstarPathEditor.cs:2025) AstarPathEditor.LoadGraphs () (at Assets/AstarPathfindingProject/Editor/AstarPathEditor.cs:1989) AstarPathEditor.OnEnable () (at Assets/AstarPathfindingProject/Editor/AstarPathEditor.cs:209)

Uh huh… Assuming you are not using FAST_NO_EXCEPTIONS (which you should only use when deploying for iPhone). That would be handled by the code
Type type = Type.GetType (typeNames[i]);
And unless you have your graph code in a separate dll (or written it in UnityScript), that should find it.

I tested to paste the above code in my project (and fixing some compiler errors since I had apparently some errors in the code) and it worked perfectly even with 3.2.3.

Sure you do not have any compiler errors in it or something. Or maybe you changed the name of the class or the namespace it was in.

I’m indeed using FAST_NO_EXCEPTIONS (however I’ve set this only in iPhone player settings, in the “Scripting Define Symbols”).
This is the code I have, if it helps to detect the problem. It’s under Assets/Pathfinding.

TileGraph.cs:
`using UnityEngine;
using System.Collections;
using Pathfinding.Nodes;

namespace Pathfinding.Nodes
{
public class TileGraph : GridGraph
{
public override Node[] CreateNodes (int n)
{
TileNode[] nodes = new TileNode[n];

		for (int i = 0; i < nodes.Length; i++)
			nodes[i] = new TileNode ();
		
		return nodes;
	}
	
	
	public override void Scan ()
	{
		base.Scan();
		...
	}
}

}`

TileNode.cs:
`using UnityEngine;
using System.Collections;

namespace Pathfinding.Nodes
{
public class TileNode : GridNode
{
public GameObject entity;
}
}`

TileGraphEditor.cs:
`using UnityEngine;
using UnityEditor;
using System.Collections;
using Pathfinding.Nodes;

[CustomGraphEditor(typeof(TileGraph), “Tile Graph”)]
public class TileGraphEditor : GridGraphEditor {

}
`

Ah so you are using it. There is a slight oddness to using iPhone builds with Fast No Exceptions. That is that some reflection (including Type.GetType) does not work. So the system falls back to using a predefined list of available graph types.
This is noted in the docs here http://arongranberg.com/astar/docs/iphone.php

You will need to update the predefined list in both JsonSerializer.cs -> GetGraphType function and AstarData.cs -> FindGraphTypes function to get it to work then.

The reason it does not work now, when it worked before is that I thought Type.GetType worked with Fast but No Exceptions on iPhone, apparently it does not and therefore I have added the fallbacks for this version.