A* Pathfinding Project  3.8.5
The A* Pathfinding Project for Unity 3D
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Events Macros Groups Pages
PolarGraphGenerator.cs

Shows a simple graph type generating a polar graph.

Version
Tested with version 3.6.7
using UnityEngine;
// Include the Pathfinding namespace to gain access to a lot of useful classes
using Pathfinding;
// Required to save the settings
using Pathfinding.Serialization;
// Inherit our new graph from a base graph type
[JsonOptIn]
public class PolarGraph : NavGraph {
[JsonMember]
public int circles = 10;
[JsonMember]
public int steps = 20;
[JsonMember]
public Vector3 center = Vector3.zero;
[JsonMember]
public float scale = 2;
PointNode[] nodes;
PointNode[] CreateNodes (int count) {
var created = new PointNode[count];
for (int i = 0; i < created.Length; i++) {
created[i] = new PointNode(active);
}
return created;
}
static Vector3 CalculateNodePosition (int circle, float angle, Matrix4x4 matrix) {
// Get the direction towards the node from the center
var pos = new Vector3(Mathf.Sin(angle), 0, Mathf.Cos(angle));
// Multiply it with the circle number to get the node position in graph space
pos *= circle;
// Multiply it with the matrix to get the node position in world space
pos = matrix.MultiplyPoint(pos);
return pos;
}
public override System.Collections.Generic.IEnumerable<Progress> ScanInternal () {
ScanInternal(p => {});
yield break;
}
void ScanInternal (OnScanStatus statusCallback) {
// Create an array containing all nodes
nodes = CreateNodes(circles*steps);
// Create a matrix which just moves the nodes to #center
// and scales their positions by #scale
// The SetMatrix call will save it to a variable called just "matrix"
SetMatrix(Matrix4x4.TRS(center, Quaternion.identity, Vector3.one*scale));
// Place the center node in the center
nodes[0].position = (Int3)matrix.MultiplyPoint(Vector3.zero);
// The number of angles (in radians) each step will use
float anglesPerStep = (2*Mathf.PI)/steps;
for (int circle = 1; circle < circles; circle++) {
for (int step = 0; step < steps; step++) {
// Get the angle to the node relative to the center
float angle = step * anglesPerStep;
Vector3 pos = CalculateNodePosition(circle, angle, matrix);
// Get the node from an index
// The middle node is at index 0
// The first circle is from 1...steps-1
// The second circle is from steps...2*steps-1
// The third is from 2*steps...3*steps-1 and so on
GraphNode node = nodes[(circle-1)*steps + step + 1];
// Assign the node position
node.position = (Int3)pos;
}
}
// Now all nodes are created, let's create some connections between them!
// Iterate through all circles
// circle 0 is just the center node so we skip that for now
for (int circle = 1; circle < circles; circle++) {
for (int step = 0; step < steps; step++) {
// Get the current node
PointNode node = nodes[(circle-1)*steps + step + 1];
// The nodes here will always have exactly four connections, like a grid, but polar.
// Except for those in the last circle which will only have three connections
int numConnections = (circle < circles-1) ? 4 : 3;
var connections = new GraphNode[numConnections];
var connectionCosts = new uint[numConnections];
// Get the next clockwise node in the current circle.
// The last node in each circle should be linked to the first node
// in the circle. But if we just did step+1 we would link it to the
// first node in the *next* circle, which we do not want
int connId = (circle-1)*steps + (step < steps-1 ? step+1 : 0) + 1;
connections[0] = nodes[connId];
// Counter clockwise node. Here we check for underflow instead
connId = (circle-1)*steps + (step > 0 ? step-1 : steps-1) + 1;
connections[1] = nodes[connId];
// The node in the previous circle (in towards the center)
if (circle > 1) {
connId = (circle-2)*steps + step + 1;
} else {
// Create a connection to the middle node, special case
connId = 0;
}
connections[2] = nodes[connId];
// Are there any more circles outside this one?
if (numConnections == 4) {
// The node in the next circle (out from the center)
connId = circle*steps + step + 1;
connections[3] = nodes[connId];
}
for (int q = 0; q < connections.Length; q++) {
// Node.position is an Int3, here we get the cost of moving between the two positions
connectionCosts[q] = (uint)(node.position-connections[q].position).costMagnitude;
}
node.connections = connections;
node.connectionCosts = connectionCosts;
}
}
// The center node is a special case, so we have to deal with it separately
PointNode centerNode = nodes[0];
centerNode.connections = new GraphNode[steps];
centerNode.connectionCosts = new uint[steps];
// Assign all nodes in the first circle as connections to the center node
for (int step = 0; step < steps; step++) {
centerNode.connections[step] = nodes[1+step];
// centerNode.position is an Int3, here we get the cost of moving between the two positions
centerNode.connectionCosts[step] = (uint)(centerNode.position-centerNode.connections[step].position).costMagnitude;
}
// Set all the nodes to be walkable
for (int i = 0; i < nodes.Length; i++) {
nodes[i].Walkable = true;
}
}
public override void GetNodes (GraphNodeDelegateCancelable del) {
if (nodes == null) return;
for (int i = 0; i < nodes.Length; i++) {
// Call the delegate and check if it wants
// more nodes or not
if (!del(nodes[i])) {
// If it did not want more nodes
// then just return
return;
}
}
}
}