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: |