OldBlueWater/BlueWater/Assets/GolemiteGames/GridBuilder2/Scripts/GridSquare.cs
2023-08-01 13:03:57 +09:00

1936 lines
70 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.IO;
//Strips at build time
#if UNITY_EDITOR
using UnityEditor;
#endif
/*************This class is the base of the system where all other components relate to**************/
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class GridSquare : MonoBehaviour
{
//Enums
public enum GridType
{
SingleCell,
Chequered,
Simple,
Points,
Lines
}
public enum BlockType
{
BlockBoth,
BlockAbove,
BlockBelow
}
/*******Grid private variables********/
//Data variables
Vector3[] gridPoints;
Vector3[] cells;
int numCells;
public Dictionary<Vector3, GameObject> gridCellsStatus;
public Dictionary<Vector3, GameObject> gridCells;
static List<MeshRenderer> freeCells = new List<MeshRenderer>();
static List<MeshRenderer> blockedCells = new List<MeshRenderer>();
//Simple mesh creation variables
Mesh mesh;
Vector3[] meshVertices;
int[] meshTriangles;
BoxCollider meshCollider;
float colliderThickness = 0.01f;
Vector2[] uvs;
Renderer rend;
//Containers
GameObject cellContainer;
GameObject pointsContainer;
GameObject gridObjContainer;
//Line variables
Mesh linesMesh;
Vector3[] linesVertices;
int[] linesTriangles;
GameObject line;
GameObject linesContainer;
//Odd
Vector3 checkBoxSize;
Transform pointsArr;
//Cached components
GridSelector gridSelector;
ObjectPlacer objectPlacer;
GridObjectOptions gridObjectOptions;
//Save and loading
GridCreationData gridCreationData;
bool loaded = false;
bool created;
bool createInEditor = false;
bool autoCellBlockPreview = false;
/*****************Serialised inspector variables**********************/
//General settings
[SerializeField] bool editorExtension = false;
[SerializeField] string id;
[SerializeField] bool visualOnly = false;
[Min(1)]
[SerializeField] int gridWidth = 10;
[Min(1)]
[SerializeField] int gridHeight = 10;
[Min(0.001f)]
[SerializeField] float cellSize = 1;
[SerializeField] GridType gridType;
[SerializeField] bool drawSimple;
[Min(0)]
[SerializeField] int autoSaveInterval;
[SerializeField] bool saveGridOnExit;
[SerializeField] bool loadSaveOnStart;
[SerializeField] bool loadConfigOnStart;
[SerializeField] bool checkMatRuntime;
[SerializeField] float tileX = 2;
[SerializeField] float tileY = 2;
[Range(0, 1f)]
//Point creation variables
[SerializeField] float pointRadius;
//LinesMeshVariables
[Range(0, 0.5f)]
[SerializeField] float linesThickness;
//Auto cell blocking variables
[SerializeField] bool autoCellBlocking = false;
[SerializeField] BlockType blocktype;
[SerializeField] LayerMask ignoreLayers;
[SerializeField] int groundLayer;
[SerializeField] float groundDistance = 0.05f;
[SerializeField] float aboveCheckBoxSize = 1f;
[SerializeField] float aboveCheckBoxHeight = 1f;
[SerializeField] float checkBoxOffset;
[SerializeField] bool showAboveBoxColliders = false;
[SerializeField] bool showBelowRays = false;
[SerializeField] bool checkGroundHits = false;
//Prefabs
[SerializeField] GameObject gridCellPrefab;
[SerializeField] GameObject secondGridCellPrefab;
[SerializeField] GameObject blockedAboveCellPrefab;
[SerializeField] GameObject blockedBelowCellPrefab;
[SerializeField] GameObject pointsPrefab;
//Debug
[SerializeField] bool drawGridPositions = false;
[SerializeField] bool drawCellPositions = false;
//Accessors
public string Id
{
get { return id; }
set { id = value; }
}
public Transform PointsArr
{
get { return pointsArr; }
}
public bool VisualOnly
{
get { return visualOnly; }
}
public GridType GetGridType
{
get { return gridType; }
}
public int GridWidth
{
get { return gridWidth; }
}
public int GridHeight
{
get { return gridHeight; }
}
public float LinesThickness
{
get { return linesThickness; }
}
public float PointRadius
{
get { return pointRadius; }
}
public bool Created
{
get { return created; }
set { created = value; }
}
public GameObject GridObjectContainer
{
get { return gridObjContainer; }
}
public float CellSize
{
get { return cellSize; }
}
public bool Loaded
{
set { loaded = value; }
}
public int GroundLayer
{
get { return groundLayer; }
}
public Vector3[] Cells
{
get { return cells; }
set { cells = value; }
}
public GameObject CellContainer
{
get => cellContainer;
set => cellContainer = value;
}
public List<MeshRenderer> FreeCells
{
get { return freeCells; }
set { freeCells = value; }
}
public List<MeshRenderer> BlockedCells
{
get { return blockedCells; }
set { blockedCells = value; }
}
public float GroundDistance
{
get => groundDistance;
set => groundDistance = value;
}
public BlockType Blocktype
{
get => blocktype;
set => blocktype = value;
}
public bool EditorExtension { get => editorExtension; set => editorExtension = value; }
public bool UseFixedUpdate { get => createInEditor; set => createInEditor = value; }
public GridCreationData GridCreationData { get => gridCreationData; set => gridCreationData = value; }
public Vector3[] GridPoints { get => gridPoints; set => gridPoints = value; }
public bool AutoCellBlockPreview { get => autoCellBlockPreview; set => autoCellBlockPreview = value; }
#if UNITY_EDITOR
private void Reset()
{
SetNewId();
CreateGrid();
CreateGridCells();
}
public void SetNewId()
{
id = GUID.Generate().ToString().Substring(0, 8);
}
#endif
private void Awake()
{
if (GridBuilder2Manager.Instance != null)
{
//Cache objects
objectPlacer = GridBuilder2Manager.Instance.ObjectPlacer;
gridObjectOptions = GridBuilder2Manager.Instance.GridObjectOptions;
gridSelector = GridBuilder2Manager.Instance.GridSelector;
}
LoadGridCreationData();
createInEditor = false;
if(gridCreationData != null)
{
created = true;
}
}
public void LoadGridCreationData()
{
string loadPath = $"GridCreationData/{gameObject.scene.name}/{this.name}-{id}".Replace(" ", string.Empty);
gridCreationData = Resources.Load<GridCreationData>(loadPath);
if (gridCreationData != null)
{
gridCreationData.RebuildData(this);
}
}
public void StartGridCR()
{
createInEditor = true;
StartCoroutine(Start());
}
IEnumerator Start()
{
if (!created)
{
#if UNITY_EDITOR
if(createInEditor)
{
EditorUtility.DisplayProgressBar("Grid Creation Progress", "Creating data structures...", 0.1f);
}
#endif
RemoveAutoCellBlockPreview();
if(createInEditor || !editorExtension)
{
InitialiseDataStructures();
}
//The grid system needs the physics to calculate so we have to wait for an update frame and then we can build the rest of the grid
if(!createInEditor)
{
yield return new WaitForFixedUpdate();
}
yield return null;
#if UNITY_EDITOR
if (createInEditor)
{
EditorUtility.DisplayProgressBar("Grid Creation Progress", "Creating grid nodes...", 0.3f);
}
#endif
/************Keep these creation types above the collider creation otherwise the grid will detect itself when building.*************/
//Creates the relevent containers and builds the grid by its grid type
switch (gridType)
{
case GridType.Simple:
{
mesh = new Mesh();
GetComponent<MeshFilter>().mesh = mesh;
rend = GetComponent<Renderer>();
CreateSimpleGrid();
break;
}
case GridType.SingleCell:
case GridType.Chequered:
{
cellContainer = new GameObject("CellContainer");
cellContainer.transform.parent = transform;
if (FindObjectOfType<BuildMode>())
{
cellContainer.SetActive(false);
}
CreateSingleCellGrid();
break;
}
case GridType.Points:
{
pointsContainer = new GameObject("PointsContainer");
pointsContainer.transform.parent = transform;
if (FindObjectOfType<BuildMode>())
{
pointsContainer.SetActive(false);
}
rend = GetComponent<Renderer>();
CreatePointGrid();
pointsArr = pointsContainer.GetComponentInChildren<Transform>();
break;
}
case GridType.Lines:
{
linesContainer = new GameObject("LinesContainer");
linesContainer.transform.parent = transform;
if (FindObjectOfType<BuildMode>())
{
linesContainer.SetActive(false);
}
linesMesh = new Mesh();
CreateLinesGrid();
break;
}
}
#if UNITY_EDITOR
if (createInEditor)
{
EditorUtility.DisplayProgressBar("Grid Creation Progress", "Saving Grid Creation Data...", 0.6f);
}
#endif
//New parent for the placed objects to go under
gridObjContainer = new GameObject("GridObjContainer");
gridObjContainer.transform.parent = transform;
//Keep this last
if (!visualOnly)
{
meshCollider = gameObject.AddComponent<BoxCollider>();
SetColliderSize();
}
if (createInEditor)
{
gridCreationData = SaveLoadGrid.CreateGridCreationData(this);
}
created = true;
}
else
{
gridObjContainer = gameObject.transform.Find("GridObjContainer").gameObject;
}
#if UNITY_EDITOR
if (createInEditor)
{
EditorUtility.DisplayProgressBar("Grid Creation Progress", "Loading options...", 0.9f);
}
#endif
//This will load the grid at beginning if enabled and if it finds a save file
if (loadSaveOnStart)
{
LoadGrid();
}
if (loadConfigOnStart)
{
LoadPreconfiguration();
}
//Sets up repeating the save command after X minutes
if (autoSaveInterval > 0)
{
InvokeRepeating("SaveGrid", autoSaveInterval * 60, autoSaveInterval * 60);
}
#if UNITY_EDITOR
if (createInEditor)
{
EditorUtility.ClearProgressBar();
}
#endif
}
private void InitialiseDataStructures()
{
//Initialises the data structures for the grid system
CreateGrid();
CreateGridCells();
CreateGridStatus();
CreateGridCellStatus();
}
private void RemoveAutoCellBlockPreview()
{
//Checks to see on play if there is a preview of the autoCellBlock on, and if so, remove it
if (gameObject.transform.childCount > 0)
{
Transform[] children = gameObject.transform.GetComponentsInChildren<Transform>();
for (int i = 0; i < children.Length; i++)
{
if (!children[i].GetComponent<GridSquare>())
{
Destroy(children[i].gameObject);
}
}
}
}
private void Update()
{
//Simple way to see the material tiling at runtime
if (gridType == GridType.Simple)
{
if (checkMatRuntime)
{
UpdateMaterial();
}
}
}
//This will save the grid on application quit if enabled
private void OnApplicationQuit()
{
if (saveGridOnExit)
{
SaveGrid();
}
}
//Sends the grid to be saved with all of its placed objects
public void SaveGrid()
{
if(gameObject.activeSelf)
{
SaveLoadGrid.SaveCurrentGrid(this);
}
}
//Loads the grid with all objects previously saved
public void LoadGrid()
{
//If it is already loaded, do not load again
if (loaded)
{
return;
}
//If you are loading a preconfig you cannot load a save until after saving again
if (loadConfigOnStart)
{
return;
}
//Clears storage for initiating objects again
ObjectStorage.GOTypeList.Clear();
ObjectStorage.GOInstanceList.Clear();
List<GameObject> destroyGOList = new List<GameObject>();
List<Vector3> changeStatusList = new List<Vector3>();
if(gridCellsStatus != null)
foreach (KeyValuePair<Vector3, GameObject> entry in gridCellsStatus)
{
if (entry.Value != null && entry.Value != this.gameObject)
{
destroyGOList.Add(entry.Value);
changeStatusList.Add(entry.Key);
}
}
//This is when you try to load after making changes on the current session without saving
if (destroyGOList.Count > 0)
{
Debug.Log("There are unsaved changes, loading old save");
//If using a confirmation UI, put the below for loop in a coroutine to wait until the user has clicked
for (int i = 0; i < destroyGOList.Count; i++)
{
ChangeCellStatus(changeStatusList[i], null);
Destroy(destroyGOList[i].gameObject);
}
}
//Will not try to load if you have hidden the grid, the data needs the gridSqaure object to be active
if (gameObject.activeSelf)
{
int counter = 0;
int objSizeCounter = 0;
int blockCellCounter = 0;
//Gets the data
GridData gridData = SaveLoadGrid.LoadCurrentGrid(this);
if (gridData != null)
{
//This loops through every placed object that was saved
for (int i = 0; i < gridData.objectName.Count; i++)
{
//Outputs the gridData to all the initial variables the GridObject class needs
/**************YOU MUST PUT YOUR PLACEABLE OBJECTS IN "Resources/Prefabs/PlaceableObjects/"*******************/
//These folders can be anywhere, but must contain the above directory ^^^^^^
GameObject resourceObject = (GameObject)Resources.Load($"PlaceableObjects/{gridData.objectName[i]}");
Vector3 position = new Vector3(gridData.xPositions[i], gridData.yPositions[i], gridData.zPositions[i]);
Vector3 offset = new Vector3(gridData.xOffsetPositions[i], gridData.yOffsetPositions[i], gridData.zOffsetPositions[i]);
Vector3 originalOffset = new Vector3(gridData.xOriginalOffsetPos[i], gridData.yOriginalOffsetPos[i], gridData.zOriginalOffsetPos[i]);
float rotation = gridData.rotationY[i];
Building.ObjectSize objSize = new Building.ObjectSize();
bool moveOnPoints = gridData.moveOnPoints[i];
List<Vector3> checkPositions = new List<Vector3>();
int buildTime = gridData.buildTime[i];
int buildTimeRemaining = gridData.buildTimeRemaining[i];
int upgradeLevel = gridData.upgradeLevel[i];
//Checks to see if the object exists in the placeable objects folder
if (resourceObject)
{
GameObject clonedObj;
//Gets check positions
for (int j = 0; j < gridData.amountOfCheckPositions[i]; j++)
{
Vector3 checkPosition = new Vector3(
gridData.xcheckPositions[counter],
gridData.ycheckPositions[counter],
gridData.zcheckPositions[counter]);
checkPositions.Add(checkPosition);
counter++;
}
//Finds the correct object size booleans
int k = 0;
System.Reflection.FieldInfo[] clonedFields;
clonedFields = objSize.GetType().GetFields();
foreach (System.Reflection.FieldInfo prop in objSize.GetType().GetFields())
{
clonedFields[k].SetValue(objSize, gridData.selectChecks[k + objSizeCounter]);
k++;
}
objSizeCounter += objSize.GetNum();
//Builds the GridObject data class
GridObject.Data gridObjectData = new GridObject.Data();
gridObjectData.ObjName = gridData.objectName[i];
gridObjectData.PrefabId = gridData.prefabID[i];
gridObjectData.InstanceId = gridData.instanceID[i];
gridObjectData.Position = position;
gridObjectData.CheckPositions = checkPositions;
gridObjectData.Offset = offset;
gridObjectData.OriginalOffset = originalOffset;
gridObjectData.Rotation = rotation;
gridObjectData.GridSquare = this;
gridObjectData.ObjSize = objSize;
gridObjectData.MoveOnPoints = moveOnPoints;
gridObjectData.BuildTime = buildTime;
gridObjectData.BuildTimeRemaining = buildTimeRemaining;
gridObjectData.UpgradeLevel = upgradeLevel;
//Rebuilds the objects back onto the grid
if (objectPlacer)
{
//Has an upgrade timer remaining
if(buildTimeRemaining > 0)
{
//In the middle of an upgrade with time remaining
if(upgradeLevel >= 1)
{
clonedObj = objectPlacer.PlaceObject(resourceObject, gridObjectData, resourceObject.layer);
}
//Being built on a timer
else
{
clonedObj = objectPlacer.DelayBuildStart(resourceObject, gridObjectData, resourceObject.layer, gridObjectData.BuildTime);
}
}
else
{
clonedObj = objectPlacer.PlaceObject(resourceObject, gridObjectData, resourceObject.layer);
}
//If the object has an upgrade, rebuild the currentUgpradeLevel
if (clonedObj.GetComponent<UpgradeData>())
{
clonedObj.GetComponent<UpgradeData>().CurrentUpgradeLevel = upgradeLevel;
if (buildTimeRemaining > 0 && (upgradeLevel >= 1))
{
if (gridObjectOptions)
{
gridObjectOptions.SelectedObject = clonedObj;
gridObjectOptions.StartUpgrade();
}
}
}
if (gridSelector.PreviewObjFloorTiles && gridSelector.PlaceTilesWithObject && gridSelector.PreviewObjFloorTilePrefab)
{
//Rebuilds the floor tiles if enabled
GameObject tileParent = new GameObject("FloorTileParent");
tileParent.transform.position = clonedObj.transform.position;
tileParent.transform.parent = clonedObj.transform;
foreach (Vector3 pos in checkPositions)
{
GameObject tile = Instantiate(gridSelector.PreviewObjFloorTilePrefab,
pos + new Vector3(0, gridSelector.HoverDistance, 0),
Quaternion.identity,
tileParent.transform);
tile.name = "previewFloorTile";
}
tileParent.transform.localRotation = Quaternion.Euler(0, -rotation, 0);
}
//Re hides the cells underneath the loaded object if enabled
if (objectPlacer.HideCellsUnderPlacedObj)
{
objectPlacer.HidePlacedObjCells(this, checkPositions);
}
}
else
{
clonedObj = null;
Debug.Log("Cannot load objects, need an object placer in the scene");
}
//Blocks the cells
ChangeCellStatus(position, clonedObj);
for (int j = 0; j < gridData.amountOfCheckPositions[i]; j++)
{
Vector3 checkPosition = new Vector3(
gridData.xcheckPositions[blockCellCounter],
gridData.ycheckPositions[blockCellCounter],
gridData.zcheckPositions[blockCellCounter]);
ChangeCellStatus(checkPosition, clonedObj);
blockCellCounter++;
}
}
//Resource object does not exist
else
{
//This adds one to the internal loop counters skipping one objectsSize if no resource is found
counter++;
objSizeCounter++;
blockCellCounter++;
Debug.Log($"{gridData.objectName[i]} not found in Resources/PlaceableObjects/");
}
}
}
loaded = true;
}
}
//Removes this grids save file, careful using this, this is the ONLY copy
//Would normally be used for something like users manually deleting old save files
public void DeleteGridSave()
{
SaveLoadGrid.DeleteCurrentGridSaveData(this);
}
public void LoadPreconfiguration()
{
//If it is already loaded, do not load again
if (loaded)
{
return;
}
//Cannot load preconfig and save
if(loadSaveOnStart)
{
return;
}
//Clears storage for initiating objects again
ObjectStorage.GOTypeList.Clear();
ObjectStorage.GOInstanceList.Clear();
List<GameObject> destroyGOList = new List<GameObject>();
List<Vector3> changeStatusList = new List<Vector3>();
if (gridCellsStatus != null)
foreach (KeyValuePair<Vector3, GameObject> entry in gridCellsStatus)
{
if (entry.Value != null && entry.Value != this.gameObject)
{
destroyGOList.Add(entry.Value);
changeStatusList.Add(entry.Key);
}
}
//This is when you try to load after making changes on the current session without saving
if (destroyGOList.Count > 0)
{
Debug.Log("There are unsaved changes, loading old save");
//If using a confirmation UI, put the below for loop in a coroutine to wait until the user has clicked
for (int i = 0; i < destroyGOList.Count; i++)
{
ChangeCellStatus(changeStatusList[i], null);
Destroy(destroyGOList[i].gameObject);
}
}
//Will not try to load if you have hidden the grid, the data needs the gridSqaure object to be active
if (gameObject.activeSelf)
{
int counter = 0;
int objSizeCounter = 0;
int blockCellCounter = 0;
//Gets the data
GridData gridData = SaveLoadGrid.LoadPreconfiguration(this);
if (gridData != null)
{
//This loops through every placed object that was saved
for (int i = 0; i < gridData.objectName.Count; i++)
{
//Outputs the gridData to all the initial variables the GridObject class needs
/**************YOU MUST PUT YOUR PLACEABLE OBJECTS IN "Resources/PlaceableObjects/"*******************/
//These folders can be anywhere, but must contain the above directory ^^^^^^
GameObject resourceObject = (GameObject)Resources.Load($"PlaceableObjects/{gridData.objectName[i]}");
Vector3 position = new Vector3(gridData.xPositions[i], gridData.yPositions[i], gridData.zPositions[i]);
Vector3 offset = new Vector3(gridData.xOffsetPositions[i], gridData.yOffsetPositions[i], gridData.zOffsetPositions[i]);
Vector3 originalOffset = new Vector3(gridData.xOriginalOffsetPos[i], gridData.yOriginalOffsetPos[i], gridData.zOriginalOffsetPos[i]);
float rotation = gridData.rotationY[i];
Building.ObjectSize objSize = new Building.ObjectSize();
bool moveOnPoints = gridData.moveOnPoints[i];
List<Vector3> checkPositions = new List<Vector3>();
int buildTime = gridData.buildTime[i];
int buildTimeRemaining = gridData.buildTimeRemaining[i];
int upgradeLevel = gridData.upgradeLevel[i];
//Checks to see if the object exists in the placeable objects folder
if (resourceObject)
{
GameObject clonedObj;
//Gets check positions
for (int j = 0; j < gridData.amountOfCheckPositions[i]; j++)
{
Vector3 checkPosition = new Vector3(
gridData.xcheckPositions[counter],
gridData.ycheckPositions[counter],
gridData.zcheckPositions[counter]);
checkPositions.Add(checkPosition);
counter++;
}
//Finds the correct object size booleans
int k = 0;
System.Reflection.FieldInfo[] clonedFields;
clonedFields = objSize.GetType().GetFields();
foreach (System.Reflection.FieldInfo prop in objSize.GetType().GetFields())
{
clonedFields[k].SetValue(objSize, gridData.selectChecks[k + objSizeCounter]);
k++;
}
objSizeCounter += objSize.GetNum();
//Builds the GridObject data class
GridObject.Data gridObjectData = new GridObject.Data();
gridObjectData.ObjName = gridData.objectName[i];
gridObjectData.PrefabId = gridData.prefabID[i];
gridObjectData.InstanceId = gridData.instanceID[i];
gridObjectData.Position = position;
gridObjectData.CheckPositions = checkPositions;
gridObjectData.Offset = offset;
gridObjectData.OriginalOffset = originalOffset;
gridObjectData.Rotation = rotation;
gridObjectData.GridSquare = this;
gridObjectData.ObjSize = objSize;
gridObjectData.MoveOnPoints = moveOnPoints;
gridObjectData.BuildTime = buildTime;
gridObjectData.BuildTimeRemaining = buildTimeRemaining;
gridObjectData.UpgradeLevel = upgradeLevel;
//Rebuilds the objects back onto the grid
if (objectPlacer)
{
if (buildTimeRemaining > 0)
{
//In the middle of an upgrade with time remaining
if (upgradeLevel >= 1)
{
clonedObj = objectPlacer.PlaceObject(resourceObject, gridObjectData, resourceObject.layer);
}
//Being built on a timer
else
{
clonedObj = objectPlacer.DelayBuildStart(resourceObject, gridObjectData, resourceObject.layer, gridObjectData.BuildTime);
}
}
else
{
clonedObj = objectPlacer.PlaceObject(resourceObject, gridObjectData, resourceObject.layer);
}
//If the object has an upgrade, rebuild the currentUgpradeLevel
if (clonedObj.GetComponent<UpgradeData>())
{
clonedObj.GetComponent<UpgradeData>().CurrentUpgradeLevel = upgradeLevel;
if (buildTimeRemaining > 0 && (upgradeLevel >= 1))
{
if (gridObjectOptions)
{
gridObjectOptions.SelectedObject = clonedObj;
gridObjectOptions.StartUpgrade();
}
}
}
if (gridSelector.PreviewObjFloorTiles && gridSelector.PlaceTilesWithObject && gridSelector.PreviewObjFloorTilePrefab)
{
//Rebuilds the floor tiles if enabled
GameObject tileParent = new GameObject("FloorTileParent");
tileParent.transform.position = clonedObj.transform.position;
tileParent.transform.parent = clonedObj.transform;
foreach (Vector3 pos in checkPositions)
{
GameObject tile = Instantiate(gridSelector.PreviewObjFloorTilePrefab,
pos + new Vector3(0, gridSelector.HoverDistance, 0),
Quaternion.identity,
tileParent.transform);
tile.name = "previewFloorTile";
}
tileParent.transform.localRotation = Quaternion.Euler(0, -rotation, 0);
}
//Re hides the cells underneath the loaded object if enabled
if (objectPlacer.HideCellsUnderPlacedObj)
{
objectPlacer.HidePlacedObjCells(this, checkPositions);
}
}
else
{
clonedObj = null;
Debug.Log("Cannot load objects, need an object placer in the scene");
}
//Blocks the cells
ChangeCellStatus(position, clonedObj);
for (int j = 0; j < gridData.amountOfCheckPositions[i]; j++)
{
Vector3 checkPosition = new Vector3(
gridData.xcheckPositions[blockCellCounter],
gridData.ycheckPositions[blockCellCounter],
gridData.zcheckPositions[blockCellCounter]);
ChangeCellStatus(checkPosition, clonedObj);
blockCellCounter++;
}
}
//Resource object does not exist
else
{
//This adds one to the internal loop counters skipping one objectsSize if no resource is found
counter++;
objSizeCounter++;
blockCellCounter++;
Debug.Log($"{gridData.objectName[i]} not found in Resources/PlaceableObjects/");
}
}
}
loaded = true;
}
}
//If the grid type is set to points, this calculates if a point should exist and where it should be
//This function includes the autoCellBlock calculations
private void CreatePointObjects(GameObject prefab, int i)
{
//Finds the vector3 position of each point on a cell
float halfCell = cellSize * 0.5f;
Vector3 point1 = gridPoints[i] + new Vector3(-halfCell, 0, halfCell);
point1 = TrimToThreeDP(point1);
Vector3 point2 = gridPoints[i] + new Vector3(halfCell, 0, halfCell);
point2 = TrimToThreeDP(point2);
Vector3 point3 = gridPoints[i] + new Vector3(halfCell, 0, -halfCell);
point3 = TrimToThreeDP(point3);
Vector3 point4 = gridPoints[i] + new Vector3(-halfCell, 0, -halfCell);
point4 = TrimToThreeDP(point4);
RaycastHit hit;
//Depending on the blocktype selected, the following functions if statements
//calculate if a point should exist or not
switch(blocktype)
{
case (BlockType.BlockBoth):
{
if (Physics.Raycast(gridPoints[i], Vector3.down, out hit, GroundDistance))
{
//This is the check for below, if it does not hit something, continue to check above
if (hit.distance < GroundDistance)
{
if (checkGroundHits)
{
Debug.Log(hit.distance);
}
//This is the check for above, if it is clear, create a point
if (CheckCellStatus(point1) || CheckCellStatus(point2) || CheckCellStatus(point3) || CheckCellStatus(point4))
{
createPhysicalGridCellObject(prefab, i, false);
}
}
}
break;
}
//This is the check for above, if clear, create a point
case (BlockType.BlockAbove):
{
if (CheckCellStatus(point1) || CheckCellStatus(point2) || CheckCellStatus(point3) || CheckCellStatus(point4))
{
createPhysicalGridCellObject(prefab, i, false);
}
break;
}
//This is the check for below, if clear, create a point
case (BlockType.BlockBelow):
{
if (Physics.Raycast(gridPoints[i], Vector3.down, out hit, GroundDistance))
{
if (hit.distance < GroundDistance)
{
if (checkGroundHits)
{
Debug.Log(hit.distance);
}
createPhysicalGridCellObject(prefab, i, false);
}
}
break;
}
}
}
//This function trims any numbers longer than 3 decimal points, fixing any rounding errors
private Vector3 TrimToThreeDP(Vector3 num)
{
num.x = float.Parse(num.x.ToString("F3"));
num.y = float.Parse(num.y.ToString("F3"));
num.z = float.Parse(num.z.ToString("F3"));
return num;
}
//Filters the cells to whether a cell block should be placed or not
public void CreateAutoCellBlock(GameObject prefab, int i, bool preview)
{
RaycastHit hit;
//Create four points from the centre of each cell
float halfCell = cellSize * 0.5f;
Vector3 point1 = new Vector3(-halfCell, 0, halfCell);
Vector3 point2 = new Vector3(halfCell, 0, halfCell);
Vector3 point3 = new Vector3(halfCell, 0, -halfCell);
Vector3 point4 = new Vector3(-halfCell, 0, -halfCell);
//Checks the points
bool point1Clear = CheckPoint(point1);
bool point2Clear = CheckPoint(point2);
bool point3Clear = CheckPoint(point3);
bool point4Clear = CheckPoint(point4);
ClearAbove(i);
//This function filters for any open space below the grid, thus not creating a cell there
bool CheckPoint(Vector3 cellPoint)
{
if (Physics.Raycast(cells[i] + cellPoint, Vector3.down, out hit, GroundDistance, 1 << groundLayer))
{
//Need to stop the underlaying grid having effect
if (hit.distance < GroundDistance)
{
if (checkGroundHits)
{
Debug.Log(hit.distance);
}
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
switch (blocktype)
{
//Only creates cells if not blocked above or below
case (BlockType.BlockBoth):
{
//Cells are both clear above and below
if (point1Clear && point2Clear && point3Clear && point4Clear && ClearAbove(i))
{
if (gridType != GridType.Points)
{
createPhysicalGridCellObject(prefab, i, false);
if (autoCellBlockPreview)
{
freeCells.Add(prefab.GetComponent<MeshRenderer>());
}
}
else
{
if (autoCellBlockPreview)
{
createPhysicalGridCellObject(prefab, i, false);
freeCells.Add(prefab.GetComponent<MeshRenderer>());
}
}
}
//Cells are blocked either above or below
else
{
if (blockedAboveCellPrefab != null && point1Clear && point2Clear && point3Clear && point4Clear)
{
createPhysicalGridCellObject(blockedAboveCellPrefab, i, true);
}
if (blockedBelowCellPrefab != null && ClearAbove(i))
{
createPhysicalGridCellObject(blockedBelowCellPrefab, i, true);
}
if (!autoCellBlockPreview)
{
//Marks the cells with something in them
//ChangeGridCellStatus(cells[i], null);
ChangeCellStatus(cells[i], gameObject);
}
else
{
//Displays the blocked cells for the preview
if (preview)
{
createPhysicalGridCellObject(prefab, i, true);
}
else
{
//ChangeGridCellStatus(cells[i], null);
ChangeCellStatus(cells[i], gameObject);
}
if (autoCellBlockPreview)
{
blockedCells.Add(prefab.GetComponent<MeshRenderer>());
}
}
}
break;
}
//Only creates cells if not blocked above
case (BlockType.BlockAbove):
{
if (ClearAbove(i))
{
if (gridType != GridType.Points)
{
createPhysicalGridCellObject(prefab, i, false);
if (autoCellBlockPreview)
{
freeCells.Add(prefab.GetComponent<MeshRenderer>());
}
}
else
{
if (autoCellBlockPreview)
{
createPhysicalGridCellObject(prefab, i, false);
freeCells.Add(prefab.GetComponent<MeshRenderer>());
}
}
}
else
{
//If a cell is blocked, place a prefab instead of leaving it empty
if (blockedAboveCellPrefab != null)
{
createPhysicalGridCellObject(blockedAboveCellPrefab, i, true);
}
//Marks the cells with something in them
if (Application.isPlaying)
{
//Marks the cells with something in them
//ChangeGridCellStatus(cells[i], null);
ChangeCellStatus(cells[i], gameObject);
}
else
{
//Displays the blocked cells for the preview
if (preview)
{
createPhysicalGridCellObject(prefab, i, true);
}
else
{
//ChangeGridCellStatus(cells[i], null);
ChangeCellStatus(cells[i], gameObject);
}
if(autoCellBlockPreview)
{
blockedCells.Add(prefab.GetComponent<MeshRenderer>());
}
}
}
break;
}
//Only creates cells if there is no empty space below
case (BlockType.BlockBelow):
{
if (point1Clear && point2Clear && point3Clear && point4Clear)
{
if (gridType != GridType.Points)
{
createPhysicalGridCellObject(prefab, i, false);
if (autoCellBlockPreview)
{
freeCells.Add(prefab.GetComponent<MeshRenderer>());
}
}
else
{
if (autoCellBlockPreview)
{
createPhysicalGridCellObject(prefab, i, false);
freeCells.Add(prefab.GetComponent<MeshRenderer>());
}
}
}
else
{
//If a cell is blocked, place a prefab instead of leaving it empty
if (blockedBelowCellPrefab != null)
{
createPhysicalGridCellObject(blockedBelowCellPrefab, i, true);
}
//Marks the cells with something in them
if (Application.isPlaying)
{
//Marks the cells with something in them
//ChangeGridCellStatus(cells[i], null);
ChangeCellStatus(cells[i], gameObject);
}
else
{
//Displays the blocked cells for the preview
if (preview)
{
createPhysicalGridCellObject(prefab, i, true);
}
else
{
//ChangeGridCellStatus(cells[i], null);
ChangeCellStatus(cells[i], gameObject);
}
if (autoCellBlockPreview)
{
blockedCells.Add(prefab.GetComponent<MeshRenderer>());
}
}
}
break;
}
}
}
private bool ClearAbove(int i)
{
//This section filters for anything blocking above the grid
bool aboveClear = true;
Collider[] colliders = Physics.OverlapBox(cells[i] + new Vector3(0, checkBoxOffset + (aboveCheckBoxHeight * 0.5f), 0), GetCheckBoxSize());
foreach (var item in colliders)
{
//If the hit is not a gridsquare component
if (!item.GetComponent<GridSquare>())
{
int layerInt = item.gameObject.layer;
if (ignoreLayers != (ignoreLayers | (1 << layerInt)))
{
aboveClear = false;
}
}
}
return aboveClear;
}
//This function creates the physical cell object using the given prefab
private void createPhysicalGridCellObject(GameObject prefab, int i, bool blocked)
{
//Checks to see if there is a pointsPrefab to use
if(gridType == GridType.Points && !pointsPrefab)
{
return;
}
//Checks to see if the grid type matches one that uses grid cells
if (gridType != GridType.Points && gridType != GridType.Lines)
{
//Checks to see if a prefab is assigned in the inspector if application is in play mode
if (Application.isPlaying && gridCellPrefab == null)
{
return;
}
}
GameObject gridCellInstance;
switch(gridType)
{
case (GridType.SingleCell):
case (GridType.Chequered):
case (GridType.Simple):
{
CreateSingleGridCellInstance(prefab, i, blocked);
break;
}
case (GridType.Points):
{
if (Application.isPlaying || createInEditor && !autoCellBlockPreview)
{
gridCellInstance = Instantiate(prefab, gridPoints[i], Quaternion.identity);
gridCellInstance.transform.parent = pointsContainer.transform;
//Scales the points
Vector3 gridCellTransform = gridCellInstance.transform.localScale;
gridCellTransform.x = pointRadius;
gridCellTransform.z = pointRadius;
gridCellInstance.transform.localScale = gridCellTransform;
//Names the points
gridCellInstance.name = "GridPoint: " + gridPoints[i];
}
else
{
CreateSingleGridCellInstance(prefab, i, blocked);
}
break;
}
case (GridType.Lines):
{
if (Application.isPlaying || createInEditor && !autoCellBlockPreview)
{
gridCellInstance = Instantiate(prefab, cells[i], Quaternion.identity);
gridCellInstance.transform.parent = linesContainer.transform;
//gridCells.Add(cells[i], gridCellInstance);
//Names the lines
gridCellInstance.name = "GridLine";
}
else
{
CreateSingleGridCellInstance(prefab, i, blocked);
}
break;
}
}
}
private GameObject CreateSingleGridCellInstance(GameObject prefab, int i, bool blocked)
{
GameObject gridCellInstance;
if (prefab != null)
{
gridCellInstance = Instantiate(prefab, cells[i], Quaternion.identity);
}
else
{
gridCellInstance = new GameObject();
}
gridCellInstance.transform.parent = cellContainer.transform;
//Scales the grid cells based on cell size
Vector3 scale = gridCellInstance.transform.localScale;
scale.x *= cellSize;
scale.z *= cellSize;
gridCellInstance.transform.localScale = scale;
//Names the cells
if (!blocked)
{
gridCellInstance.name = "GridCell: " + cells[i];
}
else
{
gridCellInstance.name = "BlockedCell: " + cells[i];
}
if (!autoCellBlockPreview)
{
ChangeGridCellStatus(cells[i], gridCellInstance);
}
else
{
//This adds the cells to relevent Lists to use them later for the Grid autocellblock preview in the editor
if (!blocked)
{
freeCells.Add(gridCellInstance.GetComponent<MeshRenderer>());
}
else
{
blockedCells.Add(gridCellInstance.GetComponent<MeshRenderer>());
}
}
return gridCellInstance;
}
//Determines the size of the checkbox used in the physics calculations
public Vector3 GetCheckBoxSize()
{
checkBoxSize = new Vector3((cellSize * aboveCheckBoxSize) * 0.5f, aboveCheckBoxHeight * 0.5f, (cellSize * aboveCheckBoxSize) * 0.5f);
return checkBoxSize;
}
//This is the core function creating all of the grid points in 3D space
public void CreateGrid()
{
//Creates the initial grid of points
if (gridWidth > 0 && gridHeight > 0)
{
//Double loop to go over grid width and grid height
gridPoints = new Vector3[(gridWidth + 1) * (gridHeight + 1)];
for (int i = 0, x = 0; x <= gridWidth; x++)
{
for (int z = 0; z <= gridHeight; z++)
{
//Add the points into the data structure
gridPoints[i] =
new Vector3(
transform.position.x + x * cellSize,
transform.position.y,
transform.position.z + z * cellSize);
i++;
}
}
}
}
//This uses the core function above to create the cells for the grid
public void CreateGridCells()
{
//Calculates the total number of cells
numCells = gridHeight * gridWidth;
cells = new Vector3[numCells];
if (gridPoints == null)
return;
//Calculates the center of the grid cells from the grid points
for (int i = 1, j = 0; i < gridPoints.Length - gridHeight; i++)
{
if (i % (gridHeight + 1) != 0)
{
cells[j] = gridPoints[i - 1] + new Vector3(cellSize, 0, cellSize) * 0.5f;
float trimmedX = float.Parse(cells[j].x.ToString("F3"));
float trimmedY = float.Parse(cells[j].y.ToString("F3"));
float trimmedZ = float.Parse(cells[j].z.ToString("F3"));
//Add the vectors into the data structure
cells[j] = new Vector3(trimmedX, trimmedY, trimmedZ);
j++;
}
}
}
//Initialises each cell with a value of null to begin with, or in other words, its empty.
public void CreateGridStatus()
{
gridCellsStatus = new Dictionary<Vector3, GameObject>();
for (int i = 0; i < cells.Length; i++)
{
gridCellsStatus.Add(cells[i], null);
};
}
public void CreateGridCellStatus()
{
gridCells = new Dictionary<Vector3, GameObject>();
for (int i = 0; i < cells.Length; i++)
{
gridCells.Add(cells[i], null);
};
}
//This function checks to see if a cell is empty.
public bool CheckCellStatus(Vector3 cellPos)
{
bool isEmpty;
GameObject value;
isEmpty = gridCellsStatus.TryGetValue(cellPos, out value);
//If a given cell position is empty and exists it will return true otherwise it will return false
if (value == null && isEmpty)
{
isEmpty = true;
}
else
{
isEmpty = false;
}
return isEmpty;
}
//This function checks to see if a cell is on the visibly created cells only.
//This is used by the ObjectPlacer Overwrite field.
public bool CheckIfOnGrid(Vector3 cellPos)
{
bool isEmpty;
GameObject value;
gridCellsStatus.TryGetValue(cellPos, out value);
//If a given cell was created
if (value != this.gameObject)
{
isEmpty = false;
}
else
{
isEmpty = true;
}
return isEmpty;
}
//This simply changes the value of the given cell position to something other than null, so the cell is not empty
//You can pass null here to empty it
public void ChangeCellStatus(Vector3 cellPos, GameObject obj)
{
gridCellsStatus[cellPos] = obj;
}
//This adds the given cell prefab to the cells List at its position
public void ChangeGridCellStatus(Vector3 cellPrefabPos, GameObject obj)
{
gridCells[cellPrefabPos] = obj;
}
//Returns the cell GameObject occupied in the gridCells dictionary at the given position
//If nothing is found or position does not exist, it will return null
public GameObject GetCellObject(Vector3 pos)
{
GameObject obj;
gridCells.TryGetValue(pos, out obj);
return obj;
}
//Returns the placed GameObject occupied in the gridCellsStatus dictionary at the given position
//If nothing is found or position does not exist, it will return null
public GameObject GetGridObject(Vector3 pos)
{
GameObject obj;
gridCellsStatus.TryGetValue(pos, out obj);
return obj;
}
/***********The following functions create initialise each grid type*******************/
//Initialises the single cell and chequered grid types
private void CreateSingleCellGrid()
{
//Chequered type with autocellblocking
if(gridType == GridType.Chequered)
{
if(autoCellBlocking)
{
int c = 0;
//Loops through all the cells
for (int i = 0; i < gridWidth; i++)
{
for (int j = 0; j < gridHeight; j++)
{
//This creates the checkered effect
if ((i + j) % 2 == 0)
{
CreateAutoCellBlock(gridCellPrefab, c, false);
}
else
{
if(secondGridCellPrefab)
{
CreateAutoCellBlock(secondGridCellPrefab, c, false);
}
else
{
ChangeGridCellStatus(cells[c], gameObject);
Debug.Log("Assign a second prefab in inspector for checkered pattern");
}
}
c++;
}
}
}
//Chequered type without autocellblocking
else
{
int c = 0;
for (int i = 0; i < gridWidth; i++)
{
for (int j = 0; j < gridHeight; j++)
{
if ((i + j) % 2 == 0)
{
createPhysicalGridCellObject(gridCellPrefab, c, false);
}
else
{
if(secondGridCellPrefab)
{
createPhysicalGridCellObject(secondGridCellPrefab, c, false);
}
else
{
Debug.Log("Assign a second prefab in inspector for checkered pattern");
}
}
c++;
}
}
}
}
if(gridType == GridType.SingleCell)
{
//Single cell type with autocellblocking
if(autoCellBlocking)
{
for (int i = 0; i < cells.Length; i++)
{
CreateAutoCellBlock(gridCellPrefab, i, false);
}
}
//Single cell type without autocellblocking
else
{
for (int i = 0; i < cells.Length; i++)
{
createPhysicalGridCellObject(gridCellPrefab, i, false);
}
}
}
}
//Creates the simple type, creating a new uv'd mesh plane
private void CreateSimpleGrid()
{
//Creates 4 vertices from the gridPoints array
meshVertices = new Vector3[]
{
gridPoints[0] - transform.position,
gridPoints[gridHeight] - transform.position,
gridPoints[gridWidth * (gridHeight + 1)] - transform.position,
gridPoints[gridPoints.Length - 1] - transform.position
};
//Creates the 2 triangles
meshTriangles = new int[]
{
0, 1, 2,
1, 3, 2
};
CreateMesh();
}
//Builds and assigns the vertices and triangles to the mesh
//Also updates the normals
private void CreateMesh()
{
mesh.Clear();
mesh.vertices = meshVertices;
mesh.triangles = meshTriangles;
mesh.name = "SimpleGridMesh";
CreateUVs();
mesh.uv = uvs;
UpdateMaterial();
mesh.RecalculateNormals();
}
//Creates the UV's for the simple grid type
private void CreateUVs()
{
uvs = new Vector2[meshVertices.Length];
uvs[0] = new Vector2(0, 0);
uvs[1] = new Vector2(0, 1);
uvs[2] = new Vector2(1, 0);
uvs[3] = new Vector2(1, 1);
}
//Updates the simple grid types material with tiling equivalent to the grid height and width
private void UpdateMaterial()
{
if(rend) rend.sharedMaterial.mainTextureScale = new Vector2((float)gridWidth / tileX, (float)gridHeight / tileY);
}
//Calculates the Point grid type
private void CreatePointGrid()
{
//With autocellblock
if(autoCellBlocking)
{
for (int i = 0; i < cells.Length; i++)
{
//Does the normal cell blocking without physically creating anything
CreateAutoCellBlock(pointsPrefab, i, false);
}
for (int i = 0; i < gridPoints.Length; i++)
{
//This is the function that goes on to create the points using the already 'available' cells specified in the last for loop
CreatePointObjects(pointsPrefab, i);
}
}
//Without autocellblock
else
{
for (int i = 0; i < gridPoints.Length; i++)
{
createPhysicalGridCellObject(pointsPrefab, i, false);
}
}
}
//Creates the lines type grid
private void CreateLinesGrid()
{
//Offset so the center of the lines is central on the cell, not on grid point
Vector3 offset = new Vector3((-cellSize * 0.5f), 0, (-cellSize * 0.5f));
//Calculates each vertex position of the lines
linesVertices = new Vector3[]
{
new Vector3(linesThickness, 0, linesThickness) + offset,
new Vector3(-linesThickness, 0, -linesThickness) + offset,
new Vector3(-linesThickness, 0, (cellSize + linesThickness)) + offset,
new Vector3(linesThickness, 0, (cellSize - linesThickness)) + offset,
new Vector3((cellSize + LinesThickness), 0, (cellSize + LinesThickness)) + offset,
new Vector3((cellSize - LinesThickness), 0, (cellSize - LinesThickness)) + offset,
new Vector3((cellSize + linesThickness), 0, -linesThickness) + offset,
new Vector3((cellSize - linesThickness), 0, linesThickness) + offset
};
//Triangle vertex order
linesTriangles = new int[]
{
0, 1, 2,
0, 2, 3,
2, 4, 3,
3, 4, 5,
4, 6, 5,
5, 6, 7,
7, 6, 1,
0, 7, 1
};
//Appends everything to the mesh
linesMesh.Clear();
linesMesh.vertices = linesVertices;
linesMesh.triangles = linesTriangles;
linesMesh.name = "LinesMesh";
line = new GameObject("Line");
line.AddComponent<MeshFilter>().mesh = linesMesh;
MeshRenderer ownMR = GetComponent<MeshRenderer>();
MeshRenderer lineMR = line.AddComponent<MeshRenderer>();
lineMR.sharedMaterial = ownMR.sharedMaterial;
lineMR.shadowCastingMode = ownMR.shadowCastingMode;
lineMR.receiveShadows = ownMR.receiveShadows;
lineMR.allowOcclusionWhenDynamic = ownMR.allowOcclusionWhenDynamic;
//Creates the lines only on available cells
for (int i = 0; i < cells.Length; i++)
{
if (autoCellBlocking)
{
CreateAutoCellBlock(line, i, false);
}
//Creates the lines on all cells
else
{
createPhysicalGridCellObject(line, i, false);
}
}
//Removes the original line created for instantiating
if(createInEditor)
{
DestroyImmediate(line);
}
else
{
Destroy(line);
}
}
//Changes the size and position of the collider based on cellSize and the grid width and height
private void SetColliderSize()
{
meshCollider.size = new Vector3(gridWidth * cellSize, colliderThickness, gridHeight * cellSize);
meshCollider.center = new Vector3((float)gridWidth * cellSize / 2, (colliderThickness / 2), (float)gridHeight * cellSize / 2);
}
//These functions initialise all the data for creating the grids points, so they can then be previewed in the viewport
private void OnValidate()
{
if(!Application.isPlaying)
{
CreateGrid();
CreateGridCells();
}
}
//Creates the viewport preview of some of the basic settings
private void OnDrawGizmos()
{
Gizmos.color = Color.red;
//If you move the grid, reinitialise its points
if (transform.hasChanged)
{
CreateGrid();
CreateGridCells();
transform.hasChanged = false;
}
//Wont run at build time
#if UNITY_EDITOR
//These two functions are used for debugging, they will impact performance if used on large grids
if (drawGridPositions)
{
//Draw the points the grid is made up from
DrawPointPositions();
}
if(drawCellPositions)
{
//Draw the cell coordinates in world space
DrawCellPositions();
}
//Previews the autocellblocking setup features
if (autoCellBlocking)
{
if (showAboveBoxColliders)
{
//Draw the autocellblock physics check boxes
DrawAutoCellBlockingBoxes();
}
if(showBelowRays)
{
//Draw the rays to check for the ground object
DrawAutoCellBlockingRays();
}
}
//Draws the grid gizmo
if(!drawSimple)
{
DrawLines();
}
else
{
DrawSimpleLines();
}
#endif
}
//Draws only the outside lines of the grid, useful if your grid is extremely large to speed up scene view
private void DrawSimpleLines()
{
Gizmos.DrawLine(gridPoints[0], gridPoints[gridHeight]);
Gizmos.DrawLine(gridPoints[gridHeight], gridPoints[gridPoints.Length - 1]);
Gizmos.DrawLine(gridPoints[gridPoints.Length - 1], gridPoints[gridPoints.Length - 1 - gridHeight]);
Gizmos.DrawLine(gridPoints[0], gridPoints[gridPoints.Length - 1 - gridHeight]);
}
//Draws a line from each grid point extending as far as the ground distance, this is how far the physics check goes
private void DrawAutoCellBlockingRays()
{
for (int i = 0; i < gridPoints.Length; i++)
{
Gizmos.DrawLine(gridPoints[i], gridPoints[i] + new Vector3(0, -GroundDistance, 0));
}
}
//Draws a box from the center of each cell
private void DrawAutoCellBlockingBoxes()
{
if (cells != null)
{
for (int i = 0; i < cells.Length; i++)
{
Gizmos.DrawWireCube(cells[i] + new Vector3(0, checkBoxOffset + (aboveCheckBoxHeight * 0.5f), 0), new Vector3(cellSize * aboveCheckBoxSize, aboveCheckBoxHeight, cellSize * aboveCheckBoxSize));
}
}
}
//Wont run at build time
#if UNITY_EDITOR
//Draws the cell position as a Vector3
private void DrawCellPositions()
{
for (int i = 0; i < numCells; i++)
{
Handles.Label(cells[i], cells[i].ToString("F3"));
}
}
//Draws the point positions as a Vector3
private void DrawPointPositions()
{
for (int i = 0; i < gridPoints.Length; i++)
{
Handles.Label(gridPoints[i], new Vector2(gridPoints[i].x, gridPoints[i].z).ToString("F3"));
}
}
#endif
//Draws the Lines of the grid
private void DrawLines()
{
if (gridHeight > 0 && gridWidth > 0)
{
//Z lines
for (int x = 0; x < gridWidth + 1; x++)
{
for (int z = 0; z < gridHeight; z++)
{
Gizmos.DrawLine(gridPoints[x * (gridHeight + 1) + z], gridPoints[x * (gridHeight + 1) + z + 1]);
}
}
//X lines
for (int z = 0; z < gridHeight + 1; z++)
{
for (int x = 0; x < gridWidth; x++)
{
Gizmos.DrawLine(gridPoints[z * gridWidth + x], gridPoints[z * gridWidth + (gridHeight + 1) + x]);
}
}
}
}
//Useful function to call to get a list of all of the currently placed objects on this grid
public List<GameObject> GetCellsDictionary()
{
List<GameObject> allPlacedObjects = new List<GameObject>();
foreach (KeyValuePair<Vector3, GameObject> entry in gridCellsStatus)
{
//Debug.Log(entry);
allPlacedObjects.Add(entry.Value);
}
return allPlacedObjects;
}
//Useful function to call to get a list of all of the currently placed objects on this grid
public List<GameObject> GetGridCellsDictionary()
{
List<GameObject> allPlacedObjects = new List<GameObject>();
foreach (KeyValuePair<Vector3, GameObject> entry in gridCells)
{
//Debug.Log(entry);
allPlacedObjects.Add(entry.Value);
}
return allPlacedObjects;
}
}