diff options
author | chai <215380520@qq.com> | 2024-05-23 10:08:29 +0800 |
---|---|---|
committer | chai <215380520@qq.com> | 2024-05-23 10:08:29 +0800 |
commit | 8722a9920c1f6119bf6e769cba270e63097f8e25 (patch) | |
tree | 2eaf9865de7fb1404546de4a4296553d8f68cc3b /Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/LayerGridGraph.cs | |
parent | 3ba4020b69e5971bb0df7ee08b31d10ea4d01937 (diff) |
+ astar project
Diffstat (limited to 'Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/LayerGridGraph.cs')
-rw-r--r-- | Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/LayerGridGraph.cs | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/LayerGridGraph.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/LayerGridGraph.cs new file mode 100644 index 0000000..c629224 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/LayerGridGraph.cs @@ -0,0 +1,246 @@ +#if !ASTAR_NO_GRID_GRAPH +using UnityEngine; +using System.Collections.Generic; +using Pathfinding.Serialization; +using Pathfinding.Graphs.Grid; + +namespace Pathfinding { + /// <summary> + /// Grid Graph, supports layered worlds. + /// [Open online documentation to see images] + /// The GridGraph is great in many ways, reliable, easily configured and updatable during runtime. + /// But it lacks support for worlds which have multiple layers, such as a building with multiple floors. + /// That's where this graph type comes in. It supports basically the same stuff as the grid graph, but also multiple layers. + /// It uses a bit more memory than a regular grid graph, but is otherwise equivalent. + /// + /// [Open online documentation to see images] + /// + /// Note: The graph supports 16 layers by default, but it can be increased to 256 by enabling the ASTAR_LEVELGRIDNODE_MORE_LAYERS option in the A* Inspector -> Settings -> Optimizations tab. + /// + /// See: <see cref="GridGraph"/> + /// </summary> + [Pathfinding.Util.Preserve] + public class LayerGridGraph : GridGraph, IUpdatableGraph { + // This function will be called when this graph is destroyed + protected override void DisposeUnmanagedData () { + base.DisposeUnmanagedData(); + + // Clean up a reference in a static variable which otherwise should point to this graph forever and stop the GC from collecting it + LevelGridNode.ClearGridGraph((int)graphIndex, this); + } + + public LayerGridGraph () { + newGridNodeDelegate = () => new LevelGridNode(); + } + + protected override GridNodeBase[] AllocateNodesJob (int size, out Unity.Jobs.JobHandle dependency) { + var newNodes = new LevelGridNode[size]; + + dependency = active.AllocateNodes(newNodes, size, newGridNodeDelegate, 1); + return newNodes; + } + + /// <summary> + /// Number of layers. + /// Warning: Do not modify this variable + /// </summary> + [JsonMember] + internal int layerCount; + + /// <summary>Nodes with a short distance to the node above it will be set unwalkable</summary> + [JsonMember] + public float characterHeight = 0.4F; + + internal int lastScannedWidth; + internal int lastScannedDepth; + + public override int LayerCount { + get => layerCount; + protected set => layerCount = value; + } + + public override int MaxLayers => LevelGridNode.MaxLayerCount; + + public override int CountNodes () { + if (nodes == null) return 0; + + int counter = 0; + for (int i = 0; i < nodes.Length; i++) { + if (nodes[i] != null) counter++; + } + return counter; + } + + public override void GetNodes (System.Action<GraphNode> action) { + if (nodes == null) return; + + for (int i = 0; i < nodes.Length; i++) { + if (nodes[i] != null) action(nodes[i]); + } + } + + /// <summary> + /// Get all nodes in a rectangle. + /// Returns: The number of nodes written to the buffer. + /// </summary> + /// <param name="rect">Region in which to return nodes. It will be clamped to the grid.</param> + /// <param name="buffer">Buffer in which the nodes will be stored. Should be at least as large as the number of nodes that can exist in that region.</param> + public override int GetNodesInRegion (IntRect rect, GridNodeBase[] buffer) { + // Clamp the rect to the grid + // Rect which covers the whole grid + var gridRect = new IntRect(0, 0, width-1, depth-1); + + rect = IntRect.Intersection(rect, gridRect); + + if (nodes == null || !rect.IsValid() || nodes.Length != width*depth*layerCount) return 0; + + int counter = 0; + try { + for (int l = 0; l < layerCount; l++) { + var lwd = l * Width * Depth; + for (int z = rect.ymin; z <= rect.ymax; z++) { + var offset = lwd + z*Width; + for (int x = rect.xmin; x <= rect.xmax; x++) { + var node = nodes[offset + x]; + if (node != null) { + buffer[counter] = node; + counter++; + } + } + } + } + } catch (System.IndexOutOfRangeException) { + // Catch the exception which 'buffer[counter] = node' would throw if the buffer was too small + throw new System.ArgumentException("Buffer is too small"); + } + + return counter; + } + + /// <summary> + /// Node in the specified cell. + /// Returns null if the coordinate is outside the grid. + /// + /// If you know the coordinate is inside the grid and you are looking to maximize performance then you + /// can look up the node in the internal array directly which is slightly faster. + /// See: <see cref="nodes"/> + /// </summary> + public GridNodeBase GetNode (int x, int z, int layer) { + if (x < 0 || z < 0 || x >= width || z >= depth || layer < 0 || layer >= layerCount) return null; + return nodes[x + z*width + layer*width*depth]; + } + + protected override IGraphUpdatePromise ScanInternal (bool async) { + LevelGridNode.SetGridGraph((int)graphIndex, this); + layerCount = 0; + lastScannedWidth = width; + lastScannedDepth = depth; + return base.ScanInternal(async); + } + + protected override GridNodeBase GetNearestFromGraphSpace (Vector3 positionGraphSpace) { + if (nodes == null || depth*width*layerCount != nodes.Length) { + return null; + } + + float xf = positionGraphSpace.x; + float zf = positionGraphSpace.z; + int x = Mathf.Clamp((int)xf, 0, width-1); + int z = Mathf.Clamp((int)zf, 0, depth-1); + var worldPos = transform.Transform(positionGraphSpace); + return GetNearestNode(worldPos, x, z, null); + } + + private GridNodeBase GetNearestNode (Vector3 position, int x, int z, NNConstraint constraint) { + int index = width*z+x; + float minDist = float.PositiveInfinity; + GridNodeBase minNode = null; + + for (int i = 0; i < layerCount; i++) { + var node = nodes[index + width*depth*i]; + if (node != null) { + float dist = ((Vector3)node.position - position).sqrMagnitude; + if (dist < minDist && (constraint == null || constraint.Suitable(node))) { + minDist = dist; + minNode = node; + } + } + } + return minNode; + } + + protected override void SerializeExtraInfo (GraphSerializationContext ctx) { + if (nodes == null) { + ctx.writer.Write(-1); + return; + } + + ctx.writer.Write(nodes.Length); + + for (int i = 0; i < nodes.Length; i++) { + if (nodes[i] == null) { + ctx.writer.Write(-1); + } else { + ctx.writer.Write(0); + nodes[i].SerializeNode(ctx); + } + } + + SerializeNodeSurfaceNormals(ctx); + } + + protected override void DeserializeExtraInfo (GraphSerializationContext ctx) { + int count = ctx.reader.ReadInt32(); + + if (count == -1) { + nodes = null; + return; + } + + nodes = new LevelGridNode[count]; + for (int i = 0; i < nodes.Length; i++) { + if (ctx.reader.ReadInt32() != -1) { + nodes[i] = newGridNodeDelegate(); + active.InitializeNode(nodes[i]); + nodes[i].DeserializeNode(ctx); + } else { + nodes[i] = null; + } + } + DeserializeNativeData(ctx, ctx.meta.version >= AstarSerializer.V4_3_37); + } + + protected override void PostDeserialization (GraphSerializationContext ctx) { + UpdateTransform(); + lastScannedWidth = width; + lastScannedDepth = depth; + + SetUpOffsetsAndCosts(); + LevelGridNode.SetGridGraph((int)graphIndex, this); + + if (nodes == null || nodes.Length == 0) return; + + if (width*depth*layerCount != nodes.Length) { + Debug.LogError("Node data did not match with bounds data. Probably a change to the bounds/width/depth data was made after scanning the graph, just prior to saving it. Nodes will be discarded"); + nodes = new GridNodeBase[0]; + return; + } + + for (int i = 0; i < layerCount; i++) { + for (int z = 0; z < depth; z++) { + for (int x = 0; x < width; x++) { + LevelGridNode node = nodes[z*width+x + width*depth*i] as LevelGridNode; + + if (node == null) { + continue; + } + + node.NodeInGridIndex = z*width+x; + node.LayerCoordinateInGrid = i; + } + } + } + } + } +} +#endif |