Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using UnityEngine;
- using System.Collections;
- using System.Collections.Generic;
- public class Grid : MonoBehaviour {
- public Transform prefab;
- public int sx = 0;
- public int sz = 0;
- void Start () {
- arr = new Node[sx,sz];
- SetUpDirections();
- SetUpGrid(sx,sz);
- BeginCalculation(new V2(0, 0));
- Display();
- }
- /// <summary>
- /// Query for Mouse events.
- /// When event is found, trace to the node clicked
- /// and begin Dijkstra's algorithm from that node.
- /// </summary>
- public void Update()
- {
- //On button press.
- if(Input.GetMouseButtonDown(0))
- {
- //Raycast a ray through the camera.
- Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
- RaycastHit hitInfo;
- if(Physics.Raycast(ray, out hitInfo, 100, 1<<8))
- {
- //If it hits, search through all the nodes until we find which node it is.
- // This is a somewhat inefficient method, but we aren't assigning any special code to each
- // GameObject node, so this works fine.
- Node n = null;
- foreach(Node arrN in arr)
- {
- if(arrN.cell == hitInfo.transform)
- {
- n = arrN;
- break;
- }
- }
- if(n == null){return;}
- //Once we figure out which node, we'll begin the calculation from that node.
- BeginCalculation(n.v2);
- }
- }
- }
- /// <summary>
- /// Sets up Vector2 directions.
- /// </summary>
- void SetUpDirections()
- {
- directions.Add(new V2(-1, 0));
- directions.Add(new V2( 0, -1));
- directions.Add(new V2( 0, 1));
- directions.Add(new V2( 1, 0));
- }
- public Node[,] arr;
- /// <summary>
- /// Sets up grid.
- /// </summary>
- /// <param name='sx'>
- /// Max size of X-Dimension (Width).
- /// </param>
- /// <param name='sz'>
- /// Max size of Z-dimension (Length).
- /// </param>
- void SetUpGrid(int sx, int sz)
- {
- //Double For Loop
- for(int ix = 0; ix < sx; ix++)
- {
- for(int iz = 0; iz < sz; iz++)
- {
- //Instantiate a new prefab.
- Transform t;
- t = (Instantiate(prefab, new Vector3(ix, 0, iz)-new Vector3(sx,0,sz)/2f, Quaternion.identity) as Transform);
- //Rename it.
- t.name = ix+" "+iz;
- //Add node info that links to the newly created gameObject.
- Node newNode = new Node();
- newNode.v2 = new V2(ix,iz);
- newNode.distance = int.MaxValue;
- newNode.cell = t;
- newNode.cell.transform.parent = transform;
- arr[ix,iz] = newNode;
- StartCoroutine(UpdateCell(newNode));
- //Assign a weight to the node and make it visually move up correspondingly.
- newNode.weight = Random.Range(0, 10);
- newNode.cell.Translate(Vector3.up*newNode.weight/50f);
- }
- }
- }
- public bool finished = true;
- /// <summary>
- /// Sets up information so Dijkstra's can begin.
- /// </summary>
- /// <param name='v2'>
- /// A Vector2. The place to begin Dijkstra's from.
- /// </param>
- public void BeginCalculation(V2 v2)
- {
- //This check ensures that we don't allow the algorithm
- // to be running more than once at the same time.
- if(!finished){return;}
- finished = false;
- //Reset all the values in the array.
- // Their distances all are at the max value, so any value
- // Dijkstra's finds will replace the current info.
- foreach(Node n in arr)
- {
- n.distance = int.MaxValue;
- UpdateCell(n);
- }
- //Don't worry about this line of code.
- // If we don't include it, the initial node won't be updated.
- queue.Enqueue(arr[v2.x, v2.z]);
- //Begin Dijkstra's call.
- StartCoroutine(Calculate(v2, 0));
- }
- public Queue<Node> queue = new Queue<Node>();
- /// <summary>
- /// The entire Dijkstra's algorithm is here.
- /// Note that this is MY implementation, and it's quite different
- /// than what you might see elsewhere.
- /// I staggered a lot of the code so that you can visually see
- /// the graph grow and expand as new values are found.
- /// </summary>
- /// <param name='v2'>
- /// The Vector2 coordinate of the node we're looking at.
- /// </param>
- /// <param name='d'>
- /// The distance to the Parent node.
- /// </param>
- public IEnumerator Calculate(V2 v2, int d)
- {
- //We're using a Queue based system.
- Queue<Node> newQueue = new Queue<Node>();
- //The initial point has distance of 0 from itself, by definition.
- arr[v2.x,v2.z].distance = 0;
- //Update the cell so that it shows that it has 0 distance.
- UpdateCell(arr[v2.x,v2.z]);
- //We enqueue the initial point.
- newQueue.Enqueue(arr[v2.x,v2.z]);
- //Here's the loop.
- //Hard to understand but bear with me.
- //This first loop checks if the queue is empty.
- // If it is not empty, then it is populated with nodes to look at.
- // At the very start, it is populated with only our initial node.
- // We later dequeue that initial node after looking at it,
- // and enqueue the neighbors around the initial node that we should
- // be looking at in the next iteration.
- while(newQueue.Count != 0)
- {
- //Now here's the second loop.
- //Given the above, we KNOW there are nodes in here to look at.
- //These nodes neighbor nodes that we just opened last iteration.
- //So, we opened the initial node at the start, and we add
- // all of its neighbors into this newQueue.
- //We now check everything in newQueue, one by one.
- //But before we do that, we're going to put everything in newQueue
- // (nodes we that neighbor nodes we had in the last iteration)
- // into queue, which is filled with nodes that we're going to examine,
- // and update if possible.
- do
- {
- //Dequeue the first node from the newQueue.
- Node n = newQueue.Dequeue();
- //Print out the name so we can see it in Editor.
- Debug.Log(n.cell.name+" : ");
- //For every node adjacent to the node we're looking at.
- foreach(V2 adj in getAdjacents(n.v2))
- {
- //There are up to 4 adj nodes.
- // We're going to call them [adj], but I'll refer to them as "THAT node".
- // And the original one as "THIS node".
- //If THAT node's [distance] variable is greater than
- // THIS node's [distance] + THAT node's [weight]
- // *Note that weight is the cost it takes to travel TO that space,
- // from a space adjacent. This weight is usually 1, but we set it
- // randomly here*
- // Then, we update THAT node's [distance] with THIS's [distance] + THAT's [weight].
- // Basically, we found a more efficient path to get here, so we update the path.
- if(arr[adj.x,adj.z].distance > n.distance+arr[adj.x,adj.z].weight)
- {
- //Here's the path update.
- arr[adj.x,adj.z].distance = n.distance+arr[adj.x,adj.z].weight;
- //Since it qualifies, we add this adj node back into the queue.
- // It won't be looked at until we finish the big do{}while loop.
- // So it's basically adding in info for the NEXT round.
- queue.Enqueue(arr[adj.x,adj.z]);
- }
- }
- //Continue to do this until the newQueue has no nodes in it.
- }while(newQueue.Count != 0);
- //Now, did we add any of the adj's from the newQueue to the queue?
- // (We put it into queue when we found a more efficient path to it)
- // If we didn't, then we exit.
- // If we did, then we dequeue each item from queue, and ..
- // 1. Update its visual.
- // 2. Put it into newQueue to use when we loop again.
- while(queue.Count != 0)
- {
- Node n = queue.Dequeue();
- StartCoroutine(UpdateCell(n));
- newQueue.Enqueue(n);
- }
- yield return null;
- }
- finished = true;
- }
- public IEnumerator UpdateCell(Node n)
- {
- //Updates the cell/node's text to show the [distance] variable.
- string s = n.distance+"";
- if(n.distance/100f >= 1)
- s = "";
- n.cell.GetComponentInChildren<TextMesh>().text = s;
- n.cell.renderer.material.color = Color.Lerp(Color.green, Color.black, (float)n.distance/(Mathf.Max(sx,sz)*4));
- yield return new WaitForEndOfFrame();
- }
- List<V2> directions = new List<V2>();
- public List<V2> getAdjacents(V2 v2)
- {
- //Gets all nodes around the node with position [v2].
- List<V2> result = new List<V2>();
- foreach(V2 dir in directions)
- {
- int x = v2.x+dir.x;
- int z = v2.z+dir.z;
- //If it's one of these, it's invalid. Like position (-1,0) is not on the grid.
- if( x < 0 ||
- x>=sx ||
- z < 0 ||
- z >=sz)
- {
- }
- else
- {
- result.Add(new V2(x,z));
- }
- }
- return result;
- }
- public void Display()
- {
- for(int ix = 0; ix < sx; ix++)
- {
- for(int iz = 0; iz < sz; iz++)
- {
- UpdateCell(arr[ix,iz]);
- }
- }
- }
- }
- public class V2{ public int x; public int z; public V2(int _x, int _z){ x = _x; z = _z; } }
- public class Node{ public V2 v2; public int distance = 0; public Transform cell; public int weight = 1;}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement