Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using UnityEngine;
- using System.Collections;
- using System.Collections.Generic;
- using System.Threading;
- public class FloodFillGrid : MonoBehaviour
- {
- //Public attributes
- public LayerMask collisionMask;
- public uint gridSizeX;
- public uint gridSizeY;
- [Range(1, 3)]
- public uint nodeSize;
- public float refreshDelay;
- public int maxRefreshdistance;
- public GameObject player;
- public Node[,] grid;
- public GameObject container;
- //Private attributes
- public float localRefreshDelay;
- Vector2 origin; //Bottom left of grid
- Node playerNode; //Node containing the player
- //Debug attributes
- private Node[,] gizmoGrid;
- public enum DebugModes { None = 0, Borders, Gizmos, distance, GizmosAnddistance };
- public DebugModes debugMode;
- public GameObject debugTextBox;
- //Use this for initialization
- public void InitializeFloodFillGrid()
- {
- if (player == null)
- player = GameObject.FindGameObjectWithTag("Player");
- if (player == null)
- throw new UnityException("Player gameobject not found!");
- grid = InitializeGrid(); //Initialize grid
- if (IsNodeInGridBounds(Mathf.FloorToInt(player.transform.position.x - origin.x), Mathf.FloorToInt(player.transform.position.y - origin.y)))
- {
- WorldToGridPosition(player.transform.position).check = true; //Grid entry point
- FloodFill(WorldToGridPosition(player.transform.position)); //Fill grid
- if (GetComponent<PathRequestManager>() == null || !GetComponent<PathRequestManager>().isActiveAndEnabled)
- throw new UnityException("RequestManager script not found or inactive!");
- GetComponent<PathRequestManager>().InitializePathRequestManager(); //Initialize PathRequestManager
- if (debugMode == DebugModes.distance || debugMode == DebugModes.GizmosAnddistance)
- {
- foreach (Node node in grid)
- {
- //if (node.check)
- {
- if (Application.isPlaying)
- node.debugText = GameObject.Instantiate(debugTextBox, GridToWorldPosition(node) + new Vector3(0, 0, -1), Quaternion.identity) as GameObject;
- }
- }
- }
- }
- else
- {
- throw new UnityException("Player is not inside the grid bounds.");
- }
- }
- //Initiate the grid
- [ExecuteInEditMode]
- Node[,] InitializeGrid()
- {
- Node[,] grid = new Node[gridSizeX, gridSizeY];
- Vector2 position;
- bool walkable;
- //Calculate bottom left of grid
- origin = new Vector2(-(gridSizeX / 2 * nodeSize), -(gridSizeY / 2 * nodeSize));
- //Determine node attributes
- for (int x = 0; x < gridSizeX; x++)
- {
- for (int y = 0; y < gridSizeY; y++)
- {
- position = origin + new Vector2(x * nodeSize, y * nodeSize);
- walkable = !Physics2D.OverlapPoint(position, collisionMask);
- if (Physics2D.OverlapPoint(position + new Vector2(1, 0), collisionMask) ||
- Physics2D.OverlapPoint(position + new Vector2(-1, 0), collisionMask) ||
- Physics2D.OverlapPoint(position + new Vector2(0, 1), collisionMask) ||
- Physics2D.OverlapPoint(position + new Vector2(0, -1), collisionMask))
- {
- grid[x, y] = new Node(walkable, x, y, true, this);
- }
- else
- {
- grid[x, y] = new Node(walkable, x, y, false, this);
- }
- }
- }
- return grid;
- }
- //Flood the grid
- void FloodFill(Node node)
- {
- if (node == null)
- return;
- Node current = node;
- List<Node> nodesToCheck = new List<Node>() { node };
- int distance;
- //Reset the grid
- foreach (Node n in grid)
- {
- if (n.check == true)
- {
- n.distance = 0;
- n.check = false;
- n.isEnqueued = false;
- }
- }
- //Check the whole grid, stop when all accessible nodes are scanned
- while (nodesToCheck.Count > 0)
- {
- current = nodesToCheck[0];
- distance = current.distance;
- current.check = true;
- nodesToCheck.RemoveAt(0); //Remove the node from queue
- if (distance < maxRefreshdistance)
- {
- //Check if neighbour nodes are inside of the grid bounds and try to enqueue it
- CheckAndEnqueueNode(current.x + 1, current.y, nodesToCheck, distance);
- CheckAndEnqueueNode(current.x - 1, current.y, nodesToCheck, distance);
- CheckAndEnqueueNode(current.x, current.y + 1, nodesToCheck, distance);
- CheckAndEnqueueNode(current.x, current.y - 1, nodesToCheck, distance);
- }
- }
- }
- //Checks if the node is valid and accessible to enqueue it for check
- void CheckAndEnqueueNode(Node node, List<Node> nodesToCheck, int distance)
- {
- if (IsNodeInGridBounds(node.x, node.y))
- {
- //Check if node is walkable, not queued for check and unchecked
- if (grid[node.x, node.y].walkable && !node.isEnqueued && !grid[node.x, node.y].check)
- {
- //Enqueue node and set its distance
- nodesToCheck.Add(grid[node.x, node.y]);
- node.isEnqueued = true;
- grid[node.x, node.y].distance = distance + 1;
- }
- }
- }
- void CheckAndEnqueueNode(int x, int y, List<Node> nodesToCheck, int distance)
- {
- if (IsNodeInGridBounds(x, y))
- {
- //Check if node is walkable, not queued for check and unchecked
- if (grid[x, y].walkable && !grid[x, y].isEnqueued && !grid[x, y].check)
- {
- //Enqueue node and set its distance
- nodesToCheck.Add(grid[x, y]);
- grid[x, y].isEnqueued = true;
- grid[x, y].distance = distance + 1;
- }
- }
- }
- //Update is called once per frame
- void Update()
- {
- if (grid != null)
- {
- localRefreshDelay += Time.deltaTime;
- if (localRefreshDelay > refreshDelay)
- {
- //Reset the timer and refresh the grid
- localRefreshDelay = 0f;
- playerNode = WorldToGridPosition(player.transform.position);
- FloodFill(playerNode);
- //Adapt displayed distance if debug is active
- if (debugMode == DebugModes.distance || debugMode == DebugModes.GizmosAnddistance)
- foreach (Node node in grid)
- if (!(node.debugText == null))
- node.debugText.GetComponent<TextMesh>().text = node.distance.ToString();
- }
- }
- }
- //Convert world to grid position
- public Node WorldToGridPosition(Vector3 position)
- {
- int x = Mathf.RoundToInt((position.x - origin.x) / (nodeSize * gridSizeX) * gridSizeX);
- int y = Mathf.RoundToInt((position.y - origin.y) / (nodeSize * gridSizeY) * gridSizeY);
- if (IsNodeInGridBounds(x, y))
- return grid[x, y];
- return null;
- }
- //Convert grid to world position
- public Vector3 GridToWorldPosition(Node node)
- {
- Vector3 position;
- position = new Vector2(node.x * nodeSize, node.y * nodeSize) + origin;
- return position;
- }
- //Checks if node is in grid bounds
- public bool IsNodeInGridBounds(int x, int y)
- {
- if (x >= 0 && x < gridSizeX && y >= 0 && y < gridSizeY)
- return true;
- return false;
- }
- //OnDrawGizmos is called when anything in the Viewport changes (not active in build), debug only
- void OnDrawGizmos()
- {
- if (isActiveAndEnabled)
- {
- if (debugMode != DebugModes.None && gridSizeX > 0 && gridSizeY > 0)
- {
- gizmoGrid = InitializeGrid();
- Gizmos.color = Color.cyan;
- for (int x = 0; x < gridSizeX; x++)
- {
- Gizmos.DrawWireCube(GridToWorldPosition(gizmoGrid[x, 0]), nodeSize * Vector3.one);
- Gizmos.DrawWireCube(GridToWorldPosition(gizmoGrid[x, gridSizeY - 1]), nodeSize * Vector3.one);
- }
- for (int y = 1; y < gridSizeY - 1; y++)
- {
- Gizmos.DrawWireCube(GridToWorldPosition(gizmoGrid[0, y]), nodeSize * Vector3.one);
- Gizmos.DrawWireCube(GridToWorldPosition(gizmoGrid[gridSizeX - 1, y]), nodeSize * Vector3.one);
- }
- }
- if (debugMode == DebugModes.Gizmos || debugMode == DebugModes.GizmosAnddistance)
- {
- if (grid != null)
- {
- //Draw grid origin
- Gizmos.DrawWireSphere(origin, 0.5f);
- //Draw all accessible nodes
- foreach (Node node in grid)
- {
- if (node.check || !node.walkable)
- {
- if (node == playerNode)
- {
- Gizmos.color = Color.blue;
- Gizmos.DrawWireSphere(GridToWorldPosition(node), nodeSize / 2);
- }
- else
- {
- Gizmos.color = (node.walkable) ? Color.white : Color.red;
- Vector3 position = GridToWorldPosition(node);
- Gizmos.DrawLine(new Vector3(position.x, position.y, 0.5f), new Vector3(position.x, position.y, -0.5f));
- }
- }
- }
- }
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement