diff --git a/Paths/Assets/Scripts/Algorithms/AStar.cs b/Paths/Assets/Scripts/Algorithms/AStar.cs index 1c395ad..2a289ce 100644 --- a/Paths/Assets/Scripts/Algorithms/AStar.cs +++ b/Paths/Assets/Scripts/Algorithms/AStar.cs @@ -3,7 +3,7 @@ using UnityEngine; namespace Algorithms { public class AStar : IPathfinding { - private NodeGrid _nodeGrid; + public NodeGrid NodeGrid { get; private set; } private Stack _path; private List _openList; @@ -14,7 +14,7 @@ namespace Algorithms { public Vector2Int End { get; private set; } public AStar(NodeGrid nodeGrid) { - this._nodeGrid = nodeGrid; + this.NodeGrid = nodeGrid; ChangeController = new ChangeController(nodeGrid.RenderNodeTypes()); } @@ -25,8 +25,8 @@ namespace Algorithms { ChangeController.AddChange(new Change(start.x, start.y, GridNodeType.Start, GridNodeType.Empty)); ChangeController.AddChange(new Change(end.x, end.y, GridNodeType.End, GridNodeType.Empty)); - Node startNode = _nodeGrid.Grid[start.x, start.y]; - Node endNode = _nodeGrid.Grid[end.x, end.y]; + Node startNode = NodeGrid.Grid[start.x, start.y]; + Node endNode = NodeGrid.Grid[end.x, end.y]; _path = new Stack(); _openList = new List(); @@ -51,7 +51,7 @@ namespace Algorithms { if (current.Position == endNode.Position) break; - Node[] adjacentNodes = this._nodeGrid.GetAdjacentNodesArray(current); + Node[] adjacentNodes = this.NodeGrid.GetAdjacentNodesArray(current); for (int i = 0; i < adjacentNodes.Length; i++) { Node node = adjacentNodes[i]; if (node != null && node.State == NodeState.None && node.Walkable) { @@ -91,5 +91,6 @@ namespace Algorithms { return _path; } + } } \ No newline at end of file diff --git a/Paths/Assets/Scripts/Algorithms/NodeGrid.cs b/Paths/Assets/Scripts/Algorithms/NodeGrid.cs index fdb059d..b3bf83f 100644 --- a/Paths/Assets/Scripts/Algorithms/NodeGrid.cs +++ b/Paths/Assets/Scripts/Algorithms/NodeGrid.cs @@ -51,6 +51,14 @@ namespace Algorithms { return temp; } + public bool IsValid(Node node) { + return IsValid(node.Position); + } + + public bool IsValid(Vector2Int position) { + return position.x >= 0 && position.y >= 0 && position.x < Width && position.y < Height; + } + public Node[] GetAdjacentNodesArray(Node node) { int col = node.Position.x; int row = node.Position.y; diff --git a/Paths/Assets/Scripts/GridController.cs b/Paths/Assets/Scripts/GridController.cs index 8b7ac18..9ce74a1 100644 --- a/Paths/Assets/Scripts/GridController.cs +++ b/Paths/Assets/Scripts/GridController.cs @@ -25,7 +25,7 @@ public class GridController : MonoBehaviour { private static readonly int Values = Shader.PropertyToID("_values"); private static readonly int GridWidth = Shader.PropertyToID("_GridWidth"); private static readonly int GridHeight = Shader.PropertyToID("_GridHeight"); - public Vector2 Size => new Vector2Int(width, height); + public Vector2Int Size => new Vector2Int(width, height); private void Start() { _values = new int[width * height]; @@ -131,4 +131,32 @@ public class GridController : MonoBehaviour { public int GetIndex(int x, int y) { return width * y + x; } + + /// + /// Translate a world position to the approximate position on the Grid. + /// May not return valid grid coordinates (outside the range). + /// + /// a Vector3 World Position; Z coordinates are inconsequential. + /// A Vector2Int representing a grid position from the bottom left. + public Vector2Int GetGridPosition(Vector3 worldPosition) { + Vector3 localScale = transform.localScale; + Vector2 gridPosition = (worldPosition + (localScale / 2f)) / new Vector2(localScale.x, localScale.y); + return new Vector2Int( + (int) (gridPosition.x * width), + (int) (gridPosition.y * height)) - Size - Vector2Int.one; + } + + /// + /// Translates a position on the grid into a real World Position. + /// + /// The XY position on the grid + /// A Vector3 centered on the grid square in the World + public Vector3 GetWorldPosition(Vector2Int gridPosition) { + Transform ttransform = transform; + Vector3 localScale = ttransform.localScale; + Vector2 bottomLeft = ttransform.position - (localScale / 2f); + var singleSquare = new Vector2(localScale.x / width, localScale.y / height); + Vector2 worldPosition = bottomLeft + (singleSquare * gridPosition) + (singleSquare / 2f); + return worldPosition; + } } \ No newline at end of file diff --git a/Paths/Assets/Scripts/IPathfinding.cs b/Paths/Assets/Scripts/IPathfinding.cs index 6707545..b1d0c2a 100644 --- a/Paths/Assets/Scripts/IPathfinding.cs +++ b/Paths/Assets/Scripts/IPathfinding.cs @@ -13,7 +13,7 @@ public interface IPathfinding { /// The position trying to be found via pathfinding /// A List of NodeGridGrid objects representing the timeline of Pathfinding Stack FindPath(Vector2Int start, Vector2Int end); - + NodeGrid NodeGrid { get; } Vector2Int Start { get; } Vector2Int End { get; } ChangeController ChangeController { get; } diff --git a/Paths/Assets/Scripts/Manager.cs b/Paths/Assets/Scripts/Manager.cs index 4f49426..385a102 100644 --- a/Paths/Assets/Scripts/Manager.cs +++ b/Paths/Assets/Scripts/Manager.cs @@ -27,7 +27,6 @@ public class Manager : MonoBehaviour { public TextMeshPro debugText; public Slider progressSlider; private float? _moveTo; - private bool _allowPausing = true; private int CurrentIndex { get => (int) _runtime; @@ -49,38 +48,27 @@ public class Manager : MonoBehaviour { _runtime = @new * _state.Count; } - Vector2 GetGridPosition(Vector3 worldPosition, Vector3 scale) { - Vector2 gridPosition = (worldPosition + (scale / 2f)) / new Vector2(scale.x, scale.y); - gridPosition = new Vector2Int( - (int) (gridPosition.x * gridController.width), - (int) (gridPosition.y * gridController.height)); - return gridPosition; - } - - Vector3 GetWorldPosition(Vector2 gridPosition, Vector3 scale) { - Vector2 bottomLeft = gridObject.transform.position - (scale / 2f); - Vector2 singleSquare = new Vector2(scale.x / gridController.width, scale.y / gridController.height); - Vector2 worldPosition = bottomLeft + (singleSquare * gridPosition) + (singleSquare / 2f); - return worldPosition; - } + public void OnDrawGizmos() { - Vector3 mouse = mainCamera.ScreenToWorldPoint(Input.mousePosition); - var localScale = gridObject.transform.localScale; - Vector2 gridPosition = GetGridPosition(mouse, localScale); + if (!Application.isPlaying) return; + Vector3 mouse = mainCamera.ScreenToWorldPoint(Input.mousePosition); + Vector3 localScale = gridObject.transform.localScale; + Vector2Int gridPosition = GetGridPosition(mouse, localScale); + Vector2Int realGridPosition = gridController.Size - gridPosition - Vector2Int.one; + var style = new GUIStyle(); style.normal.textColor = Color.blue; Gizmos.color = Color.blue; - var mouseWorldPosition = new Vector3( - (gridPosition.x / gridController.width * 10) - (localScale.x / 2f), - (gridPosition.y / gridController.height * 10) - (localScale.y / 2f), - mouse.z - ); - // Gizmos.DrawCube(GetWorldPosition(gridPosition, localScale), Vector3.one / 5f); - Gizmos.DrawWireCube(GetWorldPosition(gridPosition, localScale), localScale / gridController.Size); - Handles.Label(mouse, $"({gridPosition.x} {gridPosition.y})\n{mouse.x:F} {mouse.y:F}", style); + Gizmos.DrawWireCube(GetWorldPosition(gridPosition, localScale), localScale / (Vector2) gridController.Size); + Handles.Label(mouse, String.Format("{0}{1}", + gridPosition, + _algorithm.NodeGrid.IsValid(gridPosition) + ? $"\n{_state.Current[realGridPosition.x, realGridPosition.y]}" + : "" + ), style); } /// @@ -115,10 +103,15 @@ public class Manager : MonoBehaviour { public void Update() { // Toggle pause with space - if (_allowPausing && Input.GetKeyDown(KeyCode.Space)) { + if (Input.GetKeyDown(KeyCode.Space)) { moving = !moving; } + if (Input.GetKeyDown(KeyCode.G)) { + GeneratePath(); + return; + } + // Increment index if unpaused and not clicking (implying slider may be interacted with) if (moving && !Input.GetMouseButton(0)) { var increment = Time.deltaTime * speed * CurrentMultiplier(); @@ -130,10 +123,6 @@ public class Manager : MonoBehaviour { // Load next state in grid or update text if (CurrentIndex < _state.Count) LoadNextState(); - else { - // No new states to load, generate new grid - GeneratePath(); - } // Update progress slider silently progressSlider.SetValueWithoutNotify(_runtime / _state.Count); @@ -146,8 +135,8 @@ public class Manager : MonoBehaviour { CurrentIndex = 0; var nodeGrid = new NodeGrid(gridController.width, gridController.height); - Vector2Int start = nodeGrid.RandomPosition(); - // Vector2Int start = new Vector2Int(30, 30); + // Vector2Int start = nodeGrid.RandomPosition(); + Vector2Int start = new Vector2Int(3, 6); Vector2Int end = nodeGrid.RandomPosition(); nodeGrid.ApplyGenerator(new RandomPlacement(0.3f, true, true)); @@ -164,7 +153,7 @@ public class Manager : MonoBehaviour { /// Loads the appropriate grid state into the shader via the ChangeController instance. /// private void LoadNextState() { - _state.MoveTo(CurrentIndex); + _state.MoveTo(Math.Max(1, CurrentIndex)); // use Math.max to ensure both start/end nodes are always rendered gridController.LoadDirtyGridState(_state.Current, _state.DirtyFlags); string pathCount = _path != null ? $"{_path.Count}" : "N/A";