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/ExampleScenes/Scenes/HexagonalTurnBased/TurnBasedManager.cs | |
parent | 3ba4020b69e5971bb0df7ee08b31d10ea4d01937 (diff) |
+ astar project
Diffstat (limited to 'Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/HexagonalTurnBased/TurnBasedManager.cs')
-rw-r--r-- | Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/HexagonalTurnBased/TurnBasedManager.cs | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/HexagonalTurnBased/TurnBasedManager.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/HexagonalTurnBased/TurnBasedManager.cs new file mode 100644 index 0000000..4523399 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/ExampleScenes/Scenes/HexagonalTurnBased/TurnBasedManager.cs @@ -0,0 +1,196 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using Pathfinding; +using Pathfinding.Util; +using UnityEngine.EventSystems; + +namespace Pathfinding.Examples { + /// <summary>Helper script in the example scene 'Turn Based'</summary> + [HelpURL("https://arongranberg.com/astar/documentation/stable/turnbasedmanager.html")] + public class TurnBasedManager : VersionedMonoBehaviour { + TurnBasedAI selected; + + public float movementSpeed; + public GameObject nodePrefab; + public LayerMask layerMask; + + List<GameObject> possibleMoves = new List<GameObject>(); + EventSystem eventSystem; + + public State state = State.SelectUnit; + + public enum State { + SelectUnit, + SelectTarget, + Move + } + + protected override void Awake () { + base.Awake(); + eventSystem = UnityCompatibility.FindAnyObjectByType<EventSystem>(); + } + + void Update () { + var mousePos = Input.mousePosition; + + // If the game view is not active, the mouse position can be infinite + if (!float.IsFinite(mousePos.x)) return; + + Ray ray = Camera.main.ScreenPointToRay(mousePos); + + // Ignore any input while the mouse is over a UI element + if (eventSystem.IsPointerOverGameObject()) { + return; + } + + if (state == State.SelectTarget) { + HandleButtonUnderRay(ray); + } + + if (state == State.SelectUnit || state == State.SelectTarget) { + if (Input.GetKeyDown(KeyCode.Mouse0)) { + var unitUnderMouse = GetByRay<TurnBasedAI>(ray); + + if (unitUnderMouse != null) { + Select(unitUnderMouse); + DestroyPossibleMoves(); + GeneratePossibleMoves(selected); + state = State.SelectTarget; + } + } + } + } + + // TODO: Move to separate class + void HandleButtonUnderRay (Ray ray) { + var button = GetByRay<Astar3DButton>(ray); + + if (button != null && Input.GetKeyDown(KeyCode.Mouse0)) { + button.OnClick(); + + DestroyPossibleMoves(); + state = State.Move; + StartCoroutine(MoveToNode(selected, button.node)); + } + } + + T GetByRay<T>(Ray ray) where T : class { + RaycastHit hit; + + if (Physics.Raycast(ray, out hit, float.PositiveInfinity, layerMask)) { + return hit.transform.GetComponentInParent<T>(); + } + return null; + } + + void Select (TurnBasedAI unit) { + selected = unit; + } + + IEnumerator MoveToNode (TurnBasedAI unit, GraphNode node) { + var path = ABPath.Construct(unit.transform.position, (Vector3)node.position); + + path.traversalProvider = unit.traversalProvider; + + // Schedule the path for calculation + AstarPath.StartPath(path); + + // Wait for the path calculation to complete + yield return StartCoroutine(path.WaitForPath()); + + if (path.error) { + // Not obvious what to do here, but show the possible moves again + // and let the player choose another target node + // Likely a node was blocked between the possible moves being + // generated and the player choosing which node to move to + Debug.LogError("Path failed:\n" + path.errorLog); + state = State.SelectTarget; + GeneratePossibleMoves(selected); + yield break; + } + + // Set the target node so other scripts know which + // node is the end point in the path + unit.targetNode = path.path[path.path.Count - 1]; + + yield return StartCoroutine(MoveAlongPath(unit, path, movementSpeed)); + + unit.blocker.BlockAtCurrentPosition(); + + // Select a new unit to move + state = State.SelectUnit; + } + + /// <summary>[MoveAlongPath]</summary> + /// <summary>Interpolates the unit along the path</summary> + static IEnumerator MoveAlongPath (TurnBasedAI unit, ABPath path, float speed) { + if (path.error || path.vectorPath.Count == 0) + throw new System.ArgumentException("Cannot follow an empty path"); + + // Very simple movement, just interpolate using a catmull-rom spline + float distanceAlongSegment = 0; + for (int i = 0; i < path.vectorPath.Count - 1; i++) { + var p0 = path.vectorPath[Mathf.Max(i-1, 0)]; + // Start of current segment + var p1 = path.vectorPath[i]; + // End of current segment + var p2 = path.vectorPath[i+1]; + var p3 = path.vectorPath[Mathf.Min(i+2, path.vectorPath.Count-1)]; + + // Approximate the length of the spline + var segmentLength = Vector3.Distance(p1, p2); + + // Move the agent forward each frame, until we reach the end of the segment + while (distanceAlongSegment < segmentLength) { + // Use a Catmull-rom spline to smooth the path. See https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Catmull%E2%80%93Rom_spline + var interpolatedPoint = AstarSplines.CatmullRom(p0, p1, p2, p3, distanceAlongSegment / segmentLength); + unit.transform.position = interpolatedPoint; + yield return null; + distanceAlongSegment += Time.deltaTime * speed; + } + + distanceAlongSegment -= segmentLength; + } + + // Move the agent to the final point in the path + unit.transform.position = path.vectorPath[path.vectorPath.Count - 1]; + } + /// <summary>[MoveAlongPath]</summary> + + void DestroyPossibleMoves () { + foreach (var go in possibleMoves) { + GameObject.Destroy(go); + } + possibleMoves.Clear(); + } + + /// <summary>[GeneratePossibleMoves]</summary> + void GeneratePossibleMoves (TurnBasedAI unit) { + var path = ConstantPath.Construct(unit.transform.position, unit.movementPoints * 1000 + 1); + + path.traversalProvider = unit.traversalProvider; + + // Schedule the path for calculation + AstarPath.StartPath(path); + + // Force the path request to complete immediately + // This assumes the graph is small enough that + // this will not cause any lag + path.BlockUntilCalculated(); + + foreach (var node in path.allNodes) { + if (node != path.startNode) { + // Create a new node prefab to indicate a node that can be reached + // NOTE: If you are going to use this in a real game, you might want to + // use an object pool to avoid instantiating new GameObjects all the time + var go = GameObject.Instantiate(nodePrefab, (Vector3)node.position, Quaternion.identity) as GameObject; + possibleMoves.Add(go); + + go.GetComponent<Astar3DButton>().node = node; + } + } + } + /// <summary>[GeneratePossibleMoves]</summary> + } +} |