fix off by one Random.Range generation (??), improve docs, GetAdjacentNodesArray

This commit is contained in:
Xevion
2020-11-13 19:19:53 -06:00
parent 30b115ab2a
commit ce4343c349
7 changed files with 77 additions and 52 deletions

View File

@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=assets_005Ceditor/@EntryIndexedValue">False</s:Boolean></wpf:ResourceDictionary>

View File

@@ -1,32 +1,34 @@
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
/// <summary> namespace Editor {
/// Prevents script compilation and reload while in play mode. /// <summary>
/// The editor will show a the spinning reload icon if there are unapplied changes but will not actually /// Prevents script compilation and reload while in play mode.
/// apply them until playmode is exited. /// The editor will show a the spinning reload icon if there are unapplied changes but will not actually
/// Note: Script compile errors will not be shown while in play mode. /// apply them until playmode is exited.
/// Derived from the instructions here: /// Note: Script compile errors will not be shown while in play mode.
/// https://support.unity3d.com/hc/en-us/articles/210452343-How-to-stop-automatic-assembly-compilation-from-script /// Derived from the instructions here:
/// </summary> /// https://support.unity3d.com/hc/en-us/articles/210452343-How-to-stop-automatic-assembly-compilation-from-script
[InitializeOnLoad] /// </summary>
public class DisableScriptReload { [InitializeOnLoad]
static DisableScriptReload() { public class DisableScriptReload {
EditorApplication.playModeStateChanged static DisableScriptReload() {
+= OnPlayModeStateChanged; EditorApplication.playModeStateChanged
} += OnPlayModeStateChanged;
}
static void OnPlayModeStateChanged(PlayModeStateChange stateChange) { static void OnPlayModeStateChanged(PlayModeStateChange stateChange) {
switch (stateChange) { switch (stateChange) {
case (PlayModeStateChange.EnteredPlayMode): { case (PlayModeStateChange.EnteredPlayMode): {
EditorApplication.LockReloadAssemblies(); EditorApplication.LockReloadAssemblies();
Debug.Log("Assembly Reload locked as entering play mode"); Debug.Log("Assembly Reload locked as entering play mode");
break; break;
} }
case (PlayModeStateChange.ExitingPlayMode): { case (PlayModeStateChange.ExitingPlayMode): {
Debug.Log("Assembly Reload unlocked as exiting play mode"); Debug.Log("Assembly Reload unlocked as exiting play mode");
EditorApplication.UnlockReloadAssemblies(); EditorApplication.UnlockReloadAssemblies();
break; break;
}
} }
} }
} }

View File

@@ -43,7 +43,7 @@ namespace Algorithms {
_closedList.Add(current); _closedList.Add(current);
RecordState(); RecordState();
List<Node> adjacentNodes = this._nodeGrid.GetAdjacentNodes(current); List<Node> adjacentNodes = this._nodeGrid.GetAdjacentNodesList(current);
if (adjacentNodes.Count > 0) { if (adjacentNodes.Count > 0) {
foreach (Node n in adjacentNodes) { foreach (Node n in adjacentNodes) {

View File

@@ -20,10 +20,11 @@ namespace Algorithms {
"The height of the grid must be a positive non-zero integer."); "The height of the grid must be a positive non-zero integer.");
grid = new List<List<Node>>(width); grid = new List<List<Node>>(width);
// Fill grid with width*height nodes, zero-indexed // Fill grid with width*height nodes, zero-indexed
foreach (int x in Enumerable.Range(0, width - 1)) { for (int x = 0; x < width; x++) {
List<Node> list = new List<Node>(height); List<Node> list = new List<Node>(height);
foreach (int y in Enumerable.Range(0, height - 1)) for (int y = 0; y < height; y++)
list.Add(new Node(new Vector2Int(x, y), true)); list.Add(new Node(new Vector2Int(x, y), true));
grid.Add(list); grid.Add(list);
@@ -40,7 +41,7 @@ namespace Algorithms {
Width = this.grid.Count; Width = this.grid.Count;
} }
public List<Node> GetAdjacentNodes(Node node) { public List<Node> GetAdjacentNodesList(Node node) {
List<Node> temp = new List<Node>(); List<Node> temp = new List<Node>();
int col = node.Position.x; int col = node.Position.x;
@@ -53,7 +54,25 @@ namespace Algorithms {
return temp; return temp;
} }
public Node[] GetAdjacentNodesArray(Node node) {
int col = node.Position.x;
int row = node.Position.y;
return new Node[] {
row + 1 < Height ? grid[col][row + 1] : null,
row - 1 >= 0 ? grid[col][row - 1] : null,
col - 1 >= 0 ? grid[col - 1][row] : null,
col + 1 < Width ? grid[col + 1][row] : null
};
}
/// <summary>
/// Tests whether a coordinate is valid on the NodeGrid
/// </summary>
/// <param name="x">The X (column) coordinate</param>
/// <param name="y">The Y (row) coordinate</param>
/// <returns></returns>
public bool IsValid(int x, int y) { public bool IsValid(int x, int y) {
return x > 0 && x < Width && y > 0 && y < Height; return x > 0 && x < Width && y > 0 && y < Height;
} }
@@ -81,8 +100,8 @@ namespace Algorithms {
/// </summary> /// </summary>
public void AddRandomWall() { public void AddRandomWall() {
while (true) { while (true) {
int x = Random.Range(0, Width - 1); int x = Random.Range(0, Width);
int y = Random.Range(0, Height - 1); int y = Random.Range(0, Height);
if (grid[x][y].Walkable) { if (grid[x][y].Walkable) {
grid[x][y].Walkable = false; grid[x][y].Walkable = false;
@@ -104,7 +123,7 @@ namespace Algorithms {
/// </summary> /// </summary>
/// <returns>a valid Vector2Int position within the grid</returns> /// <returns>a valid Vector2Int position within the grid</returns>
public Vector2Int RandomPosition() { public Vector2Int RandomPosition() {
return new Vector2Int(Random.Range(0, Width - 1), Random.Range(0, Height - 1)); return new Vector2Int(Random.Range(0, Width), Random.Range(0, Height));
} }
/// <summary> /// <summary>
@@ -127,13 +146,13 @@ namespace Algorithms {
public IEnumerable<Node> Empty() { public IEnumerable<Node> Empty() {
return this.Iterator().Where(node => node.Walkable); return this.Iterator().Where(node => node.Walkable);
} }
/// <summary> /// <summary>
/// Returns a random valid node on the grid. /// Returns a random valid node on the grid.
/// </summary> /// </summary>
/// <returns>A Node object.</returns> /// <returns>A Node object.</returns>
public Node GetRandomNode() { public Node GetRandomNode() {
return grid[Random.Range(0, Width - 1)][Random.Range(0, Height - 1)]; return grid[Random.Range(0, Width)][Random.Range(0, Height)];
} }
} }
} }

View File

@@ -1,5 +1,11 @@
using Algorithms; using Algorithms;
public interface ILevelGenerator { public interface ILevelGenerator {
/// <summary>
/// Applies the LevelGenerator's algorithm.
/// A empty NodeGrid is recommended, as the algorithm may perform in unexpected ways, possibly even fail.
/// </summary>
/// <param name="nodeGrid">A NodeGrid object.</param>
/// <returns>A modified NodeGrid object.</returns>
NodeGrid Generate(NodeGrid nodeGrid); NodeGrid Generate(NodeGrid nodeGrid);
} }

View File

@@ -10,6 +10,9 @@ namespace LevelGeneration {
/// <summary> /// <summary>
/// A simple level generator implementing the Drunkard Walk algorithm. /// A simple level generator implementing the Drunkard Walk algorithm.
/// This implementation simply starts 'walks' a certain number of times.
/// Each walk chooses a node, and then repeatedly chooses an adjacent node randomly.
/// Each move clears (or adds) walls.
/// </summary> /// </summary>
/// <param name="walks">The number of independent walks that will be started.</param> /// <param name="walks">The number of independent walks that will be started.</param>
/// <param name="walkLength">The maximum number of nodes to be added/cleared</param> /// <param name="walkLength">The maximum number of nodes to be added/cleared</param>
@@ -24,16 +27,10 @@ namespace LevelGeneration {
_continueBias = continueBias; _continueBias = continueBias;
} }
/// <summary>
///
/// </summary>
/// <param name="nodeGrid"></param>
/// <returns></returns>
public NodeGrid Generate(NodeGrid nodeGrid) { public NodeGrid Generate(NodeGrid nodeGrid) {
for (int unused = 0; unused < _walks; unused++) { for (int unused = 0; unused < _walks; unused++) {
Node node = nodeGrid.GetRandomNode(); Node node = nodeGrid.GetRandomNode();
Node[] nodes = nodeGrid.GetAdjacentNodesArray(node);
nodeGrid.GetAdjacentNodes(node);
} }
return nodeGrid; return nodeGrid;

View File

@@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Algorithms; using Algorithms;
using TMPro; using TMPro;
using UnityEngine; using UnityEngine;
@@ -12,7 +11,7 @@ public class Manager : MonoBehaviour {
private IPathfinding _algorithm; private IPathfinding _algorithm;
private List<GridState> _states; private List<GridState> _states;
private int _curIndex; private int _curIndex;
private Stack<Node> path; private Stack<Node> _path;
private float _lastStart; private float _lastStart;
private float _runtime; private float _runtime;
@@ -30,10 +29,10 @@ public class Manager : MonoBehaviour {
GeneratePath(); GeneratePath();
} }
public void OnDrawGizmos() { // public void OnDrawGizmos() {
float size = (float) (10.0 / gridController.size); // float size = (float) (10.0 / gridController.size);
Gizmos.DrawWireCube(transform.position, new Vector3(size, size, size)); // Gizmos.DrawWireCube(transform.position, new Vector3(size, size, size));
} // }
public void Update() { public void Update() {
_runtime += Time.deltaTime * speed; _runtime += Time.deltaTime * speed;
@@ -56,8 +55,8 @@ public class Manager : MonoBehaviour {
var nodeGrid = new NodeGrid(gridController.size, gridController.size); var nodeGrid = new NodeGrid(gridController.size, gridController.size);
_algorithm = new AStar(nodeGrid); _algorithm = new AStar(nodeGrid);
// Vector2 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();
@@ -68,7 +67,7 @@ public class Manager : MonoBehaviour {
nodeGrid.GetNode(start).Walkable = true; nodeGrid.GetNode(start).Walkable = true;
nodeGrid.GetNode(end).Walkable = true; nodeGrid.GetNode(end).Walkable = true;
path = _algorithm.FindPath(start, end); _path = _algorithm.FindPath(start, end);
_states = _algorithm.GetStates(); _states = _algorithm.GetStates();
@@ -80,7 +79,7 @@ public class Manager : MonoBehaviour {
gridController.LoadGridState(state); gridController.LoadGridState(state);
float change = state.Time - _lastStart; float change = state.Time - _lastStart;
string pathCount = path != null ? $"{path.Count}" : "N/A"; string pathCount = _path != null ? $"{_path.Count}" : "N/A";
debugText.text = debugText.text =
$"{change * 1000.0:F1}ms\n{this.CurrentIndex:000} / {this._states.Count:000}\nPath: {pathCount} tiles"; $"{change * 1000.0:F1}ms\n{this.CurrentIndex:000} / {this._states.Count:000}\nPath: {pathCount} tiles";
} }