├── .gitignore ├── Assets ├── Models.meta ├── Models │ ├── Materials.meta │ ├── Materials │ │ ├── m_TileOutline.mat │ │ ├── m_TileOutline.mat.meta │ │ ├── m_baseTile.mat │ │ └── m_baseTile.mat.meta │ ├── tile.fbx │ └── tile.fbx.meta ├── Prefabs.meta ├── Prefabs │ ├── P_NodeView.prefab │ └── P_NodeView.prefab.meta ├── Scenes.meta ├── Scenes │ ├── U_Playground.unity │ └── U_Playground.unity.meta ├── Scripts.meta └── Scripts │ ├── Nodes&Graphs.meta │ ├── Nodes&Graphs │ ├── GraphController.cs │ ├── GraphController.cs.meta │ ├── Node.cs │ ├── Node.cs.meta │ ├── NodeView.cs │ ├── NodeView.cs.meta │ ├── Pathfinder.cs │ ├── Pathfinder.cs.meta │ ├── PriorityQueue.cs │ └── PriorityQueue.cs.meta │ ├── UI.meta │ └── UI │ ├── RaycastController.cs │ ├── RaycastController.cs.meta │ ├── UIController.cs │ └── UIController.cs.meta ├── LICENSE ├── Packages ├── manifest.json └── packages-lock.json ├── ProjectSettings ├── AudioManager.asset ├── ClusterInputManager.asset ├── DynamicsManager.asset ├── EditorBuildSettings.asset ├── EditorSettings.asset ├── GraphicsSettings.asset ├── InputManager.asset ├── NavMeshAreas.asset ├── NetworkManager.asset ├── PackageManagerSettings.asset ├── Physics2DSettings.asset ├── PresetManager.asset ├── ProjectSettings.asset ├── ProjectVersion.txt ├── QualitySettings.asset ├── TagManager.asset ├── TimeManager.asset ├── UnityConnectSettings.asset ├── VFXManager.asset ├── VersionControlSettings.asset └── XRSettings.asset └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Mm]emoryCaptures/ 12 | 13 | # Never ignore Asset meta data 14 | !/[Aa]ssets/**/*.meta 15 | 16 | # Storm 17 | /[Aa]ssets/_[Ss]torm 18 | 19 | # Uncomment this line if you wish to ignore the asset store tools plugin 20 | # /[Aa]ssets/AssetStoreTools* 21 | 22 | # Autogenerated Jetbrains Rider plugin 23 | [Aa]ssets/Plugins/Editor/JetBrains* 24 | 25 | # Visual Studio cache directory 26 | .vs/ 27 | 28 | # Gradle cache directory 29 | .gradle/ 30 | 31 | # Autogenerated VS/MD/Consulo solution and project files 32 | ExportedObj/ 33 | .consulo/ 34 | *.csproj 35 | *.unityproj 36 | *.sln 37 | *.suo 38 | *.tmp 39 | *.user 40 | *.userprefs 41 | *.pidb 42 | *.booproj 43 | *.svd 44 | *.pdb 45 | *.mdb 46 | *.opendb 47 | *.VC.db 48 | 49 | # Unity3D generated meta files 50 | *.pidb.meta 51 | *.pdb.meta 52 | *.mdb.meta 53 | 54 | # Unity3D generated file on crash reports 55 | sysinfo.txt 56 | 57 | # Builds 58 | *.apk 59 | *.unitypackage 60 | 61 | # Crashlytics generated file 62 | crashlytics-build.properties 63 | 64 | .vscode/settings.json 65 | UserSettings/EditorUserSettings.asset 66 | -------------------------------------------------------------------------------- /Assets/Models.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fa9f4ff22c229aa49b07ab54ea3d72c1 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Models/Materials.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 43a334cfa90e77242ab350f2f63b2478 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Models/Materials/m_TileOutline.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/Assets/Models/Materials/m_TileOutline.mat -------------------------------------------------------------------------------- /Assets/Models/Materials/m_TileOutline.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a78b5ef7a3956254d88d0cbb546b62f0 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Models/Materials/m_baseTile.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/Assets/Models/Materials/m_baseTile.mat -------------------------------------------------------------------------------- /Assets/Models/Materials/m_baseTile.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bb9071f32cfb00440be5e58d03ec328b 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Models/tile.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/Assets/Models/tile.fbx -------------------------------------------------------------------------------- /Assets/Models/tile.fbx.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 07207b35bda0b0a42b326c138182dff2 3 | ModelImporter: 4 | serializedVersion: 20101 5 | internalIDToNameTable: [] 6 | externalObjects: {} 7 | materials: 8 | materialImportMode: 1 9 | materialName: 0 10 | materialSearch: 1 11 | materialLocation: 1 12 | animations: 13 | legacyGenerateAnimations: 4 14 | bakeSimulation: 0 15 | resampleCurves: 1 16 | optimizeGameObjects: 0 17 | motionNodeName: 18 | rigImportErrors: 19 | rigImportWarnings: 20 | animationImportErrors: 21 | animationImportWarnings: 22 | animationRetargetingWarnings: 23 | animationDoRetargetingWarnings: 0 24 | importAnimatedCustomProperties: 0 25 | importConstraints: 0 26 | animationCompression: 1 27 | animationRotationError: 0.5 28 | animationPositionError: 0.5 29 | animationScaleError: 0.5 30 | animationWrapMode: 0 31 | extraExposedTransformPaths: [] 32 | extraUserProperties: [] 33 | clipAnimations: [] 34 | isReadable: 0 35 | meshes: 36 | lODScreenPercentages: [] 37 | globalScale: 100 38 | meshCompression: 0 39 | addColliders: 0 40 | useSRGBMaterialColor: 1 41 | sortHierarchyByName: 1 42 | importVisibility: 0 43 | importBlendShapes: 0 44 | importCameras: 0 45 | importLights: 0 46 | fileIdsGeneration: 2 47 | swapUVChannels: 0 48 | generateSecondaryUV: 0 49 | useFileUnits: 1 50 | keepQuads: 0 51 | weldVertices: 1 52 | bakeAxisConversion: 0 53 | preserveHierarchy: 0 54 | skinWeightsMode: 0 55 | maxBonesPerVertex: 4 56 | minBoneWeight: 0.001 57 | meshOptimizationFlags: -1 58 | indexFormat: 0 59 | secondaryUVAngleDistortion: 8 60 | secondaryUVAreaDistortion: 15.000001 61 | secondaryUVHardAngle: 88 62 | secondaryUVMarginMethod: 1 63 | secondaryUVMinLightmapResolution: 40 64 | secondaryUVMinObjectScale: 1 65 | secondaryUVPackMargin: 4 66 | useFileScale: 1 67 | tangentSpace: 68 | normalSmoothAngle: 60 69 | normalImportMode: 0 70 | tangentImportMode: 3 71 | normalCalculationMode: 4 72 | legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 73 | blendShapeNormalImportMode: 1 74 | normalSmoothingSource: 0 75 | referencedClips: [] 76 | importAnimation: 1 77 | humanDescription: 78 | serializedVersion: 3 79 | human: [] 80 | skeleton: [] 81 | armTwist: 0.5 82 | foreArmTwist: 0.5 83 | upperLegTwist: 0.5 84 | legTwist: 0.5 85 | armStretch: 0.05 86 | legStretch: 0.05 87 | feetSpacing: 0 88 | globalScale: 1 89 | rootMotionBoneName: 90 | hasTranslationDoF: 0 91 | hasExtraRoot: 0 92 | skeletonHasParents: 1 93 | lastHumanDescriptionAvatarSource: {instanceID: 0} 94 | autoGenerateAvatarMappingIfUnspecified: 1 95 | animationType: 2 96 | humanoidOversampling: 1 97 | avatarSetup: 0 98 | additionalBone: 0 99 | userData: 100 | assetBundleName: 101 | assetBundleVariant: 102 | -------------------------------------------------------------------------------- /Assets/Prefabs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b8a49e3f8c721ae41ae6a3c1a4a38987 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Prefabs/P_NodeView.prefab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/Assets/Prefabs/P_NodeView.prefab -------------------------------------------------------------------------------- /Assets/Prefabs/P_NodeView.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 62b57766d8885f34f8b8ae4441de8c14 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 21769a3b132b2344f8d3b103e818a826 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Scenes/U_Playground.unity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/Assets/Scenes/U_Playground.unity -------------------------------------------------------------------------------- /Assets/Scenes/U_Playground.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 19cecb06206eed24fbb0018ecb64b789 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5f3983c1b0297d947b2a10bdca7fb605 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Scripts/Nodes&Graphs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3e7b53ad21f2c924c85ee3372d587193 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Scripts/Nodes&Graphs/GraphController.cs: -------------------------------------------------------------------------------- 1 | ///----------------------------------------------------------------- 2 | /// Class: GraphController 3 | /// Description: Manages the data graph and collection of nodes 4 | /// Author: Lee 5 | /// GitHub: https://github.com/ivuecode 6 | ///----------------------------------------------------------------- 7 | using System.Collections.Generic; 8 | using UnityEngine; 9 | 10 | public class GraphController : MonoBehaviour 11 | { 12 | [Header("Component References")] 13 | public GameObject nodeViewPrefab; // Reference to the world-spaceobject 14 | 15 | [Header("Graph Settings")] 16 | public Color startNodeColor; // Color of the start node 17 | public Color endNodeColor; // Color of the end node 18 | public Color blockedNodeColor; // Color of the wall nodes 19 | public Color frontierColor; // Color of the frontier nodes 20 | public Color exploredColor; // Color of the previous explored nodes 21 | public Color pathColor; // Color of the completed path nodes 22 | public Color defaultColor; 23 | 24 | [HideInInspector] public NodeView[,] nodeViews; // 2D array of all the nodes (visual) 25 | [HideInInspector] public Node[,] nodes; // 2D array of all nodes (data) 26 | [HideInInspector] public int graphWidth; // Graph dimensions 27 | [HideInInspector] public int graphHeight; // Graph dimensions 28 | 29 | [Header("Private Variables")] 30 | private int[,] m_gridSize = new int[48, 24]; // Base grid size 31 | private Vector2[] m_allDirections = { new Vector2(0f, 1f), new Vector2(1f, 0f), new Vector2(-1f, 0f), new Vector2(0f, -1f), }; // directions for checking neighbors 32 | 33 | /// 34 | /// (short-hand function) Check (x,y) within the bounds of the Graph? 35 | /// 36 | private bool IsWithinBounds(int x, int y) => (x >= 0 && x < graphWidth && y >= 0 && y < graphHeight); 37 | 38 | /// 39 | /// (short-hand function) Returns a List of neighboring Nodes 40 | /// 41 | private List GetNeighbors(int x, int y) => GetNeighbors(x, y, nodes, m_allDirections); 42 | 43 | 44 | 45 | /// 46 | /// Initialize the Graph (data) 47 | /// 48 | public void Initialize() 49 | { 50 | // set the dimensions based on the array and initialize 51 | graphWidth = m_gridSize.GetLength(0); 52 | graphHeight = m_gridSize.GetLength(1); 53 | nodes = new Node[graphWidth, graphHeight]; 54 | 55 | // at each (x,y) position in the array setup the node 56 | for (int y = 0; y < graphHeight; y++) 57 | { 58 | for (int x = 0; x < graphWidth; x++) 59 | { 60 | NodeType type = (NodeType)m_gridSize[x, y]; 61 | Node newNode = new Node(x, y, type); 62 | nodes[x, y] = newNode; 63 | newNode.position = new Vector3(x, 0, y); 64 | } 65 | } 66 | UpdateAllNeighbours(); 67 | CreateGraph(); 68 | ResetGraph(); 69 | } 70 | 71 | /// 72 | /// Create the graph grid (visual) 73 | /// 74 | private void CreateGraph() 75 | { 76 | // setup array of NodeViews 77 | nodeViews = new NodeView[graphWidth, graphHeight]; 78 | 79 | foreach (Node n in nodes) 80 | { 81 | // create a NodeView for each corresponding Node 82 | GameObject instance = Instantiate(nodeViewPrefab, Vector3.zero, Quaternion.identity); 83 | NodeView nodeView = instance.GetComponent(); 84 | nodeView.Init(n); 85 | 86 | // store each NodeView in the array 87 | nodeViews[n.xIndex, n.yIndex] = nodeView; 88 | } 89 | } 90 | 91 | /// 92 | /// setup the neighbor Nodes for each node in the array 93 | /// 94 | private void UpdateAllNeighbours() 95 | { 96 | for (int y = 0; y < graphHeight; y++) 97 | { 98 | for (int x = 0; x < graphWidth; x++) 99 | { 100 | if (nodes[x, y].nodeType != NodeType.Blocked) 101 | { 102 | nodes[x, y].neighbors = GetNeighbors(x, y); 103 | } 104 | } 105 | } 106 | } 107 | 108 | /// 109 | /// Returns a List of neighboring Nodes from (x,y) coordinate, array of Nodes and compass directions 110 | /// 111 | private List GetNeighbors(int x, int y, Node[,] nodeArray, Vector2[] directions) 112 | { 113 | List neighborNodes = new List(); 114 | 115 | // in each direction vector... 116 | foreach (Vector2 dir in directions) 117 | { 118 | // find the (x,y) offset position 119 | int newX = x + (int)dir.x; 120 | int newY = y + (int)dir.y; 121 | 122 | // if the new position is within the graph and not blocked, add to List 123 | if (IsWithinBounds(newX, newY) && nodeArray[newX, newY] != null && nodeArray[newX, newY].nodeType != NodeType.Blocked) 124 | { 125 | neighborNodes.Add(nodeArray[newX, newY]); 126 | } 127 | } 128 | return neighborNodes; 129 | } 130 | 131 | /// 132 | /// Color a List of NodeViews, given a List of Nodes 133 | /// 134 | public void ColorNodes(List nodes, Color color) 135 | { 136 | foreach (Node n in nodes) 137 | { 138 | NodeView nodeView = nodeViews[n.xIndex, n.yIndex]; 139 | nodeView.SetColorNode(color); 140 | } 141 | } 142 | 143 | /// 144 | /// Gets the approximate distance between nodes 145 | /// 146 | public float GetNodeDistance(Node source, Node target) 147 | { 148 | int dx = Mathf.Abs(source.xIndex - target.xIndex); 149 | int dy = Mathf.Abs(source.yIndex - target.yIndex); 150 | 151 | int min = Mathf.Min(dx, dy); 152 | int max = Mathf.Max(dx, dy); 153 | 154 | int straightSteps = max - min; 155 | 156 | return (1.4f * min + straightSteps); 157 | } 158 | 159 | /// 160 | /// Toggles the nodeType state (blocked / open) 161 | /// 162 | public void ToggleNodeState(int x, int y) 163 | { 164 | if (nodes[x, y].nodeType == NodeType.Open) 165 | { 166 | nodes[x, y].nodeType = NodeType.Blocked; 167 | nodeViews[x, y].SetColorNode(blockedNodeColor); 168 | } 169 | else 170 | { 171 | nodes[x, y].nodeType = NodeType.Open; 172 | nodeViews[x, y].SetColorNode(defaultColor); 173 | } 174 | UpdateAllNeighbours(); 175 | } 176 | 177 | /// 178 | /// Reset the state of the graph 179 | /// 180 | public void ResetGraph() 181 | { 182 | // at each (x,y) position in the array setup the node 183 | for (int y = 0; y < graphHeight; y++) 184 | { 185 | for (int x = 0; x < graphWidth; x++) 186 | { 187 | nodeViews[x, y].SetColorNode(defaultColor); 188 | nodes[x, y].Reset(); 189 | nodes[x, y].nodeType = NodeType.Open; 190 | } 191 | } 192 | UpdateAllNeighbours(); 193 | } 194 | 195 | /// 196 | /// Keep the layout the same (used in the case where we want to changge algos) 197 | /// 198 | public void RerollGraph() 199 | { 200 | for (int y = 0; y < graphHeight; y++) 201 | { 202 | for (int x = 0; x < graphWidth; x++) 203 | { 204 | if (nodeViews[x, y].node.nodeType != NodeType.Blocked) 205 | { 206 | nodeViews[x, y].SetColorNode(defaultColor); 207 | nodeViews[x, y].node.Reset(); 208 | } 209 | } 210 | } 211 | } 212 | } -------------------------------------------------------------------------------- /Assets/Scripts/Nodes&Graphs/GraphController.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 02f0e608ecf063040b886186c223494b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Nodes&Graphs/Node.cs: -------------------------------------------------------------------------------- 1 | ///----------------------------------------------------------------- 2 | /// Class: Node 3 | /// Description: Data class for the Node which implements the IComparable interface 4 | /// Author: Lee 5 | /// GitHub: https://github.com/ivuecode 6 | ///----------------------------------------------------------------- 7 | using System; 8 | using UnityEngine; 9 | using System.Collections.Generic; 10 | 11 | public enum NodeType { Open, Blocked }; 12 | public class Node : IComparable 13 | { 14 | public int xIndex = -1; // x and y index in the graph array 15 | public int yIndex = -1; // x and y index in the graph array 16 | public float priority; // Priority used to set place in queue 17 | public Vector3 position; // (x,y,z) position in 3d space 18 | public Node previous = null; // Referebce to preceding null in the current graph search 19 | public NodeType nodeType = NodeType.Open; 20 | public List neighbors = new List(); // List of neighbor Nodes 21 | public float distanceTraveled = Mathf.Infinity; // Total distance traveled from the start Node 22 | 23 | 24 | 25 | /// 26 | /// Node constructor 27 | /// 28 | public Node(int x, int y, NodeType type) 29 | { 30 | xIndex = x; 31 | yIndex = y; 32 | nodeType = type; 33 | } 34 | 35 | /// 36 | /// Required by IComparable, method to compare this node with another Node based on priority 37 | /// 38 | public int CompareTo(Node other) 39 | { 40 | if (priority < other.priority) return -1; 41 | else if (priority > other.priority) return 1; 42 | else return 0; 43 | } 44 | 45 | /// 46 | /// Reset the state of this node 47 | /// 48 | public void Reset() 49 | { 50 | previous = null; 51 | priority = 0; 52 | distanceTraveled = Mathf.Infinity; 53 | } 54 | } -------------------------------------------------------------------------------- /Assets/Scripts/Nodes&Graphs/Node.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1ff2e70e7f754da4e8f2fbf69e76eb75 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Nodes&Graphs/NodeView.cs: -------------------------------------------------------------------------------- 1 | ///----------------------------------------------------------------- 2 | /// Class: NodeView 3 | /// Description: Visual controller of the node 4 | /// Author: Lee 5 | /// GitHub: https://github.com/ivuecode 6 | ///----------------------------------------------------------------- 7 | using UnityEngine; 8 | 9 | public class NodeView : MonoBehaviour 10 | { 11 | [Header("Component Referneces")] 12 | public GameObject tile; 13 | public MeshRenderer materialRenderer; 14 | public Node node; 15 | 16 | 17 | 18 | /// 19 | /// Initilize the NodeView with the corresponding Node 20 | /// 21 | public void Init(Node _node) 22 | { 23 | // set the name, position and scale of this node 24 | gameObject.name = "Node (" + _node.xIndex + "," + _node.yIndex + ")"; 25 | gameObject.transform.position = _node.position; 26 | tile.transform.localScale = new Vector3(1f - 0.1f, 1f, 1f - 0.1f); 27 | node = _node; 28 | } 29 | 30 | /// 31 | /// Set the color of this node (tile) geometry 32 | /// 33 | public void SetColorNode(Color color) 34 | { 35 | materialRenderer.material.color = color; 36 | } 37 | } -------------------------------------------------------------------------------- /Assets/Scripts/Nodes&Graphs/NodeView.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 70cedc3c83c6416469bbfca58404f2ea 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Nodes&Graphs/Pathfinder.cs: -------------------------------------------------------------------------------- 1 | ///----------------------------------------------------------------- 2 | /// Class: Pathfinder 3 | /// Description: Uses different algorithms to find a goal node 4 | /// Author: Lee 5 | /// GitHub: https://github.com/ivuecode 6 | ///----------------------------------------------------------------- 7 | using System.Collections; 8 | using System.Collections.Generic; 9 | using UnityEngine; 10 | 11 | public enum PathFindingAlgo { Dijkstra, AStar, BreadthFirstSearch, GreedyBestFirst, }; // the various pathfinding algorithms 12 | public class Pathfinder : MonoBehaviour 13 | { 14 | [Header("Component References")] 15 | public GraphController graphController; // Refernece to the graph controller 16 | public UIController uIController; // Reference to the ui controller 17 | 18 | [Header("Private Variables")] 19 | private Node m_startNode; // The start node 20 | private Node m_goalNode; // The goal node 21 | private PriorityQueue m_frontierNodes; // The "open set" of Nodes that are next to be explored 22 | private List m_exploredNodes; // The "closed set" of Nodes that have been explored 23 | private List m_pathNodes; // The List of Nodes that make up our final path from start to goal 24 | 25 | [Header("PathFinding Properties")] 26 | [HideInInspector] public PathFindingAlgo pathAlgo; // Active pathfinding mode/algorithm 27 | [HideInInspector] public float timeStep; // Speed of iterations 28 | [HideInInspector] public bool isComplete; // Is the search complete 29 | [HideInInspector] public int iterations; // Current number of iterations 30 | [HideInInspector] public float time; // Total time it took to complete 31 | 32 | 33 | 34 | /// 35 | /// Initialize the pathfinder 36 | /// 37 | public void Initialize(Node start, Node goal) 38 | { 39 | m_startNode = start; 40 | m_goalNode = goal; 41 | 42 | // our frontier begins with the start Node 43 | m_frontierNodes = new PriorityQueue(); 44 | m_frontierNodes.Enqueue(start); 45 | m_exploredNodes = new List(); 46 | m_pathNodes = new List(); 47 | 48 | // reset all Nodes in the graph 49 | for (int x = 0; x < graphController.graphWidth; x++) 50 | { 51 | for (int y = 0; y < graphController.graphHeight; y++) 52 | { 53 | graphController.nodes[x, y].Reset(); 54 | } 55 | } 56 | 57 | // setup starting values 58 | isComplete = false; 59 | iterations = 0; 60 | m_startNode.distanceTraveled = 0; 61 | StartCoroutine(SearchRoutine()); 62 | } 63 | 64 | /// 65 | /// Updates the nodes on the graph to represent the current status of the algorithm 66 | /// 67 | private void UpdateGraphUI(Node start, Node goal) 68 | { 69 | // color frontier, explored and path Nodes 70 | if (m_frontierNodes != null) graphController.ColorNodes(m_frontierNodes.ToList(), graphController.frontierColor); 71 | if (m_exploredNodes != null) graphController.ColorNodes(m_exploredNodes, graphController.exploredColor); 72 | if (m_pathNodes != null && m_pathNodes.Count > 0) graphController.ColorNodes(m_pathNodes, graphController.pathColor); 73 | 74 | // color start NodeView and goal NodeView directly 75 | NodeView startNodeView = graphController.nodeViews[start.xIndex, start.yIndex]; 76 | startNodeView.SetColorNode(graphController.startNodeColor); 77 | NodeView goalNodeView = graphController.nodeViews[goal.xIndex, goal.yIndex]; 78 | goalNodeView.SetColorNode(graphController.endNodeColor); 79 | } 80 | 81 | /// 82 | /// Primary graph search routine 83 | /// 84 | private IEnumerator SearchRoutine() 85 | { 86 | // wait one frame 87 | float timeStart = Time.realtimeSinceStartup; 88 | yield return null; 89 | 90 | while (!isComplete && m_frontierNodes != null) 91 | { 92 | if (m_frontierNodes.Count > 0) 93 | { 94 | // get the next Node from the priority queue 95 | Node currentNode = m_frontierNodes.Dequeue(); 96 | iterations++; 97 | time = (Time.realtimeSinceStartup - timeStart); 98 | uIController.totalIterations.text = "Total iterations: " + iterations; 99 | uIController.completeTime.text = "Elapsed time: " + time.ToString("F2") + " seconds"; 100 | 101 | // mark this Node as explored 102 | if (!m_exploredNodes.Contains(currentNode)) m_exploredNodes.Add(currentNode); 103 | 104 | // expand the frontier based on our search mode 105 | if (pathAlgo == PathFindingAlgo.BreadthFirstSearch) ExpandFrontierBreadthFirst(currentNode); 106 | else if (pathAlgo == PathFindingAlgo.Dijkstra) ExpandFrontierDijkstra(currentNode); 107 | else if (pathAlgo == PathFindingAlgo.GreedyBestFirst) ExpandFrontierGreedyBestFirst(currentNode); 108 | else ExpandFrontierAStar(currentNode); 109 | 110 | // if the goal node is in the frontier 111 | if (m_frontierNodes.Contains(m_goalNode)) 112 | { 113 | m_pathNodes = GetPathNodes(m_goalNode); 114 | isComplete = true; 115 | uIController.OnPathFinished(); 116 | } 117 | 118 | UpdateGraphUI(m_startNode, m_goalNode); 119 | yield return new WaitForSeconds(timeStep); 120 | } 121 | else 122 | { 123 | isComplete = true; 124 | uIController.OnPathFinished(); 125 | } 126 | } 127 | time = (Time.realtimeSinceStartup - timeStart); 128 | uIController.OnPathFinished(); 129 | } 130 | 131 | /// 132 | /// Expand the frontier nodes using Breadth First Search 133 | /// 134 | private void ExpandFrontierBreadthFirst(Node node) 135 | { 136 | if (node != null) 137 | { 138 | for (int i = 0; i < node.neighbors.Count; i++) 139 | { 140 | // if the current neighbor has not been explored and is not already part of the frontier 141 | if (!m_exploredNodes.Contains(node.neighbors[i]) && !m_frontierNodes.Contains(node.neighbors[i])) 142 | { 143 | float distanceToNeighbor = graphController.GetNodeDistance(node, node.neighbors[i]); 144 | float newDistanceTraveled = distanceToNeighbor + node.distanceTraveled + (int)node.nodeType; 145 | 146 | // create breadcrumb trail to neighbor node and set cumulative distance traveled 147 | node.neighbors[i].distanceTraveled = newDistanceTraveled; 148 | node.neighbors[i].previous = node; 149 | 150 | // add neighbor to explored Nodes, treat queue as if it were a first in-first out queue 151 | node.neighbors[i].priority = m_exploredNodes.Count; 152 | m_frontierNodes.Enqueue(node.neighbors[i]); 153 | } 154 | } 155 | } 156 | } 157 | 158 | /// 159 | /// Expand the frontier nodes using Dijkstra's algorithm 160 | /// 161 | private void ExpandFrontierDijkstra(Node node) 162 | { 163 | if (node != null) 164 | { 165 | for (int i = 0; i < node.neighbors.Count; i++) 166 | { 167 | if (!m_exploredNodes.Contains(node.neighbors[i])) 168 | { 169 | float distanceToNeighbor = graphController.GetNodeDistance(node, node.neighbors[i]); 170 | float newDistanceTraveled = distanceToNeighbor + node.distanceTraveled + (int)node.nodeType; 171 | 172 | // if a shorter path exists to the neighbor via this node, re-route 173 | if (float.IsPositiveInfinity(node.neighbors[i].distanceTraveled) || newDistanceTraveled < node.neighbors[i].distanceTraveled) 174 | { 175 | node.neighbors[i].previous = node; 176 | node.neighbors[i].distanceTraveled = newDistanceTraveled; 177 | } 178 | 179 | // if the current neighbor is not already part of the frontier 180 | if (!m_frontierNodes.Contains(node.neighbors[i])) 181 | { 182 | // set the priority based on distance traveled from start Node and add to frontier 183 | node.neighbors[i].priority = node.neighbors[i].distanceTraveled; 184 | m_frontierNodes.Enqueue(node.neighbors[i]); 185 | } 186 | } 187 | } 188 | } 189 | } 190 | 191 | /// 192 | /// Expand the frontier nodes using Greedy Best-First search 193 | /// 194 | private void ExpandFrontierGreedyBestFirst(Node node) 195 | { 196 | if (node != null) 197 | { 198 | for (int i = 0; i < node.neighbors.Count; i++) 199 | { 200 | if (!m_exploredNodes.Contains(node.neighbors[i]) && !m_frontierNodes.Contains(node.neighbors[i])) 201 | { 202 | float distanceToNeighbor = graphController.GetNodeDistance(node, node.neighbors[i]); 203 | float newDistanceTraveled = distanceToNeighbor + node.distanceTraveled + (int)node.nodeType; 204 | 205 | // create breadcrumb trail to neighbor node and set cumulative distance traveled 206 | node.neighbors[i].distanceTraveled = newDistanceTraveled; 207 | node.neighbors[i].previous = node; 208 | 209 | // set the priority based on estimated distance to goal Node 210 | node.neighbors[i].priority = graphController.GetNodeDistance(node.neighbors[i], m_goalNode); 211 | m_frontierNodes.Enqueue(node.neighbors[i]); 212 | } 213 | } 214 | } 215 | } 216 | 217 | /// 218 | /// Expand the frontier nodes using AStar search 219 | /// 220 | private void ExpandFrontierAStar(Node node) 221 | { 222 | if (node != null) 223 | { 224 | for (int i = 0; i < node.neighbors.Count; i++) 225 | { 226 | if (!m_exploredNodes.Contains(node.neighbors[i])) 227 | { 228 | float distanceToNeighbor = graphController.GetNodeDistance(node, node.neighbors[i]); 229 | float newDistanceTraveled = distanceToNeighbor + node.distanceTraveled + (int)node.nodeType; 230 | 231 | // if a shorter path exists to the neighbor via this node, re-route 232 | if (float.IsPositiveInfinity(node.neighbors[i].distanceTraveled) || newDistanceTraveled < node.neighbors[i].distanceTraveled) 233 | { 234 | node.neighbors[i].previous = node; 235 | node.neighbors[i].distanceTraveled = newDistanceTraveled; 236 | } 237 | 238 | // if the neighbor is not part of the frontier, add this to the priority queue 239 | if (!m_frontierNodes.Contains(node.neighbors[i]) && graphController != null) 240 | { 241 | // base priority, F score, on G score (distance from start) + H score (estimated distance to goal) 242 | float distanceToGoal = graphController.GetNodeDistance(node.neighbors[i], m_goalNode); 243 | node.neighbors[i].priority = node.neighbors[i].distanceTraveled + distanceToGoal; 244 | 245 | // add to priority queue using the F score 246 | m_frontierNodes.Enqueue(node.neighbors[i]); 247 | } 248 | } 249 | } 250 | } 251 | } 252 | 253 | /// 254 | /// Generate a list of path Nodes working backward from an end Node 255 | /// 256 | private List GetPathNodes(Node endNode) 257 | { 258 | List path = new List(); 259 | if (endNode == null) return path; 260 | 261 | // follow the breadcrumb trail backward until we hit a node that has no previous node (usually the start Node) 262 | path.Add(endNode); 263 | Node currentNode = endNode.previous; 264 | 265 | while (currentNode != null) 266 | { 267 | // insert the previous node at the first position in the path 268 | path.Insert(0, currentNode); 269 | currentNode = currentNode.previous; 270 | } 271 | return path; 272 | } 273 | } -------------------------------------------------------------------------------- /Assets/Scripts/Nodes&Graphs/Pathfinder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b4a4d2476e0ec3b4294e9297c5cab785 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Nodes&Graphs/PriorityQueue.cs: -------------------------------------------------------------------------------- 1 | ///----------------------------------------------------------------- 2 | /// Class: PriorityQueue 3 | /// Description: Priority queue implemented using generic list with a binary heap 4 | /// Author: Lee 5 | /// GitHub: https://github.com/ivuecode 6 | /// Notes: Implementation: https://visualstudiomagazine.com/articles/2012/11/01/priority-queues-with-c.aspx 7 | ///----------------------------------------------------------------- 8 | using System; 9 | using System.Collections.Generic; 10 | 11 | public class PriorityQueue where T : IComparable 12 | { 13 | // List of items in our queue 14 | private List m_data; 15 | 16 | /// 17 | /// Number of items currently in queue 18 | /// 19 | public int Count => m_data.Count; 20 | 21 | /// 22 | /// Check if the item contained in the data List? 23 | /// 24 | public bool Contains(T item) => m_data.Contains(item); 25 | 26 | /// 27 | /// Return the data as a generic List 28 | /// 29 | public List ToList() => m_data; 30 | 31 | /// 32 | /// Constructor 33 | /// 34 | public PriorityQueue() => m_data = new List(); 35 | 36 | /// 37 | /// Look at the first item without dequeuing 38 | /// 39 | public T Peek() 40 | { 41 | T frontItem = m_data[0]; 42 | return frontItem; 43 | } 44 | 45 | /// 46 | /// Add an item to the queue and sort using a min binary heap 47 | /// 48 | public void Enqueue(T item) 49 | { 50 | m_data.Add(item); 51 | int childindex = m_data.Count - 1; 52 | 53 | // sort using a min binary heap 54 | while (childindex > 0) 55 | { 56 | // find the parent position in the heap 57 | int parentindex = (childindex - 1) / 2; 58 | 59 | // if parent and child are already sorted, stop sorting 60 | if (m_data[childindex].CompareTo(m_data[parentindex]) >= 0) break; 61 | 62 | T tmp = m_data[childindex]; 63 | m_data[childindex] = m_data[parentindex]; 64 | m_data[parentindex] = tmp; 65 | 66 | // move up one level in the heap and repeat until sorted 67 | childindex = parentindex; 68 | } 69 | } 70 | 71 | /// 72 | /// Remove an item from queue and keep it sorted using a min binary heap 73 | /// 74 | public T Dequeue() 75 | { 76 | int lastindex = m_data.Count - 1; 77 | T frontItem = m_data[0]; 78 | m_data[0] = m_data[lastindex]; 79 | m_data.RemoveAt(lastindex); 80 | lastindex--; 81 | int parentindex = 0; 82 | 83 | // sort using binary heap 84 | while (true) 85 | { 86 | // left child 87 | int childindex = parentindex * 2 + 1; 88 | 89 | // if there is no left child, stop sorting 90 | if (childindex > lastindex) break; 91 | 92 | // right child 93 | int rightchild = childindex + 1; 94 | 95 | // if the value of the right child is less than the left child, switch to the right branch of the heap 96 | if (rightchild <= lastindex && m_data[rightchild].CompareTo(m_data[childindex]) < 0) childindex = rightchild; 97 | 98 | // if the parent and child are already sorted, then stop sorting 99 | if (m_data[parentindex].CompareTo(m_data[childindex]) <= 0) break; 100 | 101 | // if not, then swap the parent and child 102 | T tmp = m_data[parentindex]; 103 | m_data[parentindex] = m_data[childindex]; 104 | m_data[childindex] = tmp; 105 | 106 | // move down the heap onto the child's level and repeat until sorted 107 | parentindex = childindex; 108 | } 109 | return frontItem; 110 | } 111 | } -------------------------------------------------------------------------------- /Assets/Scripts/Nodes&Graphs/PriorityQueue.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 018c6cf83feef3c419f4303365ed4bb2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/UI.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f29b03621c5e50e43b9776e94ce8fd90 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Scripts/UI/RaycastController.cs: -------------------------------------------------------------------------------- 1 | ///----------------------------------------------------------------- 2 | /// Class: RaycastController 3 | /// Description: Raycast from the camera to mouse position to interact 4 | /// Author: Lee 5 | /// GitHub: https://github.com/ivuecode 6 | ///----------------------------------------------------------------- 7 | using UnityEngine; 8 | 9 | public class RaycastController : MonoBehaviour 10 | { 11 | [Header("Component References")] 12 | public Camera sceneCamera; // Reference to the main camera 13 | public UIController uIController; // Refernece to the UIController 14 | 15 | [Header("Private Variables")] 16 | private NodeView m_focusedNode; // Node we just click 17 | private NodeView m_currentNode; // Node under the mouse 18 | 19 | 20 | 21 | /// 22 | /// Update is called each frame 23 | /// 24 | void Update() 25 | { 26 | RaycastHit hit; 27 | Ray ray = sceneCamera.ScreenPointToRay(Input.mousePosition); 28 | 29 | if (Physics.Raycast(ray, out hit)) 30 | { 31 | m_currentNode = hit.transform.GetComponent(); 32 | 33 | if (Input.GetMouseButton(0)) 34 | { 35 | if (m_focusedNode == null) 36 | { 37 | m_focusedNode = m_currentNode; 38 | uIController.OnInteract(m_focusedNode.node.xIndex, m_focusedNode.node.yIndex); 39 | } 40 | 41 | if (m_focusedNode != m_currentNode) 42 | { 43 | uIController.OnInteract(m_currentNode.node.xIndex, m_currentNode.node.yIndex); 44 | m_focusedNode = m_currentNode; 45 | } 46 | } 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /Assets/Scripts/UI/RaycastController.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2fbe4e6b4f0420a45b8d9b39c7cc6c67 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/UI/UIController.cs: -------------------------------------------------------------------------------- 1 | ///----------------------------------------------------------------- 2 | /// Class: UIController 3 | /// Description: Handles creating and starting the graph and pathfinder 4 | /// Author: Lee 5 | /// GitHub: https://github.com/ivuecode 6 | ///----------------------------------------------------------------- 7 | using UnityEngine; 8 | using UnityEngine.UI; 9 | 10 | public class UIController : MonoBehaviour 11 | { 12 | [Header("Component References")] 13 | public GraphController graph; // Reference to the graph component 14 | public Pathfinder pathfinder; // Referrence to the path finder 15 | public Slider timeStepSlider; // Reference to the UI slider for setting time steps 16 | public Text timeStepValue; // Reference to the time step value 17 | public Text completeTime; // Refernece to the text for completion time 18 | public Text totalIterations; // Reference to the total iterations 19 | public Dropdown algorithmDropdown; // Reference to the dropdown 20 | public Button resetButton; // Refernece to the resetButton 21 | public Button startButton; // Reference to the startButton 22 | 23 | [Header("Private Variables")] 24 | private int m_startNodeX; // X coordinate of start Node 25 | private int m_startNodeY; // Y coordinate of start Node 26 | private int m_endNodeX; // X coordinate of end Node 27 | private int m_endNodeY; // Y coordinate of end Node 28 | private float m_timeStep; // Delay between iterations 29 | private int m_UIState; // Internal tracking of the ui build state 30 | private bool hasStarted; // Has this simulation started 31 | 32 | 33 | 34 | /// 35 | /// Initialize the graph 36 | /// 37 | private void Start() 38 | { 39 | graph.Initialize(); 40 | OnSetTimestep(); 41 | } 42 | 43 | /// 44 | /// Initialize the Pathfinder and begin the search 45 | /// 46 | public void OnStartSimulation() 47 | { 48 | graph.RerollGraph(); 49 | Node startNode = graph.nodes[m_startNodeX, m_startNodeY]; 50 | Node goalNode = graph.nodes[m_endNodeX, m_endNodeY]; 51 | 52 | pathfinder.Initialize(startNode, goalNode); 53 | hasStarted = true; 54 | resetButton.interactable = false; 55 | startButton.interactable = false; 56 | } 57 | 58 | /// 59 | /// Sets the timesetp value from the UISlider 60 | /// 61 | public void OnSetTimestep() 62 | { 63 | m_timeStep = timeStepSlider.value / 10; 64 | timeStepValue.text = "Iterations per second: " + m_timeStep.ToString("F2"); 65 | pathfinder.timeStep = m_timeStep; 66 | } 67 | 68 | /// 69 | /// Sets the pathfinder algorithm 70 | /// 71 | public void OnSetAlgorithm() 72 | { 73 | string algo = algorithmDropdown.options[algorithmDropdown.value].text; 74 | switch (algo) 75 | { 76 | case "Dijkstra": 77 | { 78 | pathfinder.pathAlgo = PathFindingAlgo.Dijkstra; 79 | break; 80 | } 81 | case "AStar": 82 | { 83 | pathfinder.pathAlgo = PathFindingAlgo.AStar; 84 | break; 85 | } 86 | case "Breadth First": 87 | { 88 | pathfinder.pathAlgo = PathFindingAlgo.BreadthFirstSearch; 89 | break; 90 | } 91 | case "Greedy Best First": 92 | { 93 | pathfinder.pathAlgo = PathFindingAlgo.GreedyBestFirst; 94 | break; 95 | } 96 | } 97 | } 98 | 99 | /// 100 | /// Resets the board 101 | /// 102 | public void OnResetBoard() 103 | { 104 | startButton.interactable = false; 105 | pathfinder.isComplete = false; 106 | hasStarted = false; 107 | m_UIState = 0; 108 | graph.ResetGraph(); 109 | } 110 | 111 | /// 112 | /// Called from the pathfinder when a path is complete 113 | /// 114 | public void OnPathFinished() 115 | { 116 | resetButton.interactable = true; 117 | startButton.interactable = true; 118 | } 119 | 120 | /// 121 | /// Called when we interact with a node based on the state of the UI 122 | /// 123 | public void OnInteract(int xIndex, int yIndex) 124 | { 125 | if (hasStarted) return; 126 | switch (m_UIState) 127 | { 128 | case 0: 129 | { 130 | graph.nodeViews[xIndex, yIndex].SetColorNode(graph.startNodeColor); 131 | m_startNodeX = xIndex; 132 | m_startNodeY = yIndex; 133 | break; 134 | } 135 | case 1: 136 | { 137 | graph.nodeViews[xIndex, yIndex].SetColorNode(graph.endNodeColor); 138 | m_endNodeX = xIndex; 139 | m_endNodeY = yIndex; 140 | startButton.interactable = true; 141 | break; 142 | } 143 | case 2: 144 | { 145 | graph.ToggleNodeState(xIndex, yIndex); 146 | break; 147 | } 148 | } 149 | m_UIState++; 150 | if (m_UIState >= 2) m_UIState = 2; 151 | } 152 | } -------------------------------------------------------------------------------- /Assets/Scripts/UI/UIController.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3244c30971775624a956a2b4b20f592d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Vue Code 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Packages/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "com.unity.collab-proxy": "1.3.9", 4 | "com.unity.ide.rider": "1.2.1", 5 | "com.unity.ide.visualstudio": "2.0.5", 6 | "com.unity.ide.vscode": "1.2.3", 7 | "com.unity.test-framework": "1.1.19", 8 | "com.unity.textmeshpro": "3.0.1", 9 | "com.unity.timeline": "1.3.6", 10 | "com.unity.ugui": "1.0.0", 11 | "com.unity.modules.ai": "1.0.0", 12 | "com.unity.modules.androidjni": "1.0.0", 13 | "com.unity.modules.animation": "1.0.0", 14 | "com.unity.modules.assetbundle": "1.0.0", 15 | "com.unity.modules.audio": "1.0.0", 16 | "com.unity.modules.cloth": "1.0.0", 17 | "com.unity.modules.director": "1.0.0", 18 | "com.unity.modules.imageconversion": "1.0.0", 19 | "com.unity.modules.imgui": "1.0.0", 20 | "com.unity.modules.jsonserialize": "1.0.0", 21 | "com.unity.modules.particlesystem": "1.0.0", 22 | "com.unity.modules.physics": "1.0.0", 23 | "com.unity.modules.physics2d": "1.0.0", 24 | "com.unity.modules.screencapture": "1.0.0", 25 | "com.unity.modules.terrain": "1.0.0", 26 | "com.unity.modules.terrainphysics": "1.0.0", 27 | "com.unity.modules.tilemap": "1.0.0", 28 | "com.unity.modules.ui": "1.0.0", 29 | "com.unity.modules.uielements": "1.0.0", 30 | "com.unity.modules.umbra": "1.0.0", 31 | "com.unity.modules.unityanalytics": "1.0.0", 32 | "com.unity.modules.unitywebrequest": "1.0.0", 33 | "com.unity.modules.unitywebrequestassetbundle": "1.0.0", 34 | "com.unity.modules.unitywebrequestaudio": "1.0.0", 35 | "com.unity.modules.unitywebrequesttexture": "1.0.0", 36 | "com.unity.modules.unitywebrequestwww": "1.0.0", 37 | "com.unity.modules.vehicles": "1.0.0", 38 | "com.unity.modules.video": "1.0.0", 39 | "com.unity.modules.vr": "1.0.0", 40 | "com.unity.modules.wind": "1.0.0", 41 | "com.unity.modules.xr": "1.0.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Packages/packages-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "com.unity.collab-proxy": { 4 | "version": "1.3.9", 5 | "depth": 0, 6 | "source": "registry", 7 | "dependencies": {}, 8 | "url": "https://packages.unity.com" 9 | }, 10 | "com.unity.ext.nunit": { 11 | "version": "1.0.5", 12 | "depth": 1, 13 | "source": "registry", 14 | "dependencies": {}, 15 | "url": "https://packages.unity.com" 16 | }, 17 | "com.unity.ide.rider": { 18 | "version": "1.2.1", 19 | "depth": 0, 20 | "source": "registry", 21 | "dependencies": { 22 | "com.unity.test-framework": "1.1.1" 23 | }, 24 | "url": "https://packages.unity.com" 25 | }, 26 | "com.unity.ide.visualstudio": { 27 | "version": "2.0.5", 28 | "depth": 0, 29 | "source": "registry", 30 | "dependencies": {}, 31 | "url": "https://packages.unity.com" 32 | }, 33 | "com.unity.ide.vscode": { 34 | "version": "1.2.3", 35 | "depth": 0, 36 | "source": "registry", 37 | "dependencies": {}, 38 | "url": "https://packages.unity.com" 39 | }, 40 | "com.unity.test-framework": { 41 | "version": "1.1.19", 42 | "depth": 0, 43 | "source": "registry", 44 | "dependencies": { 45 | "com.unity.ext.nunit": "1.0.5", 46 | "com.unity.modules.imgui": "1.0.0", 47 | "com.unity.modules.jsonserialize": "1.0.0" 48 | }, 49 | "url": "https://packages.unity.com" 50 | }, 51 | "com.unity.textmeshpro": { 52 | "version": "3.0.1", 53 | "depth": 0, 54 | "source": "registry", 55 | "dependencies": { 56 | "com.unity.ugui": "1.0.0" 57 | }, 58 | "url": "https://packages.unity.com" 59 | }, 60 | "com.unity.timeline": { 61 | "version": "1.3.6", 62 | "depth": 0, 63 | "source": "registry", 64 | "dependencies": {}, 65 | "url": "https://packages.unity.com" 66 | }, 67 | "com.unity.ugui": { 68 | "version": "1.0.0", 69 | "depth": 0, 70 | "source": "builtin", 71 | "dependencies": { 72 | "com.unity.modules.ui": "1.0.0", 73 | "com.unity.modules.imgui": "1.0.0" 74 | } 75 | }, 76 | "com.unity.modules.ai": { 77 | "version": "1.0.0", 78 | "depth": 0, 79 | "source": "builtin", 80 | "dependencies": {} 81 | }, 82 | "com.unity.modules.androidjni": { 83 | "version": "1.0.0", 84 | "depth": 0, 85 | "source": "builtin", 86 | "dependencies": {} 87 | }, 88 | "com.unity.modules.animation": { 89 | "version": "1.0.0", 90 | "depth": 0, 91 | "source": "builtin", 92 | "dependencies": {} 93 | }, 94 | "com.unity.modules.assetbundle": { 95 | "version": "1.0.0", 96 | "depth": 0, 97 | "source": "builtin", 98 | "dependencies": {} 99 | }, 100 | "com.unity.modules.audio": { 101 | "version": "1.0.0", 102 | "depth": 0, 103 | "source": "builtin", 104 | "dependencies": {} 105 | }, 106 | "com.unity.modules.cloth": { 107 | "version": "1.0.0", 108 | "depth": 0, 109 | "source": "builtin", 110 | "dependencies": { 111 | "com.unity.modules.physics": "1.0.0" 112 | } 113 | }, 114 | "com.unity.modules.director": { 115 | "version": "1.0.0", 116 | "depth": 0, 117 | "source": "builtin", 118 | "dependencies": { 119 | "com.unity.modules.audio": "1.0.0", 120 | "com.unity.modules.animation": "1.0.0" 121 | } 122 | }, 123 | "com.unity.modules.imageconversion": { 124 | "version": "1.0.0", 125 | "depth": 0, 126 | "source": "builtin", 127 | "dependencies": {} 128 | }, 129 | "com.unity.modules.imgui": { 130 | "version": "1.0.0", 131 | "depth": 0, 132 | "source": "builtin", 133 | "dependencies": {} 134 | }, 135 | "com.unity.modules.jsonserialize": { 136 | "version": "1.0.0", 137 | "depth": 0, 138 | "source": "builtin", 139 | "dependencies": {} 140 | }, 141 | "com.unity.modules.particlesystem": { 142 | "version": "1.0.0", 143 | "depth": 0, 144 | "source": "builtin", 145 | "dependencies": {} 146 | }, 147 | "com.unity.modules.physics": { 148 | "version": "1.0.0", 149 | "depth": 0, 150 | "source": "builtin", 151 | "dependencies": {} 152 | }, 153 | "com.unity.modules.physics2d": { 154 | "version": "1.0.0", 155 | "depth": 0, 156 | "source": "builtin", 157 | "dependencies": {} 158 | }, 159 | "com.unity.modules.screencapture": { 160 | "version": "1.0.0", 161 | "depth": 0, 162 | "source": "builtin", 163 | "dependencies": { 164 | "com.unity.modules.imageconversion": "1.0.0" 165 | } 166 | }, 167 | "com.unity.modules.subsystems": { 168 | "version": "1.0.0", 169 | "depth": 1, 170 | "source": "builtin", 171 | "dependencies": { 172 | "com.unity.modules.jsonserialize": "1.0.0" 173 | } 174 | }, 175 | "com.unity.modules.terrain": { 176 | "version": "1.0.0", 177 | "depth": 0, 178 | "source": "builtin", 179 | "dependencies": {} 180 | }, 181 | "com.unity.modules.terrainphysics": { 182 | "version": "1.0.0", 183 | "depth": 0, 184 | "source": "builtin", 185 | "dependencies": { 186 | "com.unity.modules.physics": "1.0.0", 187 | "com.unity.modules.terrain": "1.0.0" 188 | } 189 | }, 190 | "com.unity.modules.tilemap": { 191 | "version": "1.0.0", 192 | "depth": 0, 193 | "source": "builtin", 194 | "dependencies": { 195 | "com.unity.modules.physics2d": "1.0.0" 196 | } 197 | }, 198 | "com.unity.modules.ui": { 199 | "version": "1.0.0", 200 | "depth": 0, 201 | "source": "builtin", 202 | "dependencies": {} 203 | }, 204 | "com.unity.modules.uielements": { 205 | "version": "1.0.0", 206 | "depth": 0, 207 | "source": "builtin", 208 | "dependencies": { 209 | "com.unity.modules.ui": "1.0.0", 210 | "com.unity.modules.imgui": "1.0.0", 211 | "com.unity.modules.jsonserialize": "1.0.0", 212 | "com.unity.modules.uielementsnative": "1.0.0" 213 | } 214 | }, 215 | "com.unity.modules.uielementsnative": { 216 | "version": "1.0.0", 217 | "depth": 1, 218 | "source": "builtin", 219 | "dependencies": { 220 | "com.unity.modules.ui": "1.0.0", 221 | "com.unity.modules.imgui": "1.0.0", 222 | "com.unity.modules.jsonserialize": "1.0.0" 223 | } 224 | }, 225 | "com.unity.modules.umbra": { 226 | "version": "1.0.0", 227 | "depth": 0, 228 | "source": "builtin", 229 | "dependencies": {} 230 | }, 231 | "com.unity.modules.unityanalytics": { 232 | "version": "1.0.0", 233 | "depth": 0, 234 | "source": "builtin", 235 | "dependencies": { 236 | "com.unity.modules.unitywebrequest": "1.0.0", 237 | "com.unity.modules.jsonserialize": "1.0.0" 238 | } 239 | }, 240 | "com.unity.modules.unitywebrequest": { 241 | "version": "1.0.0", 242 | "depth": 0, 243 | "source": "builtin", 244 | "dependencies": {} 245 | }, 246 | "com.unity.modules.unitywebrequestassetbundle": { 247 | "version": "1.0.0", 248 | "depth": 0, 249 | "source": "builtin", 250 | "dependencies": { 251 | "com.unity.modules.assetbundle": "1.0.0", 252 | "com.unity.modules.unitywebrequest": "1.0.0" 253 | } 254 | }, 255 | "com.unity.modules.unitywebrequestaudio": { 256 | "version": "1.0.0", 257 | "depth": 0, 258 | "source": "builtin", 259 | "dependencies": { 260 | "com.unity.modules.unitywebrequest": "1.0.0", 261 | "com.unity.modules.audio": "1.0.0" 262 | } 263 | }, 264 | "com.unity.modules.unitywebrequesttexture": { 265 | "version": "1.0.0", 266 | "depth": 0, 267 | "source": "builtin", 268 | "dependencies": { 269 | "com.unity.modules.unitywebrequest": "1.0.0", 270 | "com.unity.modules.imageconversion": "1.0.0" 271 | } 272 | }, 273 | "com.unity.modules.unitywebrequestwww": { 274 | "version": "1.0.0", 275 | "depth": 0, 276 | "source": "builtin", 277 | "dependencies": { 278 | "com.unity.modules.unitywebrequest": "1.0.0", 279 | "com.unity.modules.unitywebrequestassetbundle": "1.0.0", 280 | "com.unity.modules.unitywebrequestaudio": "1.0.0", 281 | "com.unity.modules.audio": "1.0.0", 282 | "com.unity.modules.assetbundle": "1.0.0", 283 | "com.unity.modules.imageconversion": "1.0.0" 284 | } 285 | }, 286 | "com.unity.modules.vehicles": { 287 | "version": "1.0.0", 288 | "depth": 0, 289 | "source": "builtin", 290 | "dependencies": { 291 | "com.unity.modules.physics": "1.0.0" 292 | } 293 | }, 294 | "com.unity.modules.video": { 295 | "version": "1.0.0", 296 | "depth": 0, 297 | "source": "builtin", 298 | "dependencies": { 299 | "com.unity.modules.audio": "1.0.0", 300 | "com.unity.modules.ui": "1.0.0", 301 | "com.unity.modules.unitywebrequest": "1.0.0" 302 | } 303 | }, 304 | "com.unity.modules.vr": { 305 | "version": "1.0.0", 306 | "depth": 0, 307 | "source": "builtin", 308 | "dependencies": { 309 | "com.unity.modules.jsonserialize": "1.0.0", 310 | "com.unity.modules.physics": "1.0.0", 311 | "com.unity.modules.xr": "1.0.0" 312 | } 313 | }, 314 | "com.unity.modules.wind": { 315 | "version": "1.0.0", 316 | "depth": 0, 317 | "source": "builtin", 318 | "dependencies": {} 319 | }, 320 | "com.unity.modules.xr": { 321 | "version": "1.0.0", 322 | "depth": 0, 323 | "source": "builtin", 324 | "dependencies": { 325 | "com.unity.modules.physics": "1.0.0", 326 | "com.unity.modules.jsonserialize": "1.0.0", 327 | "com.unity.modules.subsystems": "1.0.0" 328 | } 329 | } 330 | } 331 | } 332 | -------------------------------------------------------------------------------- /ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/ProjectSettings/AudioManager.asset -------------------------------------------------------------------------------- /ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/ProjectSettings/ClusterInputManager.asset -------------------------------------------------------------------------------- /ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/ProjectSettings/DynamicsManager.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/ProjectSettings/EditorBuildSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/ProjectSettings/EditorSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/ProjectSettings/GraphicsSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/ProjectSettings/InputManager.asset -------------------------------------------------------------------------------- /ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/ProjectSettings/NavMeshAreas.asset -------------------------------------------------------------------------------- /ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/ProjectSettings/NetworkManager.asset -------------------------------------------------------------------------------- /ProjectSettings/PackageManagerSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &1 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 61 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} 13 | m_Name: 14 | m_EditorClassIdentifier: 15 | m_EnablePreviewPackages: 0 16 | m_EnablePackageDependencies: 0 17 | m_AdvancedSettingsExpanded: 1 18 | m_ScopedRegistriesSettingsExpanded: 1 19 | oneTimeWarningShown: 0 20 | m_Registries: 21 | - m_Id: main 22 | m_Name: 23 | m_Url: https://packages.unity.com 24 | m_Scopes: [] 25 | m_IsDefault: 1 26 | m_Capabilities: 7 27 | m_UserSelectedRegistryName: 28 | m_UserAddingNewScopedRegistry: 0 29 | m_RegistryInfoDraft: 30 | m_ErrorMessage: 31 | m_Original: 32 | m_Id: 33 | m_Name: 34 | m_Url: 35 | m_Scopes: [] 36 | m_IsDefault: 0 37 | m_Capabilities: 0 38 | m_Modified: 0 39 | m_Name: 40 | m_Url: 41 | m_Scopes: 42 | - 43 | m_SelectedScopeIndex: 0 44 | -------------------------------------------------------------------------------- /ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/ProjectSettings/Physics2DSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/PresetManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/ProjectSettings/PresetManager.asset -------------------------------------------------------------------------------- /ProjectSettings/ProjectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/ProjectSettings/ProjectSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 2020.1.17f1 2 | m_EditorVersionWithRevision: 2020.1.17f1 (9957aee8edc2) 3 | -------------------------------------------------------------------------------- /ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/ProjectSettings/QualitySettings.asset -------------------------------------------------------------------------------- /ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/ProjectSettings/TagManager.asset -------------------------------------------------------------------------------- /ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/ProjectSettings/TimeManager.asset -------------------------------------------------------------------------------- /ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/ProjectSettings/UnityConnectSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/VFXManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/ProjectSettings/VFXManager.asset -------------------------------------------------------------------------------- /ProjectSettings/VersionControlSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivuecode/Unity-Pathfinding/999be056609d023123bd8f24c2c7cff70b20540e/ProjectSettings/VersionControlSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/XRSettings.asset: -------------------------------------------------------------------------------- 1 | { 2 | "m_SettingKeys": [ 3 | "VR Device Disabled", 4 | "VR Device User Alert" 5 | ], 6 | "m_SettingValues": [ 7 | "False", 8 | "False" 9 | ] 10 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Path Finding Algorithms :runner: 2 | Pathfinding algorithms implemented in Unity. 3 | 4 | This project implments Dijkstra, AStar, BreadthFirstSearch and GreedyBestFirst on a tiled grid. Set the start position, goal and create walls to visualise the step-by-step process of the algorithm. You can also change the iteration speed as well as color pallet. 5 | 6 | ## Preview :eyes: 7 | ![gif demo](https://i.imgur.com/MI87H0s.gif) 8 | ![gif demo](https://i.imgur.com/3McGD2s.gif) 9 | 10 | ## Getting Started :page_with_curl: 11 | Clone or download this repository and open the project with your favourite flavour of Unity. 12 | _This project was built with Unity 2020.1.17f1_ 13 | --------------------------------------------------------------------------------