mirror of
https://github.com/Xevion/Paths.git
synced 2025-12-11 06:08:04 -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> _openList;
|
||||||
private List<Node> _closedList;
|
private List<Node> _closedList;
|
||||||
private List<GridState> _states;
|
private List<GridState> _states;
|
||||||
|
public ChangeController ChangeController { get; private set; }
|
||||||
|
|
||||||
public Vector2Int Start { get; private set; }
|
public Vector2Int Start { get; private set; }
|
||||||
public Vector2Int End { get; private set; }
|
public Vector2Int End { get; private set; }
|
||||||
@@ -17,11 +18,16 @@ namespace Algorithms {
|
|||||||
public AStar(NodeGrid nodeGrid) {
|
public AStar(NodeGrid nodeGrid) {
|
||||||
this._nodeGrid = nodeGrid;
|
this._nodeGrid = nodeGrid;
|
||||||
_states = new List<GridState>();
|
_states = new List<GridState>();
|
||||||
|
ChangeController = new ChangeController(nodeGrid.RenderNodeTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stack<Node> FindPath(Vector2Int start, Vector2Int end) {
|
public Stack<Node> FindPath(Vector2Int start, Vector2Int end) {
|
||||||
this.Start = start;
|
this.Start = start;
|
||||||
this.End = end;
|
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 startNode = new Node(start, true);
|
||||||
var endNode = new Node(end, true);
|
var endNode = new Node(end, true);
|
||||||
@@ -42,11 +48,14 @@ namespace Algorithms {
|
|||||||
_openList.Remove(current);
|
_openList.Remove(current);
|
||||||
|
|
||||||
current.State = NodeState.Closed;
|
current.State = NodeState.Closed;
|
||||||
|
ChangeController.AddChange(new Change(
|
||||||
|
current.Position.x, current.Position.y,
|
||||||
|
GridNodeType.Expanded, GridNodeType.Seen));
|
||||||
_closedList.Add(current);
|
_closedList.Add(current);
|
||||||
|
|
||||||
if (current.Position == endNode.Position)
|
if (current.Position == endNode.Position)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
RecordState();
|
RecordState();
|
||||||
|
|
||||||
Node[] adjacentNodes = this._nodeGrid.GetAdjacentNodesArray(current);
|
Node[] adjacentNodes = this._nodeGrid.GetAdjacentNodesArray(current);
|
||||||
@@ -57,16 +66,14 @@ namespace Algorithms {
|
|||||||
node.Parent = current;
|
node.Parent = current;
|
||||||
node.DistanceToTarget = NodeGrid.Manhattan(node, endNode);
|
node.DistanceToTarget = NodeGrid.Manhattan(node, endNode);
|
||||||
node.Cost = node.Weight + node.Parent.Cost;
|
node.Cost = node.Weight + node.Parent.Cost;
|
||||||
|
|
||||||
// Set to open and add to open list (sorted)
|
|
||||||
node.State = NodeState.Open;
|
|
||||||
// _openList.Add(node);
|
|
||||||
|
|
||||||
|
node.State = NodeState.Open;
|
||||||
|
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);
|
int index = _openList.BinarySearch(node);
|
||||||
if (index < 0) index = ~index;
|
if (index < 0) index = ~index;
|
||||||
_openList.Insert(index, node);
|
_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);
|
_path.Push(temp);
|
||||||
RecordState();
|
RecordState();
|
||||||
temp = temp.Parent;
|
temp = temp.Parent;
|
||||||
} while (temp != startNode && temp != null);
|
} while (temp != null && !temp.Equals(startNode));
|
||||||
|
|
||||||
return _path;
|
return _path;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,5 +138,17 @@ namespace Algorithms {
|
|||||||
Grid[(int) x, (int) y].Walkable = true;
|
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>
|
/// <summary>
|
||||||
/// Loads a GridState into the Grid Shader's StructuredBuffer
|
/// Loads a GridState into the Grid Shader's StructuredBuffer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="gridState"></param>
|
/// <param name="state"></param>
|
||||||
public void LoadGridState(GridState gridState) {
|
public void LoadGridState(GridNodeType[,] state) {
|
||||||
// Loop over matrix and set values via cast Enum to int
|
// Loop over matrix and set values via cast Enum to int
|
||||||
for (int x = 0; x < gridState.Grid.GetLength(0); x++) {
|
for (int x = 0; x < state.GetLength(0); x++) {
|
||||||
for (int y = 0; y < gridState.Grid.GetLength(1); y++)
|
for (int y = 0; y < state.GetLength(1); y++)
|
||||||
this.SetValue(x, y, (int) gridState.Grid[x, y]);
|
this.SetValue(x, y, (int) state[x, y]);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateShader(PropertyName.Values);
|
UpdateShader(PropertyName.Values);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using System.Linq;
|
|||||||
using Algorithms;
|
using Algorithms;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
public class GridState {
|
public struct GridState {
|
||||||
public readonly GridNodeType[,] Grid;
|
public readonly GridNodeType[,] Grid;
|
||||||
public readonly float Time;
|
public readonly float Time;
|
||||||
|
|
||||||
|
|||||||
@@ -22,4 +22,5 @@ public interface IPathfinding {
|
|||||||
List<GridState> GetStates();
|
List<GridState> GetStates();
|
||||||
Vector2Int Start { get; }
|
Vector2Int Start { get; }
|
||||||
Vector2Int End { get; }
|
Vector2Int End { get; }
|
||||||
|
ChangeController ChangeController { get; }
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ using UnityEngine;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Manager : MonoBehaviour {
|
public class Manager : MonoBehaviour {
|
||||||
private IPathfinding _algorithm;
|
private IPathfinding _algorithm;
|
||||||
private List<GridState> _states;
|
private ChangeController _state;
|
||||||
private int _curIndex;
|
private int _curIndex;
|
||||||
private Stack<Node> _path;
|
private Stack<Node> _path;
|
||||||
private float _lastStart;
|
private float _lastStart;
|
||||||
@@ -29,7 +29,6 @@ public class Manager : MonoBehaviour {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void Start() {
|
public void Start() {
|
||||||
_states = new List<GridState>();
|
|
||||||
GeneratePath();
|
GeneratePath();
|
||||||
Resize();
|
Resize();
|
||||||
}
|
}
|
||||||
@@ -42,10 +41,10 @@ public class Manager : MonoBehaviour {
|
|||||||
public void Update() {
|
public void Update() {
|
||||||
var increment = Time.deltaTime * speed;
|
var increment = Time.deltaTime * speed;
|
||||||
if (clampIncrement > 0)
|
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;
|
_runtime += increment;
|
||||||
|
|
||||||
if (CurrentIndex < _states.Count)
|
if (CurrentIndex < _state.Count)
|
||||||
this.LoadNextState();
|
this.LoadNextState();
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
@@ -61,30 +60,29 @@ public class Manager : MonoBehaviour {
|
|||||||
|
|
||||||
private void GeneratePath() {
|
private void GeneratePath() {
|
||||||
var nodeGrid = new NodeGrid(gridController.width, gridController.height);
|
var nodeGrid = new NodeGrid(gridController.width, gridController.height);
|
||||||
_algorithm = new AStar(nodeGrid);
|
|
||||||
|
|
||||||
Vector2Int start = nodeGrid.RandomPosition();
|
Vector2Int start = nodeGrid.RandomPosition();
|
||||||
// Vector2Int start = new Vector2Int(30, 30);
|
// Vector2Int start = new Vector2Int(30, 30);
|
||||||
Vector2Int end = nodeGrid.RandomPosition();
|
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(start).Walkable = true;
|
||||||
nodeGrid.GetNode(end).Walkable = true;
|
nodeGrid.GetNode(end).Walkable = true;
|
||||||
|
|
||||||
|
_algorithm = new AStar(nodeGrid);
|
||||||
_path = _algorithm.FindPath(start, end);
|
_path = _algorithm.FindPath(start, end);
|
||||||
|
_state = _algorithm.ChangeController;
|
||||||
_states = _algorithm.GetStates();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadNextState() {
|
private void LoadNextState() {
|
||||||
GridState state = _states[CurrentIndex];
|
_state.MoveTo(CurrentIndex);
|
||||||
gridController.LoadGridState(state);
|
gridController.LoadGridState(_state.Current);
|
||||||
|
|
||||||
float change = state.Time - _lastStart;
|
float change = _state.CurrentChange.Time - _lastStart;
|
||||||
string pathCount = _path != null ? $"{_path.Count}" : "N/A";
|
string pathCount = _path != null ? $"{_path.Count}" : "N/A";
|
||||||
debugText.text = $"{change * 1000.0:F1}ms\n" +
|
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";
|
$"Path: {pathCount} tiles";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user