mirror of
https://github.com/Xevion/Paths.git
synced 2025-12-09 16:07:57 -06:00
implement ChangeController optimizations (switch off from GridState)
This commit is contained in:
@@ -10,6 +10,7 @@ namespace Algorithms {
|
||||
private List<Node> _openList;
|
||||
private List<Node> _closedList;
|
||||
private List<GridState> _states;
|
||||
public ChangeController ChangeController { get; private set; }
|
||||
|
||||
public Vector2Int Start { get; private set; }
|
||||
public Vector2Int End { get; private set; }
|
||||
@@ -17,12 +18,17 @@ namespace Algorithms {
|
||||
public AStar(NodeGrid nodeGrid) {
|
||||
this._nodeGrid = nodeGrid;
|
||||
_states = new List<GridState>();
|
||||
ChangeController = new ChangeController(nodeGrid.RenderNodeTypes());
|
||||
}
|
||||
|
||||
public Stack<Node> FindPath(Vector2Int start, Vector2Int end) {
|
||||
this.Start = start;
|
||||
this.End = end;
|
||||
|
||||
ChangeController.AddChange(new Change(start.x, start.y, GridNodeType.Start, GridNodeType.Empty));
|
||||
ChangeController.AddChange(new Change(end.x, end.y, GridNodeType.End, GridNodeType.Empty));
|
||||
|
||||
|
||||
var startNode = new Node(start, true);
|
||||
var endNode = new Node(end, true);
|
||||
|
||||
@@ -42,6 +48,9 @@ namespace Algorithms {
|
||||
_openList.Remove(current);
|
||||
|
||||
current.State = NodeState.Closed;
|
||||
ChangeController.AddChange(new Change(
|
||||
current.Position.x, current.Position.y,
|
||||
GridNodeType.Expanded, GridNodeType.Seen));
|
||||
_closedList.Add(current);
|
||||
|
||||
if (current.Position == endNode.Position)
|
||||
@@ -58,15 +67,13 @@ namespace Algorithms {
|
||||
node.DistanceToTarget = NodeGrid.Manhattan(node, endNode);
|
||||
node.Cost = node.Weight + node.Parent.Cost;
|
||||
|
||||
// Set to open and add to open list (sorted)
|
||||
node.State = NodeState.Open;
|
||||
// _openList.Add(node);
|
||||
ChangeController.AddChange(new Change(node.Position.x, node.Position.y, GridNodeType.Seen, GridNodeType.Empty));
|
||||
|
||||
// Insert the new node into the sorted open list in ascending order
|
||||
int index = _openList.BinarySearch(node);
|
||||
if (index < 0) index = ~index;
|
||||
_openList.Insert(index, node);
|
||||
// _openList = _openList.OrderBy(n => n.F).ToList();
|
||||
// _openList.Sort((n, o) => n.F.CompareTo(o.F));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,7 +90,7 @@ namespace Algorithms {
|
||||
_path.Push(temp);
|
||||
RecordState();
|
||||
temp = temp.Parent;
|
||||
} while (temp != startNode && temp != null);
|
||||
} while (temp != null && !temp.Equals(startNode));
|
||||
|
||||
return _path;
|
||||
}
|
||||
|
||||
@@ -138,5 +138,17 @@ namespace Algorithms {
|
||||
Grid[(int) x, (int) y].Walkable = true;
|
||||
}
|
||||
}
|
||||
|
||||
public GridNodeType[,] RenderNodeTypes() {
|
||||
GridNodeType[,] nodeTypeGrid = new GridNodeType[Grid.GetLength(0), Grid.GetLength(1)];
|
||||
|
||||
for (int x = 0; x < Grid.GetLength(0); x++) {
|
||||
for (int y = 0; y < Grid.GetLength(1); y++) {
|
||||
nodeTypeGrid[x, y] = Grid[x, y].Walkable ? GridNodeType.Empty : GridNodeType.Wall;
|
||||
}
|
||||
}
|
||||
|
||||
return nodeTypeGrid;
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Paths/Assets/Scripts/Change.cs
Normal file
15
Paths/Assets/Scripts/Change.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
public readonly struct Change {
|
||||
public readonly int X;
|
||||
public readonly int Y;
|
||||
public readonly GridNodeType New;
|
||||
public readonly GridNodeType Old;
|
||||
public readonly float Time;
|
||||
|
||||
public Change(int x, int y, GridNodeType newType, GridNodeType oldType) {
|
||||
this.X = x;
|
||||
this.Y = y;
|
||||
this.New = newType;
|
||||
this.Old = oldType;
|
||||
this.Time = UnityEngine.Time.realtimeSinceStartup;
|
||||
}
|
||||
}
|
||||
3
Paths/Assets/Scripts/Change.cs.meta
Normal file
3
Paths/Assets/Scripts/Change.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce434b5fefcc4447bc8adc1ab11dd964
|
||||
timeCreated: 1606250638
|
||||
107
Paths/Assets/Scripts/ChangeController.cs
Normal file
107
Paths/Assets/Scripts/ChangeController.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Helps manage Change value types by rendering forward/backward movements to a Enum array.
|
||||
/// </summary>
|
||||
public class ChangeController {
|
||||
private readonly GridNodeType[,] _initial;
|
||||
public GridNodeType[,] Current { get; private set; }
|
||||
|
||||
public int Index { get; private set; }
|
||||
private readonly List<Change> _changes;
|
||||
public int Count => _changes.Count;
|
||||
public Change CurrentChange => _changes[Index];
|
||||
|
||||
public ChangeController(GridNodeType[,] initial) {
|
||||
_initial = initial;
|
||||
Current = initial;
|
||||
Index = 0;
|
||||
_changes = new List<Change>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the ChangeController back to the initial state.
|
||||
/// </summary>
|
||||
public void Reset() {
|
||||
Current = _initial;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new change to the list.
|
||||
/// </summary>
|
||||
/// <param name="change">A valid Change value type.</param>
|
||||
public void AddChange(Change change) {
|
||||
_changes.Add(change);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Move the ChangeController's current index forward by index.
|
||||
/// Positive values only, wil only result in forward movement (if any).
|
||||
/// </summary>
|
||||
/// <param name="n">The number of times to move forward.</param>
|
||||
public void Forward(int n = 1) {
|
||||
if (n < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(n));
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
Change cur = _changes[++Index];
|
||||
Current[cur.X, cur.Y] = cur.New;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move the ChangeController's current index backward by index.
|
||||
/// Positive values only, will only result in backward movement (if any).
|
||||
/// </summary>
|
||||
/// <param name="n">The number of times to move backward.</param>
|
||||
public void Reverse(int n = 1) {
|
||||
if (n < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(n));
|
||||
|
||||
if (n > 5 && Index - 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];
|
||||
Current[cur.X, cur.Y] = cur.Old;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move the ChangeController's current index by index, forward or backward.
|
||||
/// Values can be positive or negative to determine movement. Best used for calculating movement via difference.
|
||||
/// </summary>
|
||||
/// <param name="n">The number of times to move. Sign determines direction.</param>
|
||||
public void Move(int n) {
|
||||
if (n > 0)
|
||||
Forward(n);
|
||||
else if (n < 0)
|
||||
Reverse(-n);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move to this specific index in the ChangeController's states.
|
||||
/// All changes will be applied to get here, either forward or reverse.
|
||||
/// </summary>
|
||||
/// <param name="index">The new index to move to.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">When the index is invalid.</exception>
|
||||
public void MoveTo(int index) {
|
||||
// check that index is valid at least
|
||||
if (index >= _changes.Count || index < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(index),
|
||||
$"Cannot move to change index {index}. Only indexes from 0 to {_changes.Count - 1} are valid.");
|
||||
|
||||
// diff & move to
|
||||
int diff = index - Index;
|
||||
if (diff != 0)
|
||||
// prefer resetting if index is 0 and it needs to move at least some.
|
||||
if (index == 0 && diff > 5)
|
||||
Reset();
|
||||
else
|
||||
Move(diff);
|
||||
}
|
||||
}
|
||||
3
Paths/Assets/Scripts/ChangeController.cs.meta
Normal file
3
Paths/Assets/Scripts/ChangeController.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f90bfa4d7a4f45968a29175338225e65
|
||||
timeCreated: 1606251343
|
||||
@@ -68,12 +68,12 @@ public class GridController : MonoBehaviour {
|
||||
/// <summary>
|
||||
/// Loads a GridState into the Grid Shader's StructuredBuffer
|
||||
/// </summary>
|
||||
/// <param name="gridState"></param>
|
||||
public void LoadGridState(GridState gridState) {
|
||||
/// <param name="state"></param>
|
||||
public void LoadGridState(GridNodeType[,] state) {
|
||||
// Loop over matrix and set values via cast Enum to int
|
||||
for (int x = 0; x < gridState.Grid.GetLength(0); x++) {
|
||||
for (int y = 0; y < gridState.Grid.GetLength(1); y++)
|
||||
this.SetValue(x, y, (int) gridState.Grid[x, y]);
|
||||
for (int x = 0; x < state.GetLength(0); x++) {
|
||||
for (int y = 0; y < state.GetLength(1); y++)
|
||||
this.SetValue(x, y, (int) state[x, y]);
|
||||
}
|
||||
|
||||
UpdateShader(PropertyName.Values);
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Linq;
|
||||
using Algorithms;
|
||||
using UnityEngine;
|
||||
|
||||
public class GridState {
|
||||
public struct GridState {
|
||||
public readonly GridNodeType[,] Grid;
|
||||
public readonly float Time;
|
||||
|
||||
|
||||
@@ -22,4 +22,5 @@ public interface IPathfinding {
|
||||
List<GridState> GetStates();
|
||||
Vector2Int Start { get; }
|
||||
Vector2Int End { get; }
|
||||
ChangeController ChangeController { get; }
|
||||
}
|
||||
@@ -10,7 +10,7 @@ using UnityEngine;
|
||||
/// </summary>
|
||||
public class Manager : MonoBehaviour {
|
||||
private IPathfinding _algorithm;
|
||||
private List<GridState> _states;
|
||||
private ChangeController _state;
|
||||
private int _curIndex;
|
||||
private Stack<Node> _path;
|
||||
private float _lastStart;
|
||||
@@ -29,7 +29,6 @@ public class Manager : MonoBehaviour {
|
||||
}
|
||||
|
||||
public void Start() {
|
||||
_states = new List<GridState>();
|
||||
GeneratePath();
|
||||
Resize();
|
||||
}
|
||||
@@ -42,10 +41,10 @@ public class Manager : MonoBehaviour {
|
||||
public void Update() {
|
||||
var increment = Time.deltaTime * speed;
|
||||
if (clampIncrement > 0)
|
||||
increment = Mathf.Clamp(increment, 0, _states.Count * Time.deltaTime / clampIncrement);
|
||||
increment = Mathf.Clamp(increment, 0, _state.Count * Time.deltaTime / clampIncrement);
|
||||
_runtime += increment;
|
||||
|
||||
if (CurrentIndex < _states.Count)
|
||||
if (CurrentIndex < _state.Count)
|
||||
this.LoadNextState();
|
||||
else {
|
||||
try {
|
||||
@@ -61,30 +60,29 @@ public class Manager : MonoBehaviour {
|
||||
|
||||
private void GeneratePath() {
|
||||
var nodeGrid = new NodeGrid(gridController.width, gridController.height);
|
||||
_algorithm = new AStar(nodeGrid);
|
||||
|
||||
Vector2Int start = nodeGrid.RandomPosition();
|
||||
// Vector2Int start = new Vector2Int(30, 30);
|
||||
Vector2Int end = nodeGrid.RandomPosition();
|
||||
|
||||
nodeGrid.ApplyGenerator(new RandomPlacement(0.20f, true, true));
|
||||
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);
|
||||
|
||||
_states = _algorithm.GetStates();
|
||||
_state = _algorithm.ChangeController;
|
||||
}
|
||||
|
||||
private void LoadNextState() {
|
||||
GridState state = _states[CurrentIndex];
|
||||
gridController.LoadGridState(state);
|
||||
_state.MoveTo(CurrentIndex);
|
||||
gridController.LoadGridState(_state.Current);
|
||||
|
||||
float change = state.Time - _lastStart;
|
||||
float change = _state.CurrentChange.Time - _lastStart;
|
||||
string pathCount = _path != null ? $"{_path.Count}" : "N/A";
|
||||
debugText.text = $"{change * 1000.0:F1}ms\n" +
|
||||
$"{this.CurrentIndex:000} / {this._states.Count:000}\n" +
|
||||
$"{this.CurrentIndex:000} / {_state.Count:000}\n" +
|
||||
$"Path: {pathCount} tiles";
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user