diff options
Diffstat (limited to 'Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/TurnBased')
4 files changed, 275 insertions, 0 deletions
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/TurnBased/BlockManager.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/TurnBased/BlockManager.cs new file mode 100644 index 0000000..0a725e4 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/TurnBased/BlockManager.cs @@ -0,0 +1,181 @@ +using UnityEngine; +using System.Collections.Generic; + +namespace Pathfinding { +	using Pathfinding.Util; + +	/// <summary> +	/// Manager for blocker scripts such as SingleNodeBlocker. +	/// +	/// This is part of the turn based utilities. It can be used for +	/// any game, but it is primarily intended for turn based games. +	/// +	/// See: TurnBasedAI +	/// See: turnbased (view in online documentation for working links) +	/// See: traversal_provider (view in online documentation for working links) +	/// </summary> +	[HelpURL("https://arongranberg.com/astar/documentation/stable/blockmanager.html")] +	public class BlockManager : VersionedMonoBehaviour { +		/// <summary>Contains info on which SingleNodeBlocker objects have blocked a particular node</summary> +		Dictionary<GraphNode, List<SingleNodeBlocker> > blocked = new Dictionary<GraphNode, List<SingleNodeBlocker> >(); + +		public enum BlockMode { +			/// <summary>All blockers except those in the TraversalProvider.selector list will block</summary> +			AllExceptSelector, +			/// <summary>Only elements in the TraversalProvider.selector list will block</summary> +			OnlySelector +		} + +		/// <summary>Blocks nodes according to a BlockManager</summary> +		public class TraversalProvider : ITraversalProvider { +			/// <summary>Holds information about which nodes are occupied</summary> +			readonly BlockManager blockManager; + +			/// <summary>Affects which nodes are considered blocked</summary> +			public BlockMode mode { get; private set; } + +			/// <summary> +			/// Blockers for this path. +			/// The effect depends on <see cref="mode"/>. +			/// +			/// Note that having a large selector has a performance cost. +			/// +			/// See: mode +			/// </summary> +			readonly List<SingleNodeBlocker> selector; + +			public TraversalProvider (BlockManager blockManager, BlockMode mode, List<SingleNodeBlocker> selector) { +				if (blockManager == null) throw new System.ArgumentNullException("blockManager"); +				if (selector == null) throw new System.ArgumentNullException("selector"); + +				this.blockManager = blockManager; +				this.mode = mode; +				this.selector = selector; +			} + +			#region ITraversalProvider implementation + +			public bool CanTraverse (Path path, GraphNode node) { +				// This first IF is the default implementation that is used when no traversal provider is used +				if (!node.Walkable || (path != null && (path.enabledTags >> (int)node.Tag & 0x1) == 0)) { +					return false; +				} else if (mode == BlockMode.OnlySelector) { +					return !blockManager.NodeContainsAnyOf(node, selector); +				} else { +					// assume mode == BlockMode.AllExceptSelector +					return !blockManager.NodeContainsAnyExcept(node, selector); +				} +			} + +			public bool CanTraverse (Path path, GraphNode from, GraphNode to) { +				return CanTraverse(path, to); +			} + +			public uint GetTraversalCost (Path path, GraphNode node) { +				// Same as default implementation +				return path.GetTagPenalty((int)node.Tag) + node.Penalty; +			} + +			// This can be omitted in Unity 2021.3 and newer because a default implementation (returning true) can be used there. +			public bool filterDiagonalGridConnections { +				get { +					return true; +				} +			} + +			#endregion +		} + +		void Start () { +			if (!AstarPath.active) +				throw new System.Exception("No AstarPath object in the scene"); +		} + +		/// <summary>True if the node contains any blocker which is included in the selector list</summary> +		public bool NodeContainsAnyOf (GraphNode node, List<SingleNodeBlocker> selector) { +			List<SingleNodeBlocker> blockersInNode; + +			if (!blocked.TryGetValue(node, out blockersInNode)) { +				return false; +			} + +			for (int i = 0; i < blockersInNode.Count; i++) { +				var inNode = blockersInNode[i]; +				for (int j = 0; j < selector.Count; j++) { +					// Need to use ReferenceEquals because this code may be called from a separate thread +					// and the equality comparison that Unity provides is not thread safe +					if (System.Object.ReferenceEquals(inNode, selector[j])) { +						return true; +					} +				} +			} +			return false; +		} + +		/// <summary>True if the node contains any blocker which is not included in the selector list</summary> +		public bool NodeContainsAnyExcept (GraphNode node, List<SingleNodeBlocker> selector) { +			List<SingleNodeBlocker> blockersInNode; + +			if (!blocked.TryGetValue(node, out blockersInNode)) { +				return false; +			} + +			for (int i = 0; i < blockersInNode.Count; i++) { +				var inNode = blockersInNode[i]; +				bool found = false; +				for (int j = 0; j < selector.Count; j++) { +					// Need to use ReferenceEquals because this code may be called from a separate thread +					// and the equality comparison that Unity provides is not thread safe +					if (System.Object.ReferenceEquals(inNode, selector[j])) { +						found = true; +						break; +					} +				} +				if (!found) return true; +			} +			return false; +		} + +		/// <summary> +		/// Register blocker as being present at the specified node. +		/// Calling this method multiple times will add multiple instances of the blocker to the node. +		/// +		/// Note: The node will not be blocked immediately. Instead the pathfinding +		/// threads will be paused and then the update will be applied. It is however +		/// guaranteed to be applied before the next path request is started. +		/// </summary> +		public void InternalBlock (GraphNode node, SingleNodeBlocker blocker) { +			AstarPath.active.AddWorkItem(new AstarWorkItem(() => { +				List<SingleNodeBlocker> blockersInNode; +				if (!blocked.TryGetValue(node, out blockersInNode)) { +					blockersInNode = blocked[node] = ListPool<SingleNodeBlocker>.Claim(); +				} + +				blockersInNode.Add(blocker); +			})); +		} + +		/// <summary> +		/// Remove blocker from the specified node. +		/// Will only remove a single instance, calling this method multiple +		/// times will remove multiple instances of the blocker from the node. +		/// +		/// Note: The node will not be unblocked immediately. Instead the pathfinding +		/// threads will be paused and then the update will be applied. It is however +		/// guaranteed to be applied before the next path request is started. +		/// </summary> +		public void InternalUnblock (GraphNode node, SingleNodeBlocker blocker) { +			AstarPath.active.AddWorkItem(new AstarWorkItem(() => { +				List<SingleNodeBlocker> blockersInNode; +				if (blocked.TryGetValue(node, out blockersInNode)) { +					blockersInNode.Remove(blocker); + +					if (blockersInNode.Count == 0) { +						blocked.Remove(node); +						ListPool<SingleNodeBlocker>.Release(ref blockersInNode); +					} +				} +			})); +		} +	} +} diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/TurnBased/BlockManager.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/TurnBased/BlockManager.cs.meta new file mode 100644 index 0000000..ff85dc9 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/TurnBased/BlockManager.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: df8c077ca577944689559bb9e97f9576 +timeCreated: 1453722739 +licenseType: Store +MonoImporter: +  serializedVersion: 2 +  defaultReferences: [] +  executionOrder: 0 +  icon: {instanceID: 0} +  userData:  +  assetBundleName:  +  assetBundleVariant:  diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/TurnBased/SingleNodeBlocker.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/TurnBased/SingleNodeBlocker.cs new file mode 100644 index 0000000..496de8e --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/TurnBased/SingleNodeBlocker.cs @@ -0,0 +1,70 @@ +using UnityEngine; + +namespace Pathfinding { +	/// <summary> +	/// Blocks single nodes in a graph. +	/// +	/// This is useful in turn based games where you want +	/// units to avoid all other units while pathfinding +	/// but not be blocked by itself. +	/// +	/// Note: To use this with a movement script, you have to assign the BlockManager's traversal provider to either <see cref="Seeker.traversalProvider"/> or <see cref="FollowerEntity.pathfindingSettings.traversalProvider"/>. +	/// +	/// See: TurnBasedAI for example usage +	/// +	/// See: BlockManager +	/// See: turnbased (view in online documentation for working links) +	/// See: traversal_provider (view in online documentation for working links) +	/// </summary> +	[HelpURL("https://arongranberg.com/astar/documentation/stable/singlenodeblocker.html")] +	public class SingleNodeBlocker : VersionedMonoBehaviour { +		public GraphNode lastBlocked { get; private set; } +		public BlockManager manager; + +		/// <summary> +		/// Block node closest to the position of this object. +		/// +		/// Will unblock the last node that was reserved (if any) +		/// </summary> +		public void BlockAtCurrentPosition () { +			BlockAt(transform.position); +		} + +		/// <summary> +		/// Block node closest to the specified position. +		/// +		/// Will unblock the last node that was reserved (if any) +		/// </summary> +		public void BlockAt (Vector3 position) { +			Unblock(); +			var node = AstarPath.active.GetNearest(position, NNConstraint.None).node; +			if (node != null) { +				Block(node); +			} +		} + +		/// <summary> +		/// Block specified node. +		/// +		/// Will unblock the last node that was reserved (if any) +		/// </summary> +		public void Block (GraphNode node) { +			if (node == null) +				throw new System.ArgumentNullException("node"); + +			manager.InternalBlock(node, this); +			lastBlocked = node; +		} + +		/// <summary>Unblock the last node that was blocked (if any)</summary> +		public void Unblock () { +			if (lastBlocked == null || lastBlocked.Destroyed) { +				lastBlocked = null; +				return; +			} + +			manager.InternalUnblock(lastBlocked, this); +			lastBlocked = null; +		} +	} +} diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/TurnBased/SingleNodeBlocker.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/TurnBased/SingleNodeBlocker.cs.meta new file mode 100644 index 0000000..bdd19e7 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/TurnBased/SingleNodeBlocker.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b45e20632f1604fc6bb73e0e79cd7368 +timeCreated: 1451482127 +licenseType: Store +MonoImporter: +  serializedVersion: 2 +  defaultReferences: [] +  executionOrder: 0 +  icon: {instanceID: 0} +  userData:  +  assetBundleName:  +  assetBundleVariant:   | 
