animation state handling (stopping/start/pausing/reloading) while editing, add cleanup code to algorithm, path generation and iteration, move gizmos from manager

This commit is contained in:
Xevion
2020-11-25 11:39:20 -06:00
parent 0fa97de715
commit 6ee263cfac
4 changed files with 187 additions and 19 deletions
+19
View File
@@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using UnityEngine; using UnityEngine;
namespace Algorithms { namespace Algorithms {
@@ -92,5 +93,23 @@ namespace Algorithms {
return _path; return _path;
} }
/// <summary>
/// Attempts to clean the NodeGrid of all edits made to heuristic values and such, fast.
/// </summary>
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();
}
}
} }
} }
+10
View File
@@ -37,6 +37,16 @@ namespace Algorithms {
Walkable = walkable; Walkable = walkable;
} }
/// <summary>
/// Resets this Node back to it's assumed default values.
/// </summary>
public void Reset() {
Parent = null;
DistanceToTarget = null;
Cost = 1;
State = NodeState.None;
}
public override bool Equals(object obj) { public override bool Equals(object obj) {
return obj is Node node && Position.Equals(node.Position); return obj is Node node && Position.Equals(node.Position);
} }
+8 -1
View File
@@ -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)]; GridNodeType[,] nodeTypeGrid = new GridNodeType[Grid.GetLength(0), Grid.GetLength(1)];
for (int x = 0; x < Grid.GetLength(0); x++) { 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; return nodeTypeGrid;
} }
} }
+148 -16
View File
@@ -1,5 +1,7 @@
using System; using System;
using System.Collections.Generic;
using Algorithms; using Algorithms;
using UnityEditor;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
@@ -22,6 +24,7 @@ public enum ClickType {
/// </summary> /// </summary>
public enum AnimationState { public enum AnimationState {
Stopped, Stopped,
Paused,
Started, Started,
Reloading Reloading
} }
@@ -31,23 +34,41 @@ public enum AnimationState {
/// All UI elements are referenced and controlled here. /// All UI elements are referenced and controlled here.
/// </summary> /// </summary>
public class UIController : MonoBehaviour { public class UIController : MonoBehaviour {
// UI & important App references
public Slider progressSlider; public Slider progressSlider;
public GridController gridController; public GridController gridController;
public Manager manager; public Manager manager;
// Animation State, Click Management
private Vector2Int _lastClickLocation; private Vector2Int _lastClickLocation;
private ClickType _modify; 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 NodeGrid _grid;
private Vector2Int _start; private Vector2Int _start;
private Vector2Int _end; private Vector2Int _end;
private IPathfinding _algorithm;
private Stack<Node> _path;
private ChangeController _state;
// Animation speed & indexing
public float clampIncrement;
private float _runtime;
public int CurrentIndex => (int) _runtime;
public float speed;
private void Start() { private void Start() {
_grid = new NodeGrid(gridController.width, gridController.height); _grid = new NodeGrid(gridController.width, gridController.height);
_animating = AnimationState.Stopped; _animationState = AnimationState.Stopped;
_previousAnimationState = _animationState;
_start = _grid.RandomPosition(); _start = _grid.RandomPosition();
_end = _grid.RandomPosition(); _end = _grid.RandomPosition();
_runtime = 0;
} }
private void Update() { private void Update() {
@@ -65,6 +86,8 @@ public class UIController : MonoBehaviour {
Node node = _grid.GetNode(position); Node node = _grid.GetNode(position);
_modify = node.Walkable ? ClickType.Add : ClickType.Remove; _modify = node.Walkable ? ClickType.Add : ClickType.Remove;
node.Walkable = !node.Walkable; node.Walkable = !node.Walkable;
if (EditShouldReload)
_animationState = AnimationState.Reloading;
} }
_lastClickLocation = position; _lastClickLocation = position;
@@ -79,25 +102,27 @@ public class UIController : MonoBehaviour {
// Note: Wall toggling instantly reloads, but only real start/end node movement reloads. // Note: Wall toggling instantly reloads, but only real start/end node movement reloads.
case ClickType.Add: case ClickType.Add:
node.Walkable = false; node.Walkable = false;
_animating = AnimationState.Reloading; if (EditShouldReload)
_animationState = AnimationState.Reloading;
break; break;
case ClickType.Remove: case ClickType.Remove:
node.Walkable = true; node.Walkable = true;
_animating = AnimationState.Reloading; if (EditShouldReload)
_animationState = AnimationState.Reloading;
break; break;
case ClickType.Start: case ClickType.Start:
if (node.Walkable) { if (node.Walkable) {
_start = position; _start = position;
if (_animating == AnimationState.Started) if (EditShouldReload)
_animating = AnimationState.Reloading; _animationState = AnimationState.Reloading;
} }
break; break;
case ClickType.End: case ClickType.End:
if (node.Walkable) { if (node.Walkable) {
_end = position; _end = position;
if (_animating == AnimationState.Started) if (EditShouldReload)
_animating = AnimationState.Reloading; _animationState = AnimationState.Reloading;
} }
break; break;
@@ -108,23 +133,130 @@ public class UIController : MonoBehaviour {
} }
} }
if (_animating == AnimationState.Reloading) { // 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();
} }
else if (_animating == AnimationState.Started) {
} }
switch (_animationState) {
case AnimationState.Reloading:
if (!Input.GetMouseButton(0)) {
GeneratePath();
LoadNextState();
_animationState = AnimationState.Started;
}
else
gridController.LoadGridState(_grid.RenderNodeTypes(_start, _end)); 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";
} }
/// <summary> /// <summary>
/// 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.
/// </summary> /// </summary>
private void StartAnimation() { /// <returns>A positive non-zero float representing how fast the current frame should be processed.</returns>
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();
} }
/// <summary> return 1;
/// Stops the path animation and readies the UI Controller for grid editing. }
/// </summary>
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);
} }
} }