From 67dd0f07716034b50b16233dbda5b4f85405e2de Mon Sep 17 00:00:00 2001 From: Xevion Date: Wed, 25 Nov 2020 02:28:43 -0600 Subject: [PATCH 1/9] add movable slider, add space pause and left click freeze keybinds, fix change controller issues with reversing --- Paths/Assets/Scripts/ChangeController.cs | 2 +- Paths/Assets/Scripts/Manager.cs | 52 ++++++++++++++++++------ Paths/Assets/Shaders/GridShader.shader | 2 +- 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/Paths/Assets/Scripts/ChangeController.cs b/Paths/Assets/Scripts/ChangeController.cs index 1f084b9..db6c5e8 100644 --- a/Paths/Assets/Scripts/ChangeController.cs +++ b/Paths/Assets/Scripts/ChangeController.cs @@ -92,7 +92,7 @@ public class ChangeController { Reset(); // resetting by copying values instead of mutating might be easier. else { for (int i = 0; i < n; i++) { - Change cur = _changes[--Index]; + Change cur = _changes[Index--]; // post decrement as we apply the current Change's old, not the previous Current[cur.X, cur.Y] = cur.Old; SetDirty(new Vector2Int(cur.X, cur.Y)); } diff --git a/Paths/Assets/Scripts/Manager.cs b/Paths/Assets/Scripts/Manager.cs index 81ea5b8..c1e3407 100644 --- a/Paths/Assets/Scripts/Manager.cs +++ b/Paths/Assets/Scripts/Manager.cs @@ -3,8 +3,9 @@ using System.Collections.Generic; using Algorithms; using LevelGeneration; using TMPro; +using UnityEditor; using UnityEngine; -using UnityEngine.Analytics; +using UnityEngine.UI; /// /// The primary controller of the entire application, managing state, events and sending commands @@ -16,12 +17,17 @@ public class Manager : MonoBehaviour { private Stack _path; private float _runtime; + public float speed; + public float clampIncrement; + public bool moving = true; + public Camera mainCamera; public GameObject gridObject; public GridController gridController; public TextMeshPro debugText; - public float speed; - public float clampIncrement; + public Slider progressSlider; + private float? _moveTo; + private bool _allowPausing = true; private int CurrentIndex { get => (int) _runtime; @@ -31,6 +37,8 @@ public class Manager : MonoBehaviour { public void Start() { GeneratePath(); Resize(); + + progressSlider.onValueChanged.AddListener((value) => MoveToSlider(value)); } // public void OnDrawGizmos() { @@ -45,10 +53,10 @@ public class Manager : MonoBehaviour { private float CurrentMultiplier() { if (_state.Index == -1) return 1; - + switch (_state.CurrentChange.New) { case GridNodeType.Path: - return 1/5f; + return 1 / 5f; case GridNodeType.Empty: break; case GridNodeType.Wall: @@ -64,24 +72,41 @@ public class Manager : MonoBehaviour { default: throw new ArgumentOutOfRangeException(); } + return 1; } - - public void Update() { - var increment = Time.deltaTime * speed * CurrentMultiplier(); - if (clampIncrement > 0) - increment = Mathf.Clamp(increment, 0, _state.Count * Time.deltaTime / clampIncrement); - _runtime += increment; + public void Update() { + // Toggle pause with space + if (_allowPausing && Input.GetKeyDown(KeyCode.Space)) { + moving = !moving; + } + + // Increment index if unpaused and not clicking (implying slider may be interacted with) + if (moving && !Input.GetMouseButton(0)) { + var increment = Time.deltaTime * speed * CurrentMultiplier(); + if (clampIncrement > 0) + increment = Mathf.Clamp(increment, 0, _state.Count * Time.deltaTime / clampIncrement); + _runtime += increment; + } + + // Load next state in grid or update text if (CurrentIndex < _state.Count) LoadNextState(); else { + // No new states to load, generate new grid GeneratePath(); - CurrentIndex = 0; } + + // Update progress slider silently + progressSlider.SetValueWithoutNotify(_runtime / _state.Count); } + /// + /// Generates a new grid and runs pathfinding. + /// private void GeneratePath() { + CurrentIndex = 0; var nodeGrid = new NodeGrid(gridController.width, gridController.height); Vector2Int start = nodeGrid.RandomPosition(); @@ -98,6 +123,9 @@ public class Manager : MonoBehaviour { _state = _algorithm.ChangeController; } + /// + /// Loads the appropriate grid state into the shader via the ChangeController instance. + /// private void LoadNextState() { _state.MoveTo(CurrentIndex); gridController.LoadDirtyGridState(_state.Current, _state.DirtyFlags); diff --git a/Paths/Assets/Shaders/GridShader.shader b/Paths/Assets/Shaders/GridShader.shader index 9f97a04..fe4a044 100644 --- a/Paths/Assets/Shaders/GridShader.shader +++ b/Paths/Assets/Shaders/GridShader.shader @@ -41,7 +41,7 @@ Shader "PDT Shaders/TestGrid" static const float4 _gridColors[7] = { float4(255 / 255.0, 255 / 255.0, 255 / 255.0, 1.0), // Empty - float4(0 / 255.0, 0 / 255.0, 0 / 255.0, 1.0), // Wall + float4(5 / 255.0, 5 / 255.0, 5 / 255.0, 1.0), // Wall float4(0 / 255.0, 255 / 255.0, 0 / 255.0, 1.0), // Start float4(255 / 255.0, 0 / 255.0, 0 / 255.0, 1.0), // End float4(252 / 255.0, 236 / 255.0, 3 / 255.0, 1.0), // Seen From 592334dbaf019ef52597e630b84404ed366b3eba Mon Sep 17 00:00:00 2001 From: Xevion Date: Wed, 25 Nov 2020 02:29:15 -0600 Subject: [PATCH 2/9] work on back and forth calculating grid/world positions from mouse --- Paths/Assets/Scripts/GridController.cs | 1 + Paths/Assets/Scripts/Manager.cs | 45 +++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/Paths/Assets/Scripts/GridController.cs b/Paths/Assets/Scripts/GridController.cs index 60558e3..8b7ac18 100644 --- a/Paths/Assets/Scripts/GridController.cs +++ b/Paths/Assets/Scripts/GridController.cs @@ -25,6 +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); private void Start() { _values = new int[width * height]; diff --git a/Paths/Assets/Scripts/Manager.cs b/Paths/Assets/Scripts/Manager.cs index c1e3407..4f49426 100644 --- a/Paths/Assets/Scripts/Manager.cs +++ b/Paths/Assets/Scripts/Manager.cs @@ -41,10 +41,47 @@ public class Manager : MonoBehaviour { progressSlider.onValueChanged.AddListener((value) => MoveToSlider(value)); } - // public void OnDrawGizmos() { - // float size = (float) (10.0 / gridController.size); - // Gizmos.DrawWireCube(transform.position, new Vector3(size, size, size)); - // } + /// + /// Update the animation progress to the slider's (new) position. + /// + /// The new position on the slider. + private void MoveToSlider(float @new) { + _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); + + 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); + } /// /// Returns the current time multiplier, based on the latest change in the path. From ba7fd44d6569aed16b517ecfbb5f2347b458b2bb Mon Sep 17 00:00:00 2001 From: Xevion Date: Wed, 25 Nov 2020 09:20:30 -0600 Subject: [PATCH 3/9] small fixes to coordinate checking in Gizmo drawing, move to GridController/cleanup add docs --- Paths/Assets/Scripts/Algorithms/AStar.cs | 11 ++-- Paths/Assets/Scripts/Algorithms/NodeGrid.cs | 8 +++ Paths/Assets/Scripts/GridController.cs | 30 ++++++++++- Paths/Assets/Scripts/IPathfinding.cs | 2 +- Paths/Assets/Scripts/Manager.cs | 57 +++++++++------------ 5 files changed, 67 insertions(+), 41 deletions(-) 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"; From 0fa97de715e32558fa31aa813b474c214d10fa8a Mon Sep 17 00:00:00 2001 From: Xevion Date: Wed, 25 Nov 2020 10:24:15 -0600 Subject: [PATCH 4/9] new UIController allowing grid editing & start/end node movement, complete grid editing logic, beginnings of animation state logic --- Paths/Assets/Scripts/UIController.cs | 130 ++++++++++++++++++++++ Paths/Assets/Scripts/UIController.cs.meta | 3 + 2 files changed, 133 insertions(+) create mode 100644 Paths/Assets/Scripts/UIController.cs create mode 100644 Paths/Assets/Scripts/UIController.cs.meta diff --git a/Paths/Assets/Scripts/UIController.cs b/Paths/Assets/Scripts/UIController.cs new file mode 100644 index 0000000..76dded3 --- /dev/null +++ b/Paths/Assets/Scripts/UIController.cs @@ -0,0 +1,130 @@ +using System; +using Algorithms; +using UnityEngine; +using UnityEngine.UI; + +/// +/// Denotes what the user clicked and is now modifying. +/// Add/Remove is for wall addition/removal, Start and End is for dragging the Start and End nodes around. +/// +public enum ClickType { + Add, + Remove, + Start, + End +} + +/// +/// Denotes the precise state of the animation as the user clicks, stops or starts it. +/// Stopped is a full stop, allowing editing and manipulation. The path will not be shown or generated. +/// Started is fully engaged when the user is not currently editing or manipulating. +/// Reloading occurs when the user manipulates the grid while the program is +/// +public enum AnimationState { + Stopped, + Started, + Reloading +} + +/// +/// A expansive class that controls all UI interactions including grid modifications, slider movement, tool usage etc. +/// All UI elements are referenced and controlled here. +/// +public class UIController : MonoBehaviour { + public Slider progressSlider; + public GridController gridController; + public Manager manager; + + private Vector2Int _lastClickLocation; + private ClickType _modify; + private AnimationState _animating; + + private NodeGrid _grid; + private Vector2Int _start; + private Vector2Int _end; + + private void Start() { + _grid = new NodeGrid(gridController.width, gridController.height); + _animating = AnimationState.Stopped; + _start = _grid.RandomPosition(); + _end = _grid.RandomPosition(); + } + + private void Update() { + if (Input.GetMouseButton(0)) { + Vector3 worldMouse = manager.mainCamera.ScreenToWorldPoint(Input.mousePosition); + Vector2Int position = gridController.GetGridPosition(worldMouse); + + // Initial click, remember what they clicked + if (Input.GetMouseButtonDown(0)) { + if (position == _start) + _modify = ClickType.Start; + else if (position == _end) + _modify = ClickType.End; + else { + Node node = _grid.GetNode(position); + _modify = node.Walkable ? ClickType.Add : ClickType.Remove; + node.Walkable = !node.Walkable; + } + + _lastClickLocation = position; + } + else { + // If still holding down the button & the latest movement is over a new grid + if (_lastClickLocation != position) { + _lastClickLocation = position; + Node node = _grid.GetNode(position); + switch (_modify) { + // regular clicking toggles walls + // Note: Wall toggling instantly reloads, but only real start/end node movement reloads. + case ClickType.Add: + node.Walkable = false; + _animating = AnimationState.Reloading; + break; + case ClickType.Remove: + node.Walkable = true; + _animating = AnimationState.Reloading; + break; + case ClickType.Start: + if (node.Walkable) { + _start = position; + if (_animating == AnimationState.Started) + _animating = AnimationState.Reloading; + } + + break; + case ClickType.End: + if (node.Walkable) { + _end = position; + if (_animating == AnimationState.Started) + _animating = AnimationState.Reloading; + } + + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + } + } + + if (_animating == AnimationState.Reloading) { + } + else if (_animating == AnimationState.Started) { + } + + gridController.LoadGridState(_grid.RenderNodeTypes(_start, _end)); + } + + /// + /// Generates the path and sets up the UI Controller to begin animation. + /// + private void StartAnimation() { + } + + /// + /// Stops the path animation and readies the UI Controller for grid editing. + /// + private void StopAnimation() { + } +} \ No newline at end of file diff --git a/Paths/Assets/Scripts/UIController.cs.meta b/Paths/Assets/Scripts/UIController.cs.meta new file mode 100644 index 0000000..1c1c16b --- /dev/null +++ b/Paths/Assets/Scripts/UIController.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fd9c76568dd84a92b068dd1e622bd101 +timeCreated: 1606316179 \ No newline at end of file From 6ee263cfac7586850f8a5cadfbb86c95fe3f0e81 Mon Sep 17 00:00:00 2001 From: Xevion Date: Wed, 25 Nov 2020 11:39:20 -0600 Subject: [PATCH 5/9] animation state handling (stopping/start/pausing/reloading) while editing, add cleanup code to algorithm, path generation and iteration, move gizmos from manager --- Paths/Assets/Scripts/Algorithms/AStar.cs | 19 +++ Paths/Assets/Scripts/Algorithms/Node.cs | 10 ++ Paths/Assets/Scripts/Algorithms/NodeGrid.cs | 9 +- Paths/Assets/Scripts/UIController.cs | 168 +++++++++++++++++--- 4 files changed, 187 insertions(+), 19 deletions(-) diff --git a/Paths/Assets/Scripts/Algorithms/AStar.cs b/Paths/Assets/Scripts/Algorithms/AStar.cs index 2a289ce..aafc771 100644 --- a/Paths/Assets/Scripts/Algorithms/AStar.cs +++ b/Paths/Assets/Scripts/Algorithms/AStar.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using UnityEngine; namespace Algorithms { @@ -92,5 +93,23 @@ namespace Algorithms { return _path; } + /// + /// Attempts to clean the NodeGrid of all edits made to heuristic values and such, fast. + /// + public void Cleanup() { + while (_openList.Count > 0) { + Node node = _openList[0]; + _openList.RemoveAt(0); + + node.Reset(); + } + + while (_closedList.Count > 0) { + Node node = _closedList[0]; + _closedList.RemoveAt(0); + + node.Reset(); + } + } } } \ No newline at end of file diff --git a/Paths/Assets/Scripts/Algorithms/Node.cs b/Paths/Assets/Scripts/Algorithms/Node.cs index faab057..ae79d90 100644 --- a/Paths/Assets/Scripts/Algorithms/Node.cs +++ b/Paths/Assets/Scripts/Algorithms/Node.cs @@ -37,6 +37,16 @@ namespace Algorithms { Walkable = walkable; } + /// + /// Resets this Node back to it's assumed default values. + /// + public void Reset() { + Parent = null; + DistanceToTarget = null; + Cost = 1; + State = NodeState.None; + } + public override bool Equals(object obj) { return obj is Node node && Position.Equals(node.Position); } diff --git a/Paths/Assets/Scripts/Algorithms/NodeGrid.cs b/Paths/Assets/Scripts/Algorithms/NodeGrid.cs index b3bf83f..12a0287 100644 --- a/Paths/Assets/Scripts/Algorithms/NodeGrid.cs +++ b/Paths/Assets/Scripts/Algorithms/NodeGrid.cs @@ -147,7 +147,7 @@ namespace Algorithms { } } - public GridNodeType[,] RenderNodeTypes() { + public GridNodeType[,] RenderNodeTypes(Vector2Int? start = null, Vector2Int? end = null) { GridNodeType[,] nodeTypeGrid = new GridNodeType[Grid.GetLength(0), Grid.GetLength(1)]; for (int x = 0; x < Grid.GetLength(0); x++) { @@ -156,6 +156,13 @@ namespace Algorithms { } } + // Start / End node addition + if (start.HasValue) + nodeTypeGrid[start.Value.x, start.Value.y] = GridNodeType.Start; + + if (end.HasValue) + nodeTypeGrid[end.Value.x, end.Value.y] = GridNodeType.End; + return nodeTypeGrid; } } diff --git a/Paths/Assets/Scripts/UIController.cs b/Paths/Assets/Scripts/UIController.cs index 76dded3..c2111be 100644 --- a/Paths/Assets/Scripts/UIController.cs +++ b/Paths/Assets/Scripts/UIController.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using Algorithms; +using UnityEditor; using UnityEngine; using UnityEngine.UI; @@ -22,6 +24,7 @@ public enum ClickType { /// public enum AnimationState { Stopped, + Paused, Started, Reloading } @@ -31,23 +34,41 @@ public enum AnimationState { /// All UI elements are referenced and controlled here. /// public class UIController : MonoBehaviour { + // UI & important App references public Slider progressSlider; public GridController gridController; public Manager manager; + // Animation State, Click Management private Vector2Int _lastClickLocation; private ClickType _modify; - private AnimationState _animating; + private AnimationState _animationState; + private AnimationState _previousAnimationState; + private bool EditShouldReload => + _animationState == AnimationState.Started || _animationState == AnimationState.Paused; + + // Grid State & Pathfinding private NodeGrid _grid; private Vector2Int _start; private Vector2Int _end; + private IPathfinding _algorithm; + private Stack _path; + private ChangeController _state; + + // Animation speed & indexing + public float clampIncrement; + private float _runtime; + public int CurrentIndex => (int) _runtime; + public float speed; private void Start() { _grid = new NodeGrid(gridController.width, gridController.height); - _animating = AnimationState.Stopped; + _animationState = AnimationState.Stopped; + _previousAnimationState = _animationState; _start = _grid.RandomPosition(); _end = _grid.RandomPosition(); + _runtime = 0; } private void Update() { @@ -65,6 +86,8 @@ public class UIController : MonoBehaviour { Node node = _grid.GetNode(position); _modify = node.Walkable ? ClickType.Add : ClickType.Remove; node.Walkable = !node.Walkable; + if (EditShouldReload) + _animationState = AnimationState.Reloading; } _lastClickLocation = position; @@ -79,25 +102,27 @@ public class UIController : MonoBehaviour { // Note: Wall toggling instantly reloads, but only real start/end node movement reloads. case ClickType.Add: node.Walkable = false; - _animating = AnimationState.Reloading; + if (EditShouldReload) + _animationState = AnimationState.Reloading; break; case ClickType.Remove: node.Walkable = true; - _animating = AnimationState.Reloading; + if (EditShouldReload) + _animationState = AnimationState.Reloading; break; case ClickType.Start: if (node.Walkable) { _start = position; - if (_animating == AnimationState.Started) - _animating = AnimationState.Reloading; + if (EditShouldReload) + _animationState = AnimationState.Reloading; } break; case ClickType.End: if (node.Walkable) { _end = position; - if (_animating == AnimationState.Started) - _animating = AnimationState.Reloading; + if (EditShouldReload) + _animationState = AnimationState.Reloading; } break; @@ -108,23 +133,130 @@ public class UIController : MonoBehaviour { } } - if (_animating == AnimationState.Reloading) { - } - else if (_animating == AnimationState.Started) { + // Handle user start/stopping + if (Input.GetKeyDown(KeyCode.Space)) { + switch (_animationState) { + case AnimationState.Stopped: + _animationState = AnimationState.Reloading; + break; + case AnimationState.Paused: + _animationState = AnimationState.Started; + break; + case AnimationState.Started: + _animationState = AnimationState.Paused; + break; + case AnimationState.Reloading: + break; + default: + throw new ArgumentOutOfRangeException(); + } } - gridController.LoadGridState(_grid.RenderNodeTypes(_start, _end)); + switch (_animationState) { + case AnimationState.Reloading: + if (!Input.GetMouseButton(0)) { + GeneratePath(); + LoadNextState(); + _animationState = AnimationState.Started; + } + else + gridController.LoadGridState(_grid.RenderNodeTypes(_start, _end)); + + break; + case AnimationState.Started: + // Calculate how much to move forward + var increment = Time.deltaTime * speed * CurrentMultiplier(); + if (clampIncrement > 0) + increment = Mathf.Clamp(increment, 0, _state.Count * Time.deltaTime / clampIncrement); + _runtime += increment; + + if (CurrentIndex < _state.Count) + LoadNextState(); + break; + case AnimationState.Stopped: + gridController.LoadGridState(_grid.RenderNodeTypes(_start, _end)); + break; + case AnimationState.Paused: + break; + default: + throw new ArgumentOutOfRangeException(); + } + + if (_animationState != _previousAnimationState) { + Debug.Log($"Animation State {_previousAnimationState} -> {_animationState}"); + _previousAnimationState = _animationState; + } + } + + private void GeneratePath() { + if (_algorithm != null) + _algorithm.Cleanup(); + + _runtime = 0f; + _algorithm = new AStar(_grid); + _path = _algorithm.FindPath(_start, _end); + // Debug.Log($"{_state.Count} changs made"); + _state = _algorithm.ChangeController; + } + + private void LoadNextState() { + // Move to the new calculated index + _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"; + manager.debugText.text = $"{_state.CurrentRuntime * 1000.0:F1}ms\n" + + $"{CurrentIndex:000} / {_state.Count:000}\n" + + $"Path: {pathCount} tiles"; } /// - /// Generates the path and sets up the UI Controller to begin animation. + /// Returns the current time multiplier, based on the latest change in the path. /// - private void StartAnimation() { + /// A positive non-zero float representing how fast the current frame should be processed. + private float CurrentMultiplier() { + if (_state.Index == -1) + return 1; + + switch (_state.CurrentChange.New) { + case GridNodeType.Path: + return 1 / 5f; + case GridNodeType.Empty: + break; + case GridNodeType.Wall: + break; + case GridNodeType.Start: + break; + case GridNodeType.End: + break; + case GridNodeType.Seen: + break; + case GridNodeType.Expanded: + break; + default: + throw new ArgumentOutOfRangeException(); + } + + return 1; } - /// - /// Stops the path animation and readies the UI Controller for grid editing. - /// - private void StopAnimation() { + public void OnDrawGizmos() { + if (!Application.isPlaying) return; + + Vector3 mouse = manager.mainCamera.ScreenToWorldPoint(Input.mousePosition); + Vector3 localScale = manager.gridObject.transform.localScale; + Vector2Int gridPosition = gridController.GetGridPosition(mouse); + + var style = new GUIStyle(); + style.normal.textColor = Color.blue; + Gizmos.color = Color.blue; + + Gizmos.DrawWireCube(gridController.GetWorldPosition(gridPosition), localScale / (Vector2) gridController.Size); + Handles.Label(mouse, String.Format("{0}{1}", + gridPosition, + _algorithm.NodeGrid.IsValid(gridPosition) + ? $"\n{_state.Current[gridPosition.x, gridPosition.y]}" + : "" + ), style); } } \ No newline at end of file From 61cf4f158c5e71e4205bc400c3528abb6332dfb2 Mon Sep 17 00:00:00 2001 From: Xevion Date: Wed, 25 Nov 2020 13:03:30 -0600 Subject: [PATCH 6/9] fix progress slider with custom slider, fix last few path changes not being loaded, fix invalid mouse positions being considered --- Paths/Assets/Scripts/CustomSlider.cs | 17 ++++ Paths/Assets/Scripts/CustomSlider.cs.meta | 3 + Paths/Assets/Scripts/UIController.cs | 114 ++++++++++++++-------- 3 files changed, 91 insertions(+), 43 deletions(-) create mode 100644 Paths/Assets/Scripts/CustomSlider.cs create mode 100644 Paths/Assets/Scripts/CustomSlider.cs.meta diff --git a/Paths/Assets/Scripts/CustomSlider.cs b/Paths/Assets/Scripts/CustomSlider.cs new file mode 100644 index 0000000..cda0ebe --- /dev/null +++ b/Paths/Assets/Scripts/CustomSlider.cs @@ -0,0 +1,17 @@ +using UnityEngine.EventSystems; +using UnityEngine.UI; + +public class CustomSlider: Slider { + public bool IsPressed { get; private set; } + + public override void OnPointerDown(PointerEventData eventData) + { + base.OnPointerDown(eventData); + IsPressed = true; + } + + public override void OnPointerUp(PointerEventData eventData) { + base.OnPointerUp(eventData); + IsPressed = false; + } +} \ No newline at end of file diff --git a/Paths/Assets/Scripts/CustomSlider.cs.meta b/Paths/Assets/Scripts/CustomSlider.cs.meta new file mode 100644 index 0000000..6df6158 --- /dev/null +++ b/Paths/Assets/Scripts/CustomSlider.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1502f97daf7446a48b977b5b7fa485ad +timeCreated: 1606327381 \ No newline at end of file diff --git a/Paths/Assets/Scripts/UIController.cs b/Paths/Assets/Scripts/UIController.cs index c2111be..bc47bb9 100644 --- a/Paths/Assets/Scripts/UIController.cs +++ b/Paths/Assets/Scripts/UIController.cs @@ -5,6 +5,7 @@ using UnityEditor; using UnityEngine; using UnityEngine.UI; + /// /// Denotes what the user clicked and is now modifying. /// Add/Remove is for wall addition/removal, Start and End is for dragging the Start and End nodes around. @@ -13,7 +14,8 @@ public enum ClickType { Add, Remove, Start, - End + End, + ProgressBar } /// @@ -35,7 +37,7 @@ public enum AnimationState { /// public class UIController : MonoBehaviour { // UI & important App references - public Slider progressSlider; + public CustomSlider progressSlider; public GridController gridController; public Manager manager; @@ -59,7 +61,7 @@ public class UIController : MonoBehaviour { // Animation speed & indexing public float clampIncrement; private float _runtime; - public int CurrentIndex => (int) _runtime; + public int CurrentIndex => (int) Math.Ceiling(_runtime); public float speed; private void Start() { @@ -69,6 +71,9 @@ public class UIController : MonoBehaviour { _start = _grid.RandomPosition(); _end = _grid.RandomPosition(); _runtime = 0; + + manager.Resize(); + progressSlider.onValueChanged.AddListener((value) => MoveToSlider(value)); } private void Update() { @@ -78,7 +83,9 @@ public class UIController : MonoBehaviour { // Initial click, remember what they clicked if (Input.GetMouseButtonDown(0)) { - if (position == _start) + if (progressSlider.IsPressed) + _modify = ClickType.ProgressBar; + else if (position == _start) _modify = ClickType.Start; else if (position == _end) _modify = ClickType.End; @@ -96,38 +103,42 @@ public class UIController : MonoBehaviour { // If still holding down the button & the latest movement is over a new grid if (_lastClickLocation != position) { _lastClickLocation = position; - Node node = _grid.GetNode(position); - switch (_modify) { - // regular clicking toggles walls - // Note: Wall toggling instantly reloads, but only real start/end node movement reloads. - case ClickType.Add: - node.Walkable = false; - if (EditShouldReload) - _animationState = AnimationState.Reloading; - break; - case ClickType.Remove: - node.Walkable = true; - if (EditShouldReload) - _animationState = AnimationState.Reloading; - break; - case ClickType.Start: - if (node.Walkable) { - _start = position; + if (_grid.IsValid(position)) { + Node node = _grid.GetNode(position); + switch (_modify) { + // regular clicking toggles walls + // Note: Wall toggling instantly reloads, but only real start/end node movement reloads. + case ClickType.Add: + node.Walkable = false; if (EditShouldReload) _animationState = AnimationState.Reloading; - } - - break; - case ClickType.End: - if (node.Walkable) { - _end = position; + break; + case ClickType.Remove: + node.Walkable = true; if (EditShouldReload) _animationState = AnimationState.Reloading; - } + break; + case ClickType.Start: + if (node.Walkable) { + _start = position; + if (EditShouldReload) + _animationState = AnimationState.Reloading; + } - break; - default: - throw new ArgumentOutOfRangeException(); + break; + case ClickType.End: + if (node.Walkable) { + _end = position; + if (EditShouldReload) + _animationState = AnimationState.Reloading; + } + + break; + case ClickType.ProgressBar: + break; + default: + throw new ArgumentOutOfRangeException(); + } } } } @@ -143,7 +154,10 @@ public class UIController : MonoBehaviour { _animationState = AnimationState.Started; break; case AnimationState.Started: - _animationState = AnimationState.Paused; + if (CurrentIndex >= _state.Count) + _runtime = 0; + else + _animationState = AnimationState.Paused; break; case AnimationState.Reloading: break; @@ -162,21 +176,28 @@ public class UIController : MonoBehaviour { else gridController.LoadGridState(_grid.RenderNodeTypes(_start, _end)); + progressSlider.SetValueWithoutNotify(_runtime / _state.Count); break; case AnimationState.Started: // Calculate how much to move forward - var increment = Time.deltaTime * speed * CurrentMultiplier(); - if (clampIncrement > 0) - increment = Mathf.Clamp(increment, 0, _state.Count * Time.deltaTime / clampIncrement); - _runtime += increment; + if (!progressSlider.IsPressed) { + var increment = Time.deltaTime * speed * CurrentMultiplier(); + if (clampIncrement > 0) + increment = Mathf.Clamp(increment, 0, _state.Count * Time.deltaTime / clampIncrement); + _runtime += increment; + } - if (CurrentIndex < _state.Count) + progressSlider.SetValueWithoutNotify(_runtime / _state.Count); + + if (_runtime < _state.Count) LoadNextState(); break; case AnimationState.Stopped: gridController.LoadGridState(_grid.RenderNodeTypes(_start, _end)); break; case AnimationState.Paused: + if (_runtime < _state.Count) + LoadNextState(); break; default: throw new ArgumentOutOfRangeException(); @@ -189,24 +210,22 @@ public class UIController : MonoBehaviour { } private void GeneratePath() { - if (_algorithm != null) - _algorithm.Cleanup(); + _algorithm?.Cleanup(); // cleanup algorithm's edits to node grid _runtime = 0f; _algorithm = new AStar(_grid); _path = _algorithm.FindPath(_start, _end); - // Debug.Log($"{_state.Count} changs made"); _state = _algorithm.ChangeController; } private void LoadNextState() { // Move to the new calculated index - _state.MoveTo(Math.Max(1, CurrentIndex)); // use Math.max to ensure both start/end nodes are always rendered + _state.MoveTo(Mathf.Clamp(CurrentIndex, 1, _state.Count - 1)); // 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"; manager.debugText.text = $"{_state.CurrentRuntime * 1000.0:F1}ms\n" + - $"{CurrentIndex:000} / {_state.Count:000}\n" + + $"{CurrentIndex + 1:000} / {_state.Count:000}\n" + $"Path: {pathCount} tiles"; } @@ -254,9 +273,18 @@ public class UIController : MonoBehaviour { Gizmos.DrawWireCube(gridController.GetWorldPosition(gridPosition), localScale / (Vector2) gridController.Size); Handles.Label(mouse, String.Format("{0}{1}", gridPosition, - _algorithm.NodeGrid.IsValid(gridPosition) + _algorithm != null && _algorithm.NodeGrid.IsValid(gridPosition) ? $"\n{_state.Current[gridPosition.x, gridPosition.y]}" : "" ), style); } + + /// + /// Update the animation progress to the slider's (new) position. + /// + /// The new position on the slider. + private void MoveToSlider(float @new) { + if (_state != null) + _runtime = @new * _state.Count; + } } \ No newline at end of file From 528bf8e90e0fe60c291721bbbddacb6b0e8afb3a Mon Sep 17 00:00:00 2001 From: Xevion Date: Wed, 25 Nov 2020 13:23:16 -0600 Subject: [PATCH 7/9] overall fixes to classes, final removal of Manager, docs, CustomSlider new keyword, IPathfinding interface Cleanup() func, GridController positioning amendments --- Paths/Assets/Scripts/Algorithms/AStar.cs | 14 +- Paths/Assets/Scripts/ChangeController.cs | 4 +- Paths/Assets/Scripts/CustomSlider.cs | 2 +- Paths/Assets/Scripts/GridController.cs | 8 +- Paths/Assets/Scripts/IPathfinding.cs | 1 + Paths/Assets/Scripts/Manager.cs | 180 ----------------------- Paths/Assets/Scripts/Manager.cs.meta | 11 -- Paths/Assets/Scripts/UIController.cs | 32 +++- 8 files changed, 40 insertions(+), 212 deletions(-) delete mode 100644 Paths/Assets/Scripts/Manager.cs delete mode 100644 Paths/Assets/Scripts/Manager.cs.meta diff --git a/Paths/Assets/Scripts/Algorithms/AStar.cs b/Paths/Assets/Scripts/Algorithms/AStar.cs index aafc771..58aeeb3 100644 --- a/Paths/Assets/Scripts/Algorithms/AStar.cs +++ b/Paths/Assets/Scripts/Algorithms/AStar.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; using UnityEngine; namespace Algorithms { @@ -15,7 +14,7 @@ namespace Algorithms { public Vector2Int End { get; private set; } public AStar(NodeGrid nodeGrid) { - this.NodeGrid = nodeGrid; + NodeGrid = nodeGrid; ChangeController = new ChangeController(nodeGrid.RenderNodeTypes()); } @@ -78,7 +77,7 @@ namespace Algorithms { return null; } - // Fix start position being overriden + // Fix start and end position being overriden ChangeController.RemovePositions(start, 1); // if all good, return path @@ -86,7 +85,8 @@ namespace Algorithms { if (temp == null) return null; do { _path.Push(temp); - ChangeController.AddChange(new Change(temp.Position.x, temp.Position.y, GridNodeType.Path, GridNodeType.Expanded)); + ChangeController.AddChange(new Change(temp.Position.x, temp.Position.y, GridNodeType.Path, + GridNodeType.Expanded)); temp = temp.Parent; } while (temp != null && !temp.Equals(startNode)); @@ -100,14 +100,14 @@ namespace Algorithms { while (_openList.Count > 0) { Node node = _openList[0]; _openList.RemoveAt(0); - + node.Reset(); } - + while (_closedList.Count > 0) { Node node = _closedList[0]; _closedList.RemoveAt(0); - + node.Reset(); } } diff --git a/Paths/Assets/Scripts/ChangeController.cs b/Paths/Assets/Scripts/ChangeController.cs index db6c5e8..f59dd62 100644 --- a/Paths/Assets/Scripts/ChangeController.cs +++ b/Paths/Assets/Scripts/ChangeController.cs @@ -64,7 +64,7 @@ public class ChangeController { /// - /// Move the ChangeController's current index forward by index. + /// Move the ChangeController's current index forward by a certain number of times. /// Positive values only, wil only result in forward movement (if any). /// /// The number of times to move forward. @@ -80,7 +80,7 @@ public class ChangeController { } /// - /// Move the ChangeController's current index backward by index. + /// Move the ChangeController's current index backward by a certain number of times. /// Positive values only, will only result in backward movement (if any). /// /// The number of times to move backward. diff --git a/Paths/Assets/Scripts/CustomSlider.cs b/Paths/Assets/Scripts/CustomSlider.cs index cda0ebe..5567601 100644 --- a/Paths/Assets/Scripts/CustomSlider.cs +++ b/Paths/Assets/Scripts/CustomSlider.cs @@ -2,7 +2,7 @@ using UnityEngine.UI; public class CustomSlider: Slider { - public bool IsPressed { get; private set; } + public new bool IsPressed { get; private set; } public override void OnPointerDown(PointerEventData eventData) { diff --git a/Paths/Assets/Scripts/GridController.cs b/Paths/Assets/Scripts/GridController.cs index 9ce74a1..f4ef545 100644 --- a/Paths/Assets/Scripts/GridController.cs +++ b/Paths/Assets/Scripts/GridController.cs @@ -141,9 +141,9 @@ public class GridController : MonoBehaviour { public Vector2Int GetGridPosition(Vector3 worldPosition) { Vector3 localScale = transform.localScale; Vector2 gridPosition = (worldPosition + (localScale / 2f)) / new Vector2(localScale.x, localScale.y); - return new Vector2Int( + return Size - new Vector2Int( (int) (gridPosition.x * width), - (int) (gridPosition.y * height)) - Size - Vector2Int.one; + (int) (gridPosition.y * height)) - Vector2Int.one; } /// @@ -154,9 +154,9 @@ public class GridController : MonoBehaviour { public Vector3 GetWorldPosition(Vector2Int gridPosition) { Transform ttransform = transform; Vector3 localScale = ttransform.localScale; - Vector2 bottomLeft = ttransform.position - (localScale / 2f); + Vector2 topRight = ttransform.position + (localScale / 2f); var singleSquare = new Vector2(localScale.x / width, localScale.y / height); - Vector2 worldPosition = bottomLeft + (singleSquare * gridPosition) + (singleSquare / 2f); + Vector2 worldPosition = topRight - (singleSquare * (gridPosition + Vector2Int.one)) + (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 b1d0c2a..84e93c7 100644 --- a/Paths/Assets/Scripts/IPathfinding.cs +++ b/Paths/Assets/Scripts/IPathfinding.cs @@ -17,4 +17,5 @@ public interface IPathfinding { Vector2Int Start { get; } Vector2Int End { get; } ChangeController ChangeController { get; } + void Cleanup(); } \ No newline at end of file diff --git a/Paths/Assets/Scripts/Manager.cs b/Paths/Assets/Scripts/Manager.cs deleted file mode 100644 index 385a102..0000000 --- a/Paths/Assets/Scripts/Manager.cs +++ /dev/null @@ -1,180 +0,0 @@ -using System; -using System.Collections.Generic; -using Algorithms; -using LevelGeneration; -using TMPro; -using UnityEditor; -using UnityEngine; -using UnityEngine.UI; - -/// -/// The primary controller of the entire application, managing state, events and sending commands -/// -public class Manager : MonoBehaviour { - private IPathfinding _algorithm; - private ChangeController _state; - private int _curIndex; - private Stack _path; - private float _runtime; - - public float speed; - public float clampIncrement; - public bool moving = true; - - public Camera mainCamera; - public GameObject gridObject; - public GridController gridController; - public TextMeshPro debugText; - public Slider progressSlider; - private float? _moveTo; - - private int CurrentIndex { - get => (int) _runtime; - set => _runtime = value; - } - - public void Start() { - GeneratePath(); - Resize(); - - progressSlider.onValueChanged.AddListener((value) => MoveToSlider(value)); - } - - /// - /// Update the animation progress to the slider's (new) position. - /// - /// The new position on the slider. - private void MoveToSlider(float @new) { - _runtime = @new * _state.Count; - } - - - - public void OnDrawGizmos() { - 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; - - 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); - } - - /// - /// Returns the current time multiplier, based on the latest change in the path. - /// - /// A positive non-zero float representing how fast the current frame should be processed. - private float CurrentMultiplier() { - if (_state.Index == -1) - return 1; - - switch (_state.CurrentChange.New) { - case GridNodeType.Path: - return 1 / 5f; - case GridNodeType.Empty: - break; - case GridNodeType.Wall: - break; - case GridNodeType.Start: - break; - case GridNodeType.End: - break; - case GridNodeType.Seen: - break; - case GridNodeType.Expanded: - break; - default: - throw new ArgumentOutOfRangeException(); - } - - return 1; - } - - public void Update() { - // Toggle pause with 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(); - if (clampIncrement > 0) - increment = Mathf.Clamp(increment, 0, _state.Count * Time.deltaTime / clampIncrement); - _runtime += increment; - } - - // Load next state in grid or update text - if (CurrentIndex < _state.Count) - LoadNextState(); - - // Update progress slider silently - progressSlider.SetValueWithoutNotify(_runtime / _state.Count); - } - - /// - /// Generates a new grid and runs pathfinding. - /// - private void GeneratePath() { - CurrentIndex = 0; - var nodeGrid = new NodeGrid(gridController.width, gridController.height); - - // Vector2Int start = nodeGrid.RandomPosition(); - Vector2Int start = new Vector2Int(3, 6); - Vector2Int end = nodeGrid.RandomPosition(); - - nodeGrid.ApplyGenerator(new RandomPlacement(0.3f, true, true)); - - nodeGrid.GetNode(start).Walkable = true; - nodeGrid.GetNode(end).Walkable = true; - - _algorithm = new AStar(nodeGrid); - _path = _algorithm.FindPath(start, end); - _state = _algorithm.ChangeController; - } - - /// - /// Loads the appropriate grid state into the shader via the ChangeController instance. - /// - private void LoadNextState() { - _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"; - debugText.text = $"{_state.CurrentRuntime * 1000.0:F1}ms\n" + - $"{this.CurrentIndex:000} / {_state.Count:000}\n" + - $"Path: {pathCount} tiles"; - } - - /// - /// Scales the GridController GameObject to fit within the Camera - /// - private void Resize() { - float ratioImage = (float) gridController.width / gridController.height; - float ratioScreen = mainCamera.aspect; - - var orthographicSize = mainCamera.orthographicSize; - var image = new Vector2(gridController.width, gridController.height); - var screen = new Vector2(2 * orthographicSize * mainCamera.aspect, orthographicSize * 2); - - gridObject.transform.localScale = ratioScreen > ratioImage - ? new Vector3(image.x * screen.y / image.y, screen.y, 0.001f) - : new Vector3(screen.x, image.y * screen.x / image.x, 0.001f); - } -} \ No newline at end of file diff --git a/Paths/Assets/Scripts/Manager.cs.meta b/Paths/Assets/Scripts/Manager.cs.meta deleted file mode 100644 index ccde7f7..0000000 --- a/Paths/Assets/Scripts/Manager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ca142250b9964eb1adf66ac7c5cc3e3e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 300 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Paths/Assets/Scripts/UIController.cs b/Paths/Assets/Scripts/UIController.cs index bc47bb9..14c5730 100644 --- a/Paths/Assets/Scripts/UIController.cs +++ b/Paths/Assets/Scripts/UIController.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using Algorithms; +using TMPro; using UnityEditor; using UnityEngine; -using UnityEngine.UI; /// @@ -39,7 +39,9 @@ public class UIController : MonoBehaviour { // UI & important App references public CustomSlider progressSlider; public GridController gridController; - public Manager manager; + public Camera mainCamera; + public TextMeshPro debugText; + public GameObject gridObject; // Animation State, Click Management private Vector2Int _lastClickLocation; @@ -72,13 +74,13 @@ public class UIController : MonoBehaviour { _end = _grid.RandomPosition(); _runtime = 0; - manager.Resize(); + Resize(); progressSlider.onValueChanged.AddListener((value) => MoveToSlider(value)); } private void Update() { if (Input.GetMouseButton(0)) { - Vector3 worldMouse = manager.mainCamera.ScreenToWorldPoint(Input.mousePosition); + Vector3 worldMouse = mainCamera.ScreenToWorldPoint(Input.mousePosition); Vector2Int position = gridController.GetGridPosition(worldMouse); // Initial click, remember what they clicked @@ -224,7 +226,7 @@ public class UIController : MonoBehaviour { gridController.LoadDirtyGridState(_state.Current, _state.DirtyFlags); string pathCount = _path != null ? $"{_path.Count}" : "N/A"; - manager.debugText.text = $"{_state.CurrentRuntime * 1000.0:F1}ms\n" + + debugText.text = $"{_state.CurrentRuntime * 1000.0:F1}ms\n" + $"{CurrentIndex + 1:000} / {_state.Count:000}\n" + $"Path: {pathCount} tiles"; } @@ -262,8 +264,8 @@ public class UIController : MonoBehaviour { public void OnDrawGizmos() { if (!Application.isPlaying) return; - Vector3 mouse = manager.mainCamera.ScreenToWorldPoint(Input.mousePosition); - Vector3 localScale = manager.gridObject.transform.localScale; + Vector3 mouse = mainCamera.ScreenToWorldPoint(Input.mousePosition); + Vector3 localScale = gridObject.transform.localScale; Vector2Int gridPosition = gridController.GetGridPosition(mouse); var style = new GUIStyle(); @@ -287,4 +289,20 @@ public class UIController : MonoBehaviour { if (_state != null) _runtime = @new * _state.Count; } + + /// + /// Scales the GridController GameObject to fit within the Camera + /// + public void Resize() { + float ratioImage = (float) gridController.width / gridController.height; + float ratioScreen = mainCamera.aspect; + + var orthographicSize = mainCamera.orthographicSize; + var image = new Vector2(gridController.width, gridController.height); + var screen = new Vector2(2 * orthographicSize * mainCamera.aspect, orthographicSize * 2); + + gridObject.transform.localScale = ratioScreen > ratioImage + ? new Vector3(image.x * screen.y / image.y, screen.y, 0.001f) + : new Vector3(screen.x, image.y * screen.x / image.x, 0.001f); + } } \ No newline at end of file From d841b8760bfce7a6932378642798202039260732 Mon Sep 17 00:00:00 2001 From: Xevion Date: Wed, 25 Nov 2020 21:18:14 -0600 Subject: [PATCH 8/9] general documentation improvements --- Paths/Assets/Scenes/Default.unity | 925 +++++++++++++++++++- Paths/Assets/Scripts/Algorithms/AStar.cs | 11 +- Paths/Assets/Scripts/Algorithms/NodeGrid.cs | 33 +- Paths/Assets/Scripts/Change.cs | 6 +- Paths/Assets/Scripts/ChangeController.cs | 16 +- Paths/Assets/Scripts/CustomSlider.cs | 6 + Paths/Assets/Scripts/GridController.cs | 1 + Paths/Assets/Scripts/UIController.cs | 5 +- 8 files changed, 962 insertions(+), 41 deletions(-) diff --git a/Paths/Assets/Scenes/Default.unity b/Paths/Assets/Scenes/Default.unity index 90f6a17..5f9ad67 100644 --- a/Paths/Assets/Scenes/Default.unity +++ b/Paths/Assets/Scenes/Default.unity @@ -123,6 +123,410 @@ NavMeshSettings: debug: m_Flags: 0 m_NavMeshData: {fileID: 0} +--- !u!1 &17751484 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 17751485} + - component: {fileID: 17751487} + - component: {fileID: 17751486} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &17751485 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 17751484} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 229754413} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &17751486 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 17751484} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Button + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4281479730 + m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 24 + m_fontSizeBase: 24 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 1 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &17751487 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 17751484} + m_CullTransparentMesh: 0 +--- !u!1 &229754412 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 229754413} + - component: {fileID: 229754416} + - component: {fileID: 229754415} + - component: {fileID: 229754414} + m_Layer: 5 + m_Name: Button + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &229754413 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 229754412} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 17751485} + m_Father: {fileID: 1155758495} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 70.714, y: -12.815} + m_SizeDelta: {x: 141.42737, y: 25.629944} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &229754414 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 229754412} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 229754415} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &229754415 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 229754412} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &229754416 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 229754412} + m_CullTransparentMesh: 0 +--- !u!1 &344474894 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 344474895} + - component: {fileID: 344474897} + - component: {fileID: 344474896} + m_Layer: 5 + m_Name: Handle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &344474895 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 344474894} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.65, y: 0.65, z: 1} + m_Children: [] + m_Father: {fileID: 831361552} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 35, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &344474896 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 344474894} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10913, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &344474897 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 344474894} + m_CullTransparentMesh: 0 +--- !u!1 &422608066 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 422608067} + - component: {fileID: 422608069} + - component: {fileID: 422608068} + m_Layer: 5 + m_Name: Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &422608067 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 422608066} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1127471362} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.25} + m_AnchorMax: {x: 1, y: 0.75} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &422608068 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 422608066} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.26415092, g: 0.26415092, b: 0.26415092, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &422608069 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 422608066} + m_CullTransparentMesh: 0 --- !u!1 &519420028 GameObject: m_ObjectHideFlags: 0 @@ -206,6 +610,81 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &542076403 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 542076404} + - component: {fileID: 542076406} + - component: {fileID: 542076405} + m_Layer: 5 + m_Name: Fill + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &542076404 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 542076403} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2071673332} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 10, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &542076405 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 542076403} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.16981131, g: 0.16981131, b: 0.16981131, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &542076406 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 542076403} + m_CullTransparentMesh: 0 --- !u!850595691 &628914115 LightingSettings: m_ObjectHideFlags: 0 @@ -267,7 +746,7 @@ LightingSettings: m_PVRFilteringAtrousPositionSigmaDirect: 0.5 m_PVRFilteringAtrousPositionSigmaIndirect: 2 m_PVRFilteringAtrousPositionSigmaAO: 1 ---- !u!1 &1373243071 +--- !u!1 &831361551 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -275,47 +754,340 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1373243072} - - component: {fileID: 1373243073} - m_Layer: 0 - m_Name: Game Manager + - component: {fileID: 831361552} + m_Layer: 5 + m_Name: Handle Slide Area m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!4 &1373243072 -Transform: +--- !u!224 &831361552 +RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1373243071} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_GameObject: {fileID: 831361551} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 3 + m_Children: + - {fileID: 344474895} + m_Father: {fileID: 1127471362} + m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &1373243073 + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -20, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &938674168 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 938674171} + - component: {fileID: 938674170} + - component: {fileID: 938674169} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &938674169 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1373243071} + m_GameObject: {fileID: 938674168} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ca142250b9964eb1adf66ac7c5cc3e3e, type: 3} + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} m_Name: m_EditorClassIdentifier: - mainCamera: {fileID: 519420031} - gridObject: {fileID: 2092623184} + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &938674170 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 938674168} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &938674171 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 938674168} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1127471361 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1127471362} + - component: {fileID: 1127471363} + m_Layer: 5 + m_Name: ProgressSlider + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1127471362 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1127471361} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 422608067} + - {fileID: 2071673332} + - {fileID: 831361552} + m_Father: {fileID: 1155758495} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: -0} + m_AnchoredPosition: {x: 0.2999878, y: 11} + m_SizeDelta: {x: -22.869019, y: 35} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1127471363 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1127471361} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1502f97daf7446a48b977b5b7fa485ad, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 0.5660378, g: 0.5660378, b: 0.5660378, a: 1} + m_HighlightedColor: {r: 0.7735849, g: 0.7735849, b: 0.7735849, a: 1} + m_PressedColor: {r: 0.3301887, g: 0.3301887, b: 0.3301887, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 344474896} + m_FillRect: {fileID: 542076404} + m_HandleRect: {fileID: 344474895} + m_Direction: 0 + m_MinValue: 0 + m_MaxValue: 1 + m_WholeNumbers: 0 + m_Value: 0 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &1155758491 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1155758495} + - component: {fileID: 1155758494} + - component: {fileID: 1155758493} + - component: {fileID: 1155758492} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1155758492 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1155758491} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &1155758493 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1155758491} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!223 &1155758494 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1155758491} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 25 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &1155758495 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1155758491} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 1127471362} + - {fileID: 1998222258} + - {fileID: 229754413} + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1 &1378668893 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1378668895} + - component: {fileID: 1378668894} + m_Layer: 0 + m_Name: UIController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1378668894 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1378668893} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fd9c76568dd84a92b068dd1e622bd101, type: 3} + m_Name: + m_EditorClassIdentifier: + progressSlider: {fileID: 1127471363} gridController: {fileID: 2092623185} + mainCamera: {fileID: 519420031} debugText: {fileID: 1436240699} + gridObject: {fileID: 2092623184} + clampIncrement: 1.25 speed: 2500 - clampIncrement: 2 +--- !u!4 &1378668895 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1378668893} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1.0482129, y: 0.49563652, z: -32.86509} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1436240698 GameObject: m_ObjectHideFlags: 0 @@ -478,7 +1250,7 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 4 + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} @@ -577,6 +1349,117 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1998222257 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1998222258} + - component: {fileID: 1998222260} + - component: {fileID: 1998222259} + m_Layer: 5 + m_Name: Panel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1998222258 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1998222257} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1155758495} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: -297.2, y: 123.3} + m_SizeDelta: {x: -683.3771, y: -359.0529} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1998222259 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1998222257} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1998222260 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1998222257} + m_CullTransparentMesh: 0 +--- !u!1 &2071673331 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2071673332} + m_Layer: 5 + m_Name: Fill Area + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2071673332 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2071673331} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 542076404} + m_Father: {fileID: 1127471362} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.25} + m_AnchorMax: {x: 1, y: 0.75} + m_AnchoredPosition: {x: -5, y: 0} + m_SizeDelta: {x: -20, y: 0} + m_Pivot: {x: 0.5, y: 0.5} --- !u!1 &2092623184 GameObject: m_ObjectHideFlags: 0 @@ -609,8 +1492,8 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: gridMaterial: {fileID: 2100000, guid: 780d53bea4df7b0418e9c8ed8afd6410, type: 2} - width: 10 - height: 10 + width: 60 + height: 34 --- !u!23 &2092623186 MeshRenderer: m_ObjectHideFlags: 0 diff --git a/Paths/Assets/Scripts/Algorithms/AStar.cs b/Paths/Assets/Scripts/Algorithms/AStar.cs index 58aeeb3..d8b82c1 100644 --- a/Paths/Assets/Scripts/Algorithms/AStar.cs +++ b/Paths/Assets/Scripts/Algorithms/AStar.cs @@ -3,12 +3,12 @@ using UnityEngine; namespace Algorithms { public class AStar : IPathfinding { - public NodeGrid NodeGrid { get; private set; } + public NodeGrid NodeGrid { get; } private Stack _path; private List _openList; private List _closedList; - public ChangeController ChangeController { get; private set; } + public ChangeController ChangeController { get; } public Vector2Int Start { get; private set; } public Vector2Int End { get; private set; } @@ -39,18 +39,22 @@ namespace Algorithms { _openList.Add(startNode); while (_openList.Count != 0) { + // take the first node out (lowest F score) current = _openList[0]; _openList.RemoveAt(0); + // add it to closed list & mark current.State = NodeState.Closed; ChangeController.AddChange(new Change( current.Position.x, current.Position.y, GridNodeType.Expanded, GridNodeType.Seen)); _closedList.Add(current); + // exit if this is the end node if (current.Position == endNode.Position) break; + // look at all adjacent nodes and add them to the open list if possible Node[] adjacentNodes = this.NodeGrid.GetAdjacentNodesArray(current); for (int i = 0; i < adjacentNodes.Length; i++) { Node node = adjacentNodes[i]; @@ -60,6 +64,7 @@ namespace Algorithms { node.DistanceToTarget = NodeGrid.Manhattan(node, endNode); node.Cost = node.Weight + node.Parent.Cost; + // mark as open node.State = NodeState.Open; ChangeController.AddChange(new Change(node.Position.x, node.Position.y, GridNodeType.Seen, GridNodeType.Empty)); @@ -95,6 +100,8 @@ namespace Algorithms { /// /// Attempts to clean the NodeGrid of all edits made to heuristic values and such, fast. + /// This is done by clearing the open and closed list, and for each node, resetting them (clearing heuristic + /// values and setting state back to it's default). /// public void Cleanup() { while (_openList.Count > 0) { diff --git a/Paths/Assets/Scripts/Algorithms/NodeGrid.cs b/Paths/Assets/Scripts/Algorithms/NodeGrid.cs index 12a0287..76f0c0c 100644 --- a/Paths/Assets/Scripts/Algorithms/NodeGrid.cs +++ b/Paths/Assets/Scripts/Algorithms/NodeGrid.cs @@ -37,8 +37,15 @@ namespace Algorithms { Width = this.Grid.GetLength(1); } + /// + /// Returns adjacent Node objects in each of the cardinal directions. + /// Only valid nodes will be included. Invalid positions will return 0 nodes. + /// + /// The node from which adjacents will be found. + /// A length 4 or less list containing nodes. + /// public List GetAdjacentNodesList(Node node) { - List temp = new List(); + List temp = new List(4); int col = node.Position.x; int row = node.Position.y; @@ -51,19 +58,29 @@ namespace Algorithms { return temp; } - public bool IsValid(Node node) { - return IsValid(node.Position); - } - + /// + /// Returns True if a Vector2Int position is within the grid's boundaries. + /// + /// A Vector2Int coordinate position. + /// True if valid and real (a node with the same position exists). public bool IsValid(Vector2Int position) { return position.x >= 0 && position.y >= 0 && position.x < Width && position.y < Height; } + /// + /// Returns a 1D Array describing the valid nearby nodes. + /// Invalid nodes will be represented by null. + /// Currently only returns nodes in cardinal directions (no diagonals). + /// Only valid positions within the grid are returned. + /// + /// A valid position on the grid. + /// A 4 length array containing valid nodes in each of the cardinal directions. + /// public Node[] GetAdjacentNodesArray(Node node) { int col = node.Position.x; int row = node.Position.y; - return new [] { + return new[] { row + 1 < Height ? Grid[col, row + 1] : null, row - 1 >= 0 ? Grid[col, row - 1] : null, col - 1 >= 0 ? Grid[col - 1, row] : null, @@ -159,10 +176,10 @@ namespace Algorithms { // Start / End node addition if (start.HasValue) nodeTypeGrid[start.Value.x, start.Value.y] = GridNodeType.Start; - + if (end.HasValue) nodeTypeGrid[end.Value.x, end.Value.y] = GridNodeType.End; - + return nodeTypeGrid; } } diff --git a/Paths/Assets/Scripts/Change.cs b/Paths/Assets/Scripts/Change.cs index 1cf7546..d8d5ba7 100644 --- a/Paths/Assets/Scripts/Change.cs +++ b/Paths/Assets/Scripts/Change.cs @@ -1,4 +1,8 @@ -public readonly struct Change { +/// +/// A Change struct represents a Change in the grid's rendering. +/// This struct remembers the original and new GridNodeType, the time it was recorded and of course the relevant position. +/// +public readonly struct Change { public readonly int X; public readonly int Y; public readonly GridNodeType New; diff --git a/Paths/Assets/Scripts/ChangeController.cs b/Paths/Assets/Scripts/ChangeController.cs index f59dd62..2824524 100644 --- a/Paths/Assets/Scripts/ChangeController.cs +++ b/Paths/Assets/Scripts/ChangeController.cs @@ -9,16 +9,16 @@ public class ChangeController { private readonly GridNodeType[,] _initial; public GridNodeType[,] Current { get; private set; } public bool[,] DirtyFlags { get; private set; } - public int Index { get; private set; } + public int CurrentChangeIndex { get; private set; } private readonly List _changes; public int Count => _changes.Count; - public Change CurrentChange => _changes[Index]; - public double CurrentRuntime => _changes[Index].Time - _changes[0].Time; + public Change CurrentChange => _changes[CurrentChangeIndex]; + public double CurrentRuntime => _changes[CurrentChangeIndex].Time - _changes[0].Time; public ChangeController(GridNodeType[,] initial) { _initial = initial; Current = initial; - Index = -1; + CurrentChangeIndex = -1; _changes = new List(); DirtyFlags = new bool[initial.GetLength(0), initial.GetLength(1)]; SetDirty(); @@ -73,7 +73,7 @@ public class ChangeController { throw new ArgumentOutOfRangeException(nameof(n)); for (int i = 0; i < n; i++) { - Change cur = _changes[++Index]; + Change cur = _changes[++CurrentChangeIndex]; Current[cur.X, cur.Y] = cur.New; SetDirty(new Vector2Int(cur.X, cur.Y)); } @@ -88,11 +88,11 @@ public class ChangeController { if (n < 0) throw new ArgumentOutOfRangeException(nameof(n)); - if (n > 5 && Index - n == 0) + if (n > 5 && CurrentChangeIndex - n == 0) Reset(); // resetting by copying values instead of mutating might be easier. else { for (int i = 0; i < n; i++) { - Change cur = _changes[Index--]; // post decrement as we apply the current Change's old, not the previous + Change cur = _changes[CurrentChangeIndex--]; // post decrement as we apply the current Change's old, not the previous Current[cur.X, cur.Y] = cur.Old; SetDirty(new Vector2Int(cur.X, cur.Y)); } @@ -124,7 +124,7 @@ public class ChangeController { $"Cannot move to change index {index}. Only indexes from 0 to {_changes.Count - 1} are valid."); // diff & move to - int diff = index - Index; + int diff = index - CurrentChangeIndex; if (diff != 0) // prefer resetting if index is 0 and it needs to move at least some. if (index == 0 && diff > 5) diff --git a/Paths/Assets/Scripts/CustomSlider.cs b/Paths/Assets/Scripts/CustomSlider.cs index 5567601..5ecac5f 100644 --- a/Paths/Assets/Scripts/CustomSlider.cs +++ b/Paths/Assets/Scripts/CustomSlider.cs @@ -1,7 +1,13 @@ using UnityEngine.EventSystems; using UnityEngine.UI; +/// +/// A simple custom slider implementation that adds a single boolean field; IsPressed. +/// public class CustomSlider: Slider { + /// + /// Whether or not the Slider is currently being pressed on by the Left Click mouse button. + /// public new bool IsPressed { get; private set; } public override void OnPointerDown(PointerEventData eventData) diff --git a/Paths/Assets/Scripts/GridController.cs b/Paths/Assets/Scripts/GridController.cs index f4ef545..d9a0035 100644 --- a/Paths/Assets/Scripts/GridController.cs +++ b/Paths/Assets/Scripts/GridController.cs @@ -29,6 +29,7 @@ public class GridController : MonoBehaviour { private void Start() { _values = new int[width * height]; + // TODO: Decide at some point how to improve how the ComputerBuffer's size is allocated. _buffer = new ComputeBuffer((int) Mathf.Pow(2048, 2), 4); // Update all Shader properties diff --git a/Paths/Assets/Scripts/UIController.cs b/Paths/Assets/Scripts/UIController.cs index 14c5730..590affb 100644 --- a/Paths/Assets/Scripts/UIController.cs +++ b/Paths/Assets/Scripts/UIController.cs @@ -156,6 +156,7 @@ public class UIController : MonoBehaviour { _animationState = AnimationState.Started; break; case AnimationState.Started: + // Restart if already on final frame, else simply pause if (CurrentIndex >= _state.Count) _runtime = 0; else @@ -170,6 +171,7 @@ public class UIController : MonoBehaviour { switch (_animationState) { case AnimationState.Reloading: + // Reloading seizes while the mouse button is depressed if (!Input.GetMouseButton(0)) { GeneratePath(); LoadNextState(); @@ -195,6 +197,7 @@ public class UIController : MonoBehaviour { LoadNextState(); break; case AnimationState.Stopped: + // Render editable grid when fully stopped gridController.LoadGridState(_grid.RenderNodeTypes(_start, _end)); break; case AnimationState.Paused: @@ -236,7 +239,7 @@ public class UIController : MonoBehaviour { /// /// A positive non-zero float representing how fast the current frame should be processed. private float CurrentMultiplier() { - if (_state.Index == -1) + if (_state.CurrentChangeIndex == -1) return 1; switch (_state.CurrentChange.New) { From 734148ca192cc97150488e06daba4bab5acff32c Mon Sep 17 00:00:00 2001 From: Xevion Date: Thu, 26 Nov 2020 09:19:28 -0600 Subject: [PATCH 9/9] fix unpausing during edits while paused, fixed end node changes not being rendered properly --- Paths/Assets/Scripts/Algorithms/AStar.cs | 9 +++++++-- Paths/Assets/Scripts/UIController.cs | 8 +++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Paths/Assets/Scripts/Algorithms/AStar.cs b/Paths/Assets/Scripts/Algorithms/AStar.cs index d8b82c1..7f56aa7 100644 --- a/Paths/Assets/Scripts/Algorithms/AStar.cs +++ b/Paths/Assets/Scripts/Algorithms/AStar.cs @@ -82,8 +82,7 @@ namespace Algorithms { return null; } - // Fix start and end position being overriden - ChangeController.RemovePositions(start, 1); + // if all good, return path Node temp = _closedList[_closedList.IndexOf(current)]; @@ -95,6 +94,12 @@ namespace Algorithms { temp = temp.Parent; } while (temp != null && !temp.Equals(startNode)); + // Fix start and end position being overriden + // TODO: Look into using a proper fix for this instead of a 'patch'. + ChangeController.RemovePositions(start, 1); + ChangeController.RemovePositions(end, 3); + + return _path; } diff --git a/Paths/Assets/Scripts/UIController.cs b/Paths/Assets/Scripts/UIController.cs index 590affb..837aec1 100644 --- a/Paths/Assets/Scripts/UIController.cs +++ b/Paths/Assets/Scripts/UIController.cs @@ -50,7 +50,7 @@ public class UIController : MonoBehaviour { private AnimationState _previousAnimationState; private bool EditShouldReload => - _animationState == AnimationState.Started || _animationState == AnimationState.Paused; + _animationState == AnimationState.Started; // Grid State & Pathfinding private NodeGrid _grid; @@ -95,7 +95,9 @@ public class UIController : MonoBehaviour { Node node = _grid.GetNode(position); _modify = node.Walkable ? ClickType.Add : ClickType.Remove; node.Walkable = !node.Walkable; - if (EditShouldReload) + if (_animationState == AnimationState.Paused) + _animationState = AnimationState.Stopped; + else if (_animationState == AnimationState.Started) _animationState = AnimationState.Reloading; } @@ -230,7 +232,7 @@ public class UIController : MonoBehaviour { string pathCount = _path != null ? $"{_path.Count}" : "N/A"; debugText.text = $"{_state.CurrentRuntime * 1000.0:F1}ms\n" + - $"{CurrentIndex + 1:000} / {_state.Count:000}\n" + + $"{CurrentIndex:000} / {_state.Count:000}\n" + $"Path: {pathCount} tiles"; }