mirror of
https://github.com/Xevion/Paths.git
synced 2025-12-06 13:15:50 -06:00
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:
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Algorithms {
|
||||
@@ -92,5 +93,23 @@ namespace Algorithms {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,16 @@ namespace Algorithms {
|
||||
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) {
|
||||
return obj is Node node && Position.Equals(node.Position);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
/// </summary>
|
||||
public enum AnimationState {
|
||||
Stopped,
|
||||
Paused,
|
||||
Started,
|
||||
Reloading
|
||||
}
|
||||
@@ -31,23 +34,41 @@ public enum AnimationState {
|
||||
/// All UI elements are referenced and controlled here.
|
||||
/// </summary>
|
||||
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<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() {
|
||||
_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";
|
||||
}
|
||||
|
||||
/// <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>
|
||||
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();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user