summaryrefslogtreecommitdiff
path: root/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/ExampleScripts/RecastTileUpdateHandler.cs
diff options
context:
space:
mode:
authorchai <215380520@qq.com>2024-05-23 10:08:29 +0800
committerchai <215380520@qq.com>2024-05-23 10:08:29 +0800
commit8722a9920c1f6119bf6e769cba270e63097f8e25 (patch)
tree2eaf9865de7fb1404546de4a4296553d8f68cc3b /Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/ExampleScripts/RecastTileUpdateHandler.cs
parent3ba4020b69e5971bb0df7ee08b31d10ea4d01937 (diff)
+ astar project
Diffstat (limited to 'Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/ExampleScripts/RecastTileUpdateHandler.cs')
-rw-r--r--Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/ExampleScripts/RecastTileUpdateHandler.cs161
1 files changed, 161 insertions, 0 deletions
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/ExampleScripts/RecastTileUpdateHandler.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/ExampleScripts/RecastTileUpdateHandler.cs
new file mode 100644
index 0000000..d9dcdb8
--- /dev/null
+++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/ExampleScripts/RecastTileUpdateHandler.cs
@@ -0,0 +1,161 @@
+using UnityEngine;
+
+namespace Pathfinding {
+ /// <summary>
+ /// Helper for easier fast updates to recast graphs.
+ ///
+ /// When updating recast graphs, you might just have plonked down a few
+ /// GraphUpdateScene objects or issued a few GraphUpdateObjects to the
+ /// system. This works fine if you are only issuing a few but the problem
+ /// is that they don't have any coordination in between themselves. So if
+ /// you have 10 GraphUpdateScene objects in one tile, they will all update
+ /// that tile (10 times in total) instead of just updating it once which
+ /// is all that is required (meaning it will be 10 times slower than just
+ /// updating one tile). This script exists to help with updating only the
+ /// tiles that need updating and only updating them once instead of
+ /// multiple times.
+ ///
+ /// It is coupled with the RecastTileUpdate component, which works a bit
+ /// like the GraphUpdateScene component, just with fewer options. You can
+ /// attach the RecastTileUpdate to any GameObject to have it schedule an
+ /// update for the tile(s) that contain the GameObject. E.g if you are
+ /// creating a new building somewhere, you can attach the RecastTileUpdate
+ /// component to it to make it update the graph when it is instantiated.
+ ///
+ /// If a single tile contains multiple RecastTileUpdate components and
+ /// many try to update the graph at the same time, only one tile update
+ /// will be done, which greatly improves performance.
+ ///
+ /// If you have objects that are instantiated at roughly the same time
+ /// but not exactly the same frame, you can use the maxThrottlingDelay
+ /// field. It will delay updates up to that number of seconds to allow
+ /// more updates to be batched together.
+ ///
+ /// Note: You should only have one instance of this script in the scene
+ /// if you only have a single recast graph. If you have more than one
+ /// graph you can have more than one instance of this script but you need
+ /// to manually call the SetGraph method to configure it with the correct
+ /// graph.
+ ///
+ /// Note: This does not use navmesh cutting. If you only ever add
+ /// obstacles, but never add any new walkable surfaces then you might
+ /// want to use navmesh cutting instead. See navmeshcutting (view in online documentation for working links).
+ ///
+ /// Deprecated: Since version 5.0, this component is not necessary, since normal graph updates on recast graphs are now batched together if they update the same tiles.
+ /// Use e.g. the <see cref="DynamicGridObstacle"/> component instead.
+ /// </summary>
+ [HelpURL("https://arongranberg.com/astar/documentation/stable/recasttileupdatehandler.html")]
+ public class RecastTileUpdateHandler : MonoBehaviour {
+ /// <summary>Graph that handles the updates</summary>
+ RecastGraph graph;
+
+ /// <summary>True for a tile if it needs updating</summary>
+ bool[] dirtyTiles;
+
+ /// <summary>True if any elements in dirtyTiles are true</summary>
+ bool anyDirtyTiles = false;
+
+ /// <summary>Earliest update request we are handling right now</summary>
+ float earliestDirty = float.NegativeInfinity;
+
+ /// <summary>All tile updates will be performed within (roughly) this number of seconds</summary>
+ public float maxThrottlingDelay = 0.5f;
+
+ public void SetGraph (RecastGraph graph) {
+ this.graph = graph;
+
+ if (graph == null)
+ return;
+
+ dirtyTiles = new bool[graph.tileXCount*graph.tileZCount];
+ anyDirtyTiles = false;
+ }
+
+ /// <summary>Requests an update to all tiles which touch the specified bounds</summary>
+ public void ScheduleUpdate (Bounds bounds) {
+ if (graph == null) {
+ // If no graph has been set, use the first graph available
+ if (AstarPath.active != null) {
+ SetGraph(AstarPath.active.data.recastGraph);
+ }
+
+ if (graph == null) {
+ Debug.LogError("Received tile update request (from RecastTileUpdate), but no RecastGraph could be found to handle it");
+ return;
+ }
+ }
+
+ // Make sure that tiles which do not strictly
+ // contain this bounds object but which still
+ // might need to be updated are actually updated
+ int voxelCharacterRadius = Mathf.CeilToInt(graph.characterRadius/graph.cellSize);
+ int borderSize = voxelCharacterRadius + 3;
+
+ // Expand borderSize voxels on each side
+ bounds.Expand(new Vector3(borderSize, 0, borderSize)*graph.cellSize*2);
+
+ var touching = graph.GetTouchingTiles(bounds);
+
+ if (touching.Width * touching.Height > 0) {
+ if (!anyDirtyTiles) {
+ earliestDirty = Time.time;
+ anyDirtyTiles = true;
+ }
+
+ for (int z = touching.ymin; z <= touching.ymax; z++) {
+ for (int x = touching.xmin; x <= touching.xmax; x++) {
+ dirtyTiles[z*graph.tileXCount + x] = true;
+ }
+ }
+ }
+ }
+
+ void OnEnable () {
+ RecastTileUpdate.OnNeedUpdates += ScheduleUpdate;
+ }
+
+ void OnDisable () {
+ RecastTileUpdate.OnNeedUpdates -= ScheduleUpdate;
+ }
+
+ void Update () {
+ if (anyDirtyTiles && Time.time - earliestDirty >= maxThrottlingDelay && graph != null) {
+ UpdateDirtyTiles();
+ }
+ }
+
+ /// <summary>Update all dirty tiles now</summary>
+ public void UpdateDirtyTiles () {
+ if (graph == null) {
+ new System.InvalidOperationException("No graph is set on this object");
+ }
+
+ if (graph.tileXCount * graph.tileZCount != dirtyTiles.Length) {
+ Debug.LogError("Graph has changed dimensions. Clearing queued graph updates and resetting.");
+ SetGraph(graph);
+ return;
+ }
+
+ for (int z = 0; z < graph.tileZCount; z++) {
+ for (int x = 0; x < graph.tileXCount; x++) {
+ if (dirtyTiles[z*graph.tileXCount + x]) {
+ dirtyTiles[z*graph.tileXCount + x] = false;
+
+ var bounds = graph.GetTileBounds(x, z);
+
+ // Shrink it a bit to make sure other tiles
+ // are not included because of rounding errors
+ bounds.extents *= 0.5f;
+
+ var guo = new GraphUpdateObject(bounds);
+ guo.nnConstraint.graphMask = 1 << (int)graph.graphIndex;
+
+ AstarPath.active.UpdateGraphs(guo);
+ }
+ }
+ }
+
+ anyDirtyTiles = false;
+ }
+ }
+}