Advertisement
SteamGear

Untitled

Jun 11th, 2016
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 10.08 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Threading;
  5.  
  6. public class FloodFillGrid : MonoBehaviour
  7. {
  8.     //Public attributes
  9.     public LayerMask collisionMask;
  10.     public uint gridSizeX;
  11.     public uint gridSizeY;
  12.     [Range(1, 3)]
  13.     public uint nodeSize;
  14.     public float refreshDelay;
  15.     public int maxRefreshdistance;
  16.     public GameObject player;
  17.     public Node[,] grid;
  18.     public GameObject container;
  19.     //Private attributes
  20.     public float localRefreshDelay;
  21.     Vector2 origin; //Bottom left of grid
  22.     Node playerNode; //Node containing the player
  23.  
  24.     //Debug attributes
  25.     private Node[,] gizmoGrid;
  26.     public enum DebugModes { None = 0, Borders, Gizmos, distance, GizmosAnddistance };
  27.     public DebugModes debugMode;
  28.     public GameObject debugTextBox;
  29.  
  30.     //Use this for initialization
  31.     public void InitializeFloodFillGrid()
  32.     {
  33.         if (player == null)
  34.             player = GameObject.FindGameObjectWithTag("Player");
  35.         if (player == null)
  36.             throw new UnityException("Player gameobject not found!");
  37.  
  38.         grid = InitializeGrid(); //Initialize grid
  39.         if (IsNodeInGridBounds(Mathf.FloorToInt(player.transform.position.x - origin.x), Mathf.FloorToInt(player.transform.position.y - origin.y)))
  40.         {
  41.             WorldToGridPosition(player.transform.position).check = true; //Grid entry point
  42.             FloodFill(WorldToGridPosition(player.transform.position));  //Fill grid      
  43.  
  44.             if (GetComponent<PathRequestManager>() == null || !GetComponent<PathRequestManager>().isActiveAndEnabled)
  45.                 throw new UnityException("RequestManager script not found or inactive!");
  46.             GetComponent<PathRequestManager>().InitializePathRequestManager(); //Initialize PathRequestManager
  47.  
  48.             if (debugMode == DebugModes.distance || debugMode == DebugModes.GizmosAnddistance)
  49.             {
  50.                 foreach (Node node in grid)
  51.                 {
  52.                     //if (node.check)
  53.                     {
  54.                         if (Application.isPlaying)
  55.                             node.debugText = GameObject.Instantiate(debugTextBox, GridToWorldPosition(node) + new Vector3(0, 0, -1), Quaternion.identity) as GameObject;
  56.                     }
  57.                 }
  58.             }
  59.         }
  60.         else
  61.         {
  62.             throw new UnityException("Player is not inside the grid bounds.");
  63.         }
  64.     }
  65.  
  66.     //Initiate the grid
  67.     [ExecuteInEditMode]
  68.     Node[,] InitializeGrid()
  69.     {
  70.         Node[,] grid = new Node[gridSizeX, gridSizeY];
  71.  
  72.         Vector2 position;
  73.         bool walkable;
  74.         //Calculate bottom left of grid
  75.         origin = new Vector2(-(gridSizeX / 2 * nodeSize), -(gridSizeY / 2 * nodeSize));
  76.  
  77.         //Determine node attributes
  78.         for (int x = 0; x < gridSizeX; x++)
  79.         {
  80.             for (int y = 0; y < gridSizeY; y++)
  81.             {
  82.                 position = origin + new Vector2(x * nodeSize, y * nodeSize);
  83.                 walkable = !Physics2D.OverlapPoint(position, collisionMask);
  84.                 if (Physics2D.OverlapPoint(position + new Vector2(1, 0), collisionMask) ||
  85.                     Physics2D.OverlapPoint(position + new Vector2(-1, 0), collisionMask) ||
  86.                     Physics2D.OverlapPoint(position + new Vector2(0, 1), collisionMask) ||
  87.                     Physics2D.OverlapPoint(position + new Vector2(0, -1), collisionMask))
  88.                 {
  89.                     grid[x, y] = new Node(walkable, x, y, true, this);
  90.                 }
  91.                 else
  92.                 {
  93.                     grid[x, y] = new Node(walkable, x, y, false, this);
  94.                 }
  95.             }
  96.         }
  97.         return grid;
  98.     }
  99.  
  100.     //Flood the grid
  101.     void FloodFill(Node node)
  102.     {
  103.         if (node == null)
  104.             return;
  105.  
  106.         Node current = node;
  107.         List<Node> nodesToCheck = new List<Node>() { node };
  108.         int distance;
  109.  
  110.         //Reset the grid
  111.         foreach (Node n in grid)
  112.         {
  113.             if (n.check == true)
  114.             {
  115.                 n.distance = 0;
  116.                 n.check = false;
  117.                 n.isEnqueued = false;
  118.             }
  119.         }
  120.  
  121.         //Check the whole grid, stop when all accessible nodes are scanned
  122.         while (nodesToCheck.Count > 0)
  123.         {
  124.             current = nodesToCheck[0];
  125.             distance = current.distance;
  126.             current.check = true;
  127.             nodesToCheck.RemoveAt(0); //Remove the node from queue
  128.             if (distance < maxRefreshdistance)
  129.             {
  130.                 //Check if neighbour nodes are inside of the grid bounds and try to enqueue it
  131.                 CheckAndEnqueueNode(current.x + 1, current.y, nodesToCheck, distance);
  132.                 CheckAndEnqueueNode(current.x - 1, current.y, nodesToCheck, distance);
  133.                 CheckAndEnqueueNode(current.x, current.y + 1, nodesToCheck, distance);
  134.                 CheckAndEnqueueNode(current.x, current.y - 1, nodesToCheck, distance);
  135.             }
  136.         }
  137.     }
  138.  
  139.     //Checks if the node is valid and accessible to enqueue it for check
  140.     void CheckAndEnqueueNode(Node node, List<Node> nodesToCheck, int distance)
  141.  
  142.     {
  143.         if (IsNodeInGridBounds(node.x, node.y))
  144.         {
  145.             //Check if node is walkable, not queued for check and unchecked
  146.             if (grid[node.x, node.y].walkable && !node.isEnqueued && !grid[node.x, node.y].check)
  147.             {
  148.                 //Enqueue node and set its distance
  149.                 nodesToCheck.Add(grid[node.x, node.y]);
  150.                 node.isEnqueued = true;
  151.                 grid[node.x, node.y].distance = distance + 1;
  152.             }
  153.         }
  154.     }
  155.  
  156.     void CheckAndEnqueueNode(int x, int y, List<Node> nodesToCheck, int distance)
  157.     {
  158.         if (IsNodeInGridBounds(x, y))
  159.         {
  160.             //Check if node is walkable, not queued for check and unchecked
  161.             if (grid[x, y].walkable && !grid[x, y].isEnqueued && !grid[x, y].check)
  162.             {
  163.                 //Enqueue node and set its distance
  164.                 nodesToCheck.Add(grid[x, y]);
  165.                 grid[x, y].isEnqueued = true;
  166.                 grid[x, y].distance = distance + 1;
  167.             }
  168.         }
  169.     }
  170.     //Update is called once per frame
  171.     void Update()
  172.     {
  173.         if (grid != null)
  174.         {
  175.             localRefreshDelay += Time.deltaTime;
  176.             if (localRefreshDelay > refreshDelay)
  177.             {
  178.                 //Reset the timer and refresh the grid
  179.                 localRefreshDelay = 0f;
  180.                 playerNode = WorldToGridPosition(player.transform.position);
  181.                 FloodFill(playerNode);
  182.                 //Adapt displayed distance if debug is active
  183.                 if (debugMode == DebugModes.distance || debugMode == DebugModes.GizmosAnddistance)
  184.                     foreach (Node node in grid)
  185.                         if (!(node.debugText == null))
  186.                             node.debugText.GetComponent<TextMesh>().text = node.distance.ToString();
  187.             }
  188.         }
  189.     }
  190.  
  191.     //Convert world to grid position
  192.     public Node WorldToGridPosition(Vector3 position)
  193.     {
  194.         int x = Mathf.RoundToInt((position.x - origin.x) / (nodeSize * gridSizeX) * gridSizeX);
  195.         int y = Mathf.RoundToInt((position.y - origin.y) / (nodeSize * gridSizeY) * gridSizeY);
  196.         if (IsNodeInGridBounds(x, y))
  197.             return grid[x, y];
  198.         return null;
  199.     }
  200.  
  201.     //Convert grid to world position
  202.     public Vector3 GridToWorldPosition(Node node)
  203.     {
  204.         Vector3 position;
  205.         position = new Vector2(node.x * nodeSize, node.y * nodeSize) + origin;
  206.  
  207.         return position;
  208.     }
  209.  
  210.     //Checks if node is in grid bounds
  211.     public bool IsNodeInGridBounds(int x, int y)
  212.     {
  213.         if (x >= 0 && x < gridSizeX && y >= 0 && y < gridSizeY)
  214.             return true;
  215.         return false;
  216.     }
  217.  
  218.     //OnDrawGizmos is called when anything in the Viewport changes (not active in build), debug only
  219.     void OnDrawGizmos()
  220.     {
  221.         if (isActiveAndEnabled)
  222.         {
  223.             if (debugMode != DebugModes.None && gridSizeX > 0 && gridSizeY > 0)
  224.             {
  225.                 gizmoGrid = InitializeGrid();
  226.                 Gizmos.color = Color.cyan;
  227.                 for (int x = 0; x < gridSizeX; x++)
  228.                 {
  229.                     Gizmos.DrawWireCube(GridToWorldPosition(gizmoGrid[x, 0]), nodeSize * Vector3.one);
  230.                     Gizmos.DrawWireCube(GridToWorldPosition(gizmoGrid[x, gridSizeY - 1]), nodeSize * Vector3.one);
  231.                 }
  232.                 for (int y = 1; y < gridSizeY - 1; y++)
  233.                 {
  234.                     Gizmos.DrawWireCube(GridToWorldPosition(gizmoGrid[0, y]), nodeSize * Vector3.one);
  235.                     Gizmos.DrawWireCube(GridToWorldPosition(gizmoGrid[gridSizeX - 1, y]), nodeSize * Vector3.one);
  236.                 }
  237.             }
  238.             if (debugMode == DebugModes.Gizmos || debugMode == DebugModes.GizmosAnddistance)
  239.             {
  240.                 if (grid != null)
  241.                 {
  242.                     //Draw grid origin
  243.                     Gizmos.DrawWireSphere(origin, 0.5f);
  244.  
  245.                     //Draw all accessible nodes
  246.                     foreach (Node node in grid)
  247.                     {
  248.                         if (node.check || !node.walkable)
  249.                         {
  250.                             if (node == playerNode)
  251.                             {
  252.                                 Gizmos.color = Color.blue;
  253.                                 Gizmos.DrawWireSphere(GridToWorldPosition(node), nodeSize / 2);
  254.                             }
  255.                             else
  256.                             {
  257.                                 Gizmos.color = (node.walkable) ? Color.white : Color.red;
  258.                                 Vector3 position = GridToWorldPosition(node);
  259.                                 Gizmos.DrawLine(new Vector3(position.x, position.y, 0.5f), new Vector3(position.x, position.y, -0.5f));
  260.                             }
  261.                         }
  262.                     }
  263.                 }
  264.             }
  265.         }
  266.     }
  267. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement