using System;
using Core.Utilities;
using KTGMGemClient;
using TowerDefense.Level;
using TowerDefense.UI.HUD;
using UnityEngine;
using UnityEngine.UI;
namespace TowerDefense.Towers.Placement
{
///
/// A tower placement location made from a grid.
/// Its origin is centered in the middle of the lower-right cell. It can be oriented in any direction
///
[RequireComponent(typeof(BoxCollider))]
public class TowerPlacementGridEndless : MonoBehaviour, IPlacementArea
{
public static float GRID_OPENCASH = 100;
///
/// Prefab used to visualise the grid.
/// 如果在游戏内并不需要Grid显示或者用其它的方式显示,则可以去掉这个数据。
///
public PlacementTile placementTilePrefab;
///
/// Visualisation prefab to instantiate on mobile platforms
///
public PlacementTile placementTilePrefabMobile;
///
/// 塔位血条对应的UI界面.
///
public GameObject towerBloodUIPrefab;
///
/// 等待购买开启对应按钮.
///
public Button waitBuyBtnPrefab;
///
/// 最后一行格子与前一行格子之间的空位长度.
///
public float gridFreePos;
public float gridFreePos2;
///
/// The dimensions of the grid
///
public IntVector2 dimensions;
///
/// Size of the edge of a cell
///
[Tooltip("The size of the edge of one grid cell for area. Should match the physical grid size of towers")]
public float gridSize = 1;
///
/// Inverted grid size, to multiply with
///
private float m_InvGridSize;
///
/// Array of available cells
///
private bool[,] m_AvailableCells;
///
/// 每一个格子的对应的类型。不同的类型可以转化,但可合成的类型不能转化。
/// 初始化的时候会根据配置数据来初始化不同的格子状态
///
private PlacementGridType[,] m_arrGridType;
///
/// 等待开启塔位的按钮
///
private EndlessTowerGridOpen[,] m_arrTGO;
private float[,] m_arrCoinGenTime;
///
/// 每一个Tile格子的中心店的世界坐标
///
private Vector2[,] arrGridCentPos;
///
/// 攻击塔位对应的UI位置信息.
///
private Vector2[,] m_arrTowerBloodUIPos;
///
/// 所有塔位血条UI
///
private TowerBloodVis[,] arrTowerBloodUi;
///
/// Array of s
///
private PlacementTile[,] m_Tiles;
///
/// 攻击塔行数,i.e. 前两排是攻击塔位
///
///
public int AttackRowNumbers { get; } = 2;
///
/// 攻击塔位对应的子弹UI位置信息.
///
private Vector2[,] m_arrTowerBulletUIPos;
private BulletUICtl[,] arrTowerBulletUi;
private EnergyUICtl[,] arrTowerEnergyUi;
private ParticleSystem[,] arrTowerEnergyEffect;
///
/// 充能特效对应的Prefab.
///
public ParticleSystem energyEffectPrefab;
///
/// 此位置上塔对应的子弹充能Prefab.塔放置到当前的塔位后,如果是对应的塔防类型,需要把
/// 相应的界面指针传到塔防的数据结构内。
///
public GameObject towerBulletUIPrefab;
///
/// 充能条对应的界面
///
public GameObject towerEnergyUIPrefab;
///
/// Converts a location in world space into local grid coordinates.
///
/// indicating world space coordinates to convert.
/// indicating size of object to center.
/// containing the grid coordinates corresponding to location.
public IntVector2 WorldToGrid(Vector3 worldLocation, IntVector2 sizeOffset)
{
Vector3 localLocation = transform.InverseTransformPoint(worldLocation);
// Scale by inverse grid size
localLocation *= m_InvGridSize;
// Offset by half size
var offset = new Vector3(sizeOffset.x * 0.5f, 0.0f, sizeOffset.y * 0.5f);
localLocation -= offset;
int xPos = Mathf.RoundToInt(localLocation.x);
int yPos = Mathf.RoundToInt(localLocation.z);
return new IntVector2(xPos, yPos);
}
public IntVector2 getdimsize()
{
return dimensions;
}
///
/// 实现引用.
///
public bool opponent { get; set; }
public bool isOpponent()
{
return opponent;
}
///
/// 获取对应位置的充能子弹界面指针.
///
///
///
public BulletUICtl GetBulletUICtl(int x, int y)
{
return arrTowerBulletUi[x, 3 - y];
}
///
/// 获取对应位置的能量条界面指针.
///
///
///
public EnergyUICtl GetEnergyUICtl(int x, int y)
{
return arrTowerEnergyUi[x, 3 - y];
}
///
/// 获取一个可以放置塔防的位置.
///
///
public IntVector2 getFreePos(int xdim, int ydim, bool forceGet = false)
{
IntVector2 resvec = new IntVector2();
int subval = AttackRowNumbers;
if (forceGet)
subval = 0;
// Range产生的随机数是 [min, max),Y值再减2是因为最前面两排是战斗塔位。
int maxXdim = dimensions.x - xdim + 1;
int maxYdim = (dimensions.y - ydim + 1) - subval;
resvec.x = UnityEngine.Random.Range(0, maxXdim);
resvec.y = UnityEngine.Random.Range(0, maxYdim);
TowerFitStatus tfs = Fits(resvec, new IntVector2(xdim, ydim));
// 处理ForceGet
bool legalVal = (tfs == TowerFitStatus.Fits);
if (legalVal && forceGet)
{
if (m_arrGridType[resvec.x, resvec.y] != PlacementGridType.EGridOpen)
legalVal = false;
}
if (legalVal)
{
return resvec;
}
else
{
int looptime = 0;
while (looptime < 10)
{
looptime++;
resvec.x = UnityEngine.Random.Range(0, maxXdim);
resvec.y = UnityEngine.Random.Range(0, maxYdim);
tfs = Fits(resvec, new IntVector2(xdim, ydim));
// 处理forceGet.
if (forceGet)
{
if (m_arrGridType[resvec.x, resvec.y] != PlacementGridType.EGridOpen)
continue;
}
if (tfs == TowerFitStatus.Fits) return resvec;
}
// 循环超过10次,则直接寻找空位,找不到则返回错误.
for (int x = 0; x < maxXdim; x++)
{
for (int y = 0; y < maxYdim; y++)
{
if (!m_AvailableCells[x, y])
{
// 处理ForceGet
if (forceGet)
{
if (m_arrGridType[x, y] != PlacementGridType.EGridOpen)
continue;
}
resvec.x = x;
resvec.y = y;
return resvec;
}
}
}
}
return new IntVector2(-1, -1);
}
///
/// 判断是否是一个空置的攻击位
///
///
///
///
public bool isFreeAtackPos(int x, int y)
{
if (m_AvailableCells[x, y])
return false;
if (m_arrGridType[x, y] == PlacementGridType.EGridOpen)
return true;
return false;
}
///
/// 是否是等待购买的攻击塔位.
///
///
///
///
public bool isWaitBuyGrid(int x, int y)
{
if (m_AvailableCells[x, y])
return false;
if (m_arrGridType[x, y] == PlacementGridType.EGridWaitBuy)
return true;
return false;
}
///
/// 开启金币生产模式
///
public void startCoinGenMode()
{
m_arrCoinGenTime = new float[dimensions.x, AttackRowNumbers];
int ty = dimensions.y - 1;
for (int tx = 0; tx < dimensions.x; tx++)
{
for (int y = 0; y < AttackRowNumbers; ++y)
{
if (m_arrGridType[tx, ty - y] == PlacementGridType.EGridOpen || m_arrGridType[tx, ty - y] == PlacementGridType.EGridCombo)
m_arrCoinGenTime[tx, y] = 0;
else
m_arrCoinGenTime[tx, y] = -1f;
}
}
}
void Update()
{
if (m_arrCoinGenTime == null || !EndlessUIStart.instance.IsGameRunning) return;
float delta = Time.deltaTime;
float timePe = JsonDataCenter.GOLD_TIME / 1000.0f;
// 处理每一开启的格子,用于金币数据增加:
for (int ti = 0; ti < dimensions.x; ti++)
{
for (int y = 0; y < AttackRowNumbers; ++y)
{
// 是否是可以增加金币的格子:
if (m_arrCoinGenTime[ti, y] < 0) continue;
// 时间判断.
if (m_arrCoinGenTime[ti, y] >= 0)
{
m_arrCoinGenTime[ti, y] += delta;
if (m_arrCoinGenTime[ti, y] > timePe)
{
m_arrCoinGenTime[ti, y] -= timePe;
// 增加金币:
EndlessLevelManager.instance.Currency.AddCurrency(JsonDataCenter.GOLD_ADD);
}
}
}
}
}
///
/// 设置格子为合成状态。
///
///
///
///
public bool SetComboGrid(int x, int y)
{
if (m_arrGridType[x, y] == PlacementGridType.EGridOpen)
{
m_arrGridType[x, y] = PlacementGridType.EGridCombo;
return true;
}
else return false;
}
///
/// 设置某一个格子为已破坏塔位。
///
///
///
///
public bool SetDestroyedGrid(int x, int y)
{
// 释放掉界面显示
if (m_arrGridType[x, y] == PlacementGridType.EGridWaitBuy)
{
if (m_arrTGO[x, y])
{
m_arrTGO[x, y].Release();
m_arrTGO[x, y] = null;
}
}
// 任何情况下,都可以破坏,没有购买,上面有塔,都得破坏
m_arrGridType[x, y] = PlacementGridType.EGridDestroyed;
if (arrTowerBloodUi[x, dimensions.y - 1 - y] != null)
arrTowerBloodUi[x, dimensions.y - 1 - y].gameObject.SetActive(false);
m_Tiles[x, y].SetTileType(PlacementGridType.EGridDestroyed);
return true;
}
///
/// Returns the world coordinates corresponding to a grid location.
/// 把格子坐标转换成世界坐标
///
/// The coordinate in grid space
/// indicating size of object to center.
/// Vector3 containing world coordinates for specified grid cell.
public Vector3 GridToWorld(IntVector2 gridPosition, IntVector2 sizeOffset)
{
float freePos = 0;
if (gridPosition.y == 3)
freePos = gridFreePos;
else if (gridPosition.y == 2)
freePos = gridFreePos2;
// Calculate scaled local position
Vector3 localPos = new Vector3(gridPosition.x + (sizeOffset.x * 0.5f), 0, gridPosition.y + (sizeOffset.y * 0.5f) + freePos) *
gridSize;
return transform.TransformPoint(localPos);
}
///
/// Tests whether the indicated cell range represents a valid placement location.
///
/// The grid location
/// The size of the item
/// Whether the indicated range is valid for placement.
public TowerFitStatus Fits(IntVector2 gridPos, IntVector2 size)
{
// If the tile size of the tower exceeds the dimensions of the placement area, immediately decline placement.
if ((size.x > dimensions.x) || (size.y > dimensions.y))
{
return TowerFitStatus.OutOfBounds;
}
IntVector2 extents = gridPos + size;
// Out of range of our bounds
if ((gridPos.x < 0) || (gridPos.y < 0) ||
(extents.x > dimensions.x) || (extents.y > dimensions.y))
{
return TowerFitStatus.OutOfBounds;
}
// Ensure there are no existing towers within our tile silhuette.
for (int y = gridPos.y; y < extents.y; y++)
{
for (int x = gridPos.x; x < extents.x; x++)
{
if (m_AvailableCells[x, y])
{
return TowerFitStatus.Overlaps;
}
}
}
// If we've got far, we've got a valid position.
return TowerFitStatus.Fits;
}
///
/// Sets a cell range as being occupied by a tower.
///
/// The grid location
/// The size of the item
public void Occupy(IntVector2 gridPos, IntVector2 size)
{
IntVector2 extents = gridPos + size;
// Validate the dimensions and size
if ((size.x > dimensions.x) || (size.y > dimensions.y))
{
throw new ArgumentOutOfRangeException("size", "Given dimensions do not fit in our grid");
}
// Out of range of our bounds
if ((gridPos.x < 0) || (gridPos.y < 0) ||
(extents.x > dimensions.x) || (extents.y > dimensions.y))
{
Debug.Log("目标GridPos is:" + gridPos.x + "," + gridPos.y + "," + size.x + "," + size.y);
throw new ArgumentOutOfRangeException("gridPos", "Given footprint is out of range of our grid");
}
// 填充对应格子为占用状态
for (int y = gridPos.y; y < extents.y; y++)
{
for (int x = gridPos.x; x < extents.x; x++)
{
m_AvailableCells[x, y] = true;
}
}
}
///
/// Removes a tower from a grid, setting its cells as unoccupied.
///
/// The grid location
/// The size of the item
public void Clear(IntVector2 gridPos, IntVector2 size)
{
IntVector2 extents = gridPos + size;
// Validate the dimensions and size
if ((size.x > dimensions.x) || (size.y > dimensions.y))
{
throw new ArgumentOutOfRangeException("size", "Given dimensions do not fit in our grid");
}
// Out of range of our bounds
if ((gridPos.x < 0) || (gridPos.y < 0) ||
(extents.x > dimensions.x) || (extents.y > dimensions.y))
{
throw new ArgumentOutOfRangeException("gridPos", "Given footprint is out of range of our grid");
}
// 清空对应格子为占用状态
for (int y = gridPos.y; y < extents.y; y++)
{
for (int x = gridPos.x; x < extents.x; x++)
{
m_AvailableCells[x, y] = false;
}
}
}
///
/// Initialize values
///
protected virtual void Awake()
{
ResizeCollider();
// Initialize empty bool array (defaults are false, which is what we want)
m_AvailableCells = new bool[dimensions.x, dimensions.y];
opponent = false;
}
///
/// 预计算每一个塔位格子的屏幕坐标。
///
void Start()
{
// 初始化塔位类型.
initTileGridType();
// Precalculate inverted grid size, to save a division every time we translate coords
m_InvGridSize = 1 / gridSize;
SetUpGrid();
// 初始化格子对应的屏幕坐标数据 延迟执行
Invoke("preCalculateGridUIPos", 0.3f);
//preCalculateGridUIPos();
}
///
/// 预计算塔位格子对应的屏幕坐标以及塔位格子的屏幕尺寸
/// WORK START: 计算屏幕坐标,然后开搞屏幕相关的内容。下午要把塔位上显示界面搞出来。
/// WORK START: 为什么OppoGrid对应的屏幕坐标不对?
///
void preCalculateGridUIPos()
{
arrGridCentPos = new Vector2[dimensions.x, dimensions.y];
Vector3 targetPos = GridToWorld(new IntVector2(0, 0), new IntVector2(1, 1));
if (!ViewPortAdj.instance.bAdjViewPort)
ViewPortAdj.instance.adjViewportRect();
float size = 10.29f;
for (int x = 0; x < dimensions.x; ++x)
{
for (int y = 0; y < dimensions.y; ++y)
{
arrGridCentPos[x, y].x = targetPos.x + x * size;
arrGridCentPos[x, y].y = targetPos.y + y * size - 44.5f;
}
}
// 血条位置的设定
PreCalculateTowerBloodUi();
m_arrTGO = new EndlessTowerGridOpen[dimensions.x, dimensions.y];
for (int x = 0; x < dimensions.x; ++x)
{
for (int y = dimensions.y - AttackRowNumbers; y < dimensions.y; ++y)
{
if (m_arrGridType[x, y] != PlacementGridType.EGridWaitBuy) continue;
GameObject container = GameObject.Find("BuyButtonContainer");
Button buyButton = Instantiate(waitBuyBtnPrefab);
buyButton.transform.SetParent(container.transform);
Vector3 pos = buyButton.transform.position;
pos.x = arrGridCentPos[x, y].x;
pos.z = arrGridCentPos[x, y].y;
pos.y = 30;
buyButton.transform.position = pos;
buyButton.transform.localRotation = Quaternion.identity;
buyButton.transform.localScale = Vector3.one;
// 设置按钮对应的点击功能
EndlessTowerGridOpen tgo = buyButton.GetComponent();
if (tgo)
{
tgo.SetBuyBtnInfo(x, y, this);
tgo.cashText.SetText(TowerPlacementGrid.GRID_OPENCASH_SELF.ToString());
m_arrTGO[x, y] = tgo;
}
}
}
}
///
/// 设置某一个位置的血条.
///
/// Tower在X方向上的位置信息
///
public void setTowerPosHealth(int ix, float health)
{
if (m_arrGridType[ix, dimensions.y - 1] == PlacementGridType.EGridDestroyed && m_arrGridType[ix, dimensions.y - 2] == PlacementGridType.EGridDestroyed)
return;
int index = 0;
if (m_arrGridType[ix, dimensions.y - 1] == PlacementGridType.EGridDestroyed)
index = 1;
// todo
if (arrTowerBloodUi[ix, index] != null)
{
if (health < 1.0f)
{
arrTowerBloodUi[ix, index].gameObject.SetActive(true);
arrTowerBloodUi[ix, index].SetHealthScale(health);
}
}
}
///
/// 处理Tower血量的UI界面
///
protected void PreCalculateTowerBloodUi()
{
// 处理攻击塔位的血条位置信息.
m_arrTowerBloodUIPos = new Vector2[dimensions.x, AttackRowNumbers];
// 前两排是攻击塔位
arrTowerBloodUi = new TowerBloodVis[dimensions.x, AttackRowNumbers];
int dy = dimensions.y - 1;
// 处理攻击塔位对应的血条
m_arrTowerBulletUIPos = new Vector2[dimensions.x, AttackRowNumbers];
arrTowerBulletUi = new BulletUICtl[dimensions.x, AttackRowNumbers];
arrTowerEnergyUi = new EnergyUICtl[dimensions.x, AttackRowNumbers];
arrTowerEnergyEffect = new ParticleSystem[dimensions.x, AttackRowNumbers];
for (int x = 0; x < dimensions.x; x++)
{
for (int y = 0; y < AttackRowNumbers; ++y)
{
m_arrTowerBloodUIPos[x, y].x = arrGridCentPos[x, dy - y].x;
m_arrTowerBloodUIPos[x, y].y = arrGridCentPos[x, dy - y].y;
m_arrTowerBulletUIPos[x, y].x = arrGridCentPos[x, dy - y].x;
m_arrTowerBulletUIPos[x, y].y = arrGridCentPos[x, dy - y].y;
// 现在PVE基地不需要血条
GameObject img = Instantiate(towerBloodUIPrefab);
GameObject container = GameObject.Find("BuyButtonContainer");
img.transform.SetParent(container.transform);
Vector3 tpos = img.transform.position;
tpos.x = m_arrTowerBloodUIPos[x, y].x;
tpos.z = m_arrTowerBloodUIPos[x, y].y + 4.2f - y * 1.66f;
tpos.y = 30f;
img.transform.position = tpos;
img.transform.localScale = Vector3.one;
img.transform.localRotation = Quaternion.identity;
TowerBloodVis tbv = img.GetComponent();
arrTowerBloodUi[x, y] = tbv;
tbv.gameObject.SetActive(false);
img = Instantiate(towerBulletUIPrefab);
img.transform.SetParent(container.transform, true);
tpos = img.transform.position;
tpos.x = m_arrTowerBulletUIPos[x, y].x + 4.2f;
tpos.z = m_arrTowerBulletUIPos[x, y].y - 0.5f;
tpos.y = 30f;
img.transform.position = tpos;
img.transform.localScale = Vector3.one;
img.transform.localRotation = Quaternion.identity;
BulletUICtl buc = img.GetComponent();
arrTowerBulletUi[x, y] = buc;
buc.gameObject.SetActive(false);
// 把充能条也创建出来了.
img = Instantiate(towerEnergyUIPrefab);
img.transform.SetParent(container.transform);
tpos = img.transform.position;
tpos.x = m_arrTowerBulletUIPos[x, y].x + 4.2f;
tpos.z = m_arrTowerBulletUIPos[x, y].y - 0.5f;
tpos.y = 30f;
img.transform.position = tpos;
img.transform.localScale = Vector3.one;
img.transform.localRotation = Quaternion.identity;
EnergyUICtl euc = img.GetComponent();
arrTowerEnergyUi[x, y] = euc;
euc.gameObject.SetActive(false);
// 设置播放特效对应的3D坐标:
Vector3 vpos = GridToWorld(new IntVector2(x, dy - y), new IntVector2(2, 1));
vpos.x -= (gridSize / 2.0f);
vpos.y += 5.0f;
arrTowerEnergyEffect[x, y] = Instantiate(energyEffectPrefab);
arrTowerEnergyEffect[x, y].transform.position = vpos;
arrTowerEnergyEffect[x, y].Stop();
}
}
}
public void updateGridOpenCoin(int ix, int iy)
{
GRID_OPENCASH = Mathf.Floor(GRID_OPENCASH * 1.2f);
for (int x = 0; x < dimensions.x; x++)
{
for (int y = 0; y < dimensions.y; y++)
{
if (m_arrGridType[x, y] != PlacementGridType.EGridWaitBuy)
continue;
if (m_arrTGO[x, y] != null)
{
m_arrTGO[x, y].cashText.SetText(GRID_OPENCASH.ToString());
}
}
}
}
///
/// 是否有已开启的可放置攻击位置。
///
///
public bool hasFreeAttackPos()
{
int iy = dimensions.y - 1;
for (int ix = 0; ix < dimensions.x; ix++)
{
for (int y = iy; y > dimensions.y - AttackRowNumbers; --y)
{
if (m_arrGridType[ix, y] == PlacementGridType.EGridOpen)
return true;
}
}
return false;
}
///
/// 购买塔位.
///
///
///
public void BuyTowerGrid(int ix, int iy)
{
// 更新核心的数据信息
if (m_arrGridType[ix, iy] != PlacementGridType.EGridWaitBuy) return;
m_arrGridType[ix, iy] = PlacementGridType.EGridOpen;
m_AvailableCells[ix, iy] = false;
m_Tiles[ix, iy].SetTileType(PlacementGridType.EGridOpen);
// 开启金币获取模式.
m_arrCoinGenTime[ix, dimensions.y - 1 - iy] = 0;
}
///
/// 购买对应的待购攻击塔位.
///
///
///
///
public bool buyWaitBuyGrid(int x, int y)
{
EndlessTowerGridOpen tgo = m_arrTGO[x, y];
if (tgo)
tgo.OnClick();
else
return false;
return true;
}
///
/// 初始化当前塔防位的类型信息.
///
void initTileGridType()
{
m_arrGridType = new PlacementGridType[dimensions.x, dimensions.y];
int sy = dimensions.y - 1;
for (int tx = 0; tx < dimensions.x; tx++)
{
m_arrGridType[tx, sy] = PlacementGridType.EGridWaitBuy;
m_arrGridType[tx, sy - 1] = PlacementGridType.EGridWaitBuy;
}
// 设置塔位默认开启,后面需要根据配置来
m_arrGridType[2, 3] = PlacementGridType.EGridOpen;
++GameConfig.EndlessOpenAttackTowerCount;
}
///
/// 在指定的位置播放充能成功的特效.
///
///
///
/// 是播放还是停止播放
public void PlayEnergyEffect(int x, int y, bool play = true)
{
int dy = dimensions.y - 1 - y;
if (!arrTowerEnergyEffect[x, dy]) return;
if (play)
arrTowerEnergyEffect[x, dy].Play();
else
arrTowerEnergyEffect[x, dy].Stop();
}
///
/// Set collider's size and center
///
void ResizeCollider()
{
var myCollider = GetComponent();
Vector3 size = new Vector3(dimensions.x, 0, dimensions.y) * gridSize;
myCollider.size = size;
// Collider origin is our bottom-left corner
myCollider.center = size * 0.5f;
}
///
/// Instantiates Tile Objects to visualise the grid and sets up the
///
protected void SetUpGrid()
{
PlacementTile tileToUse;
#if UNITY_STANDALONE
tileToUse = placementTilePrefab;
#else
tileToUse = placementTilePrefabMobile;
#endif
if (tileToUse != null)
{
// Create a container that will hold the cells.
var tilesParent = new GameObject("Container");
tilesParent.transform.parent = transform;
tilesParent.transform.localPosition = Vector3.zero;
tilesParent.transform.localRotation = Quaternion.identity;
m_Tiles = new PlacementTile[dimensions.x, dimensions.y];
// 无尽模式上面两排都是可上阵的,所以这里-2
for (int y = dimensions.y - 2; y < dimensions.y; y++)
{
for (int x = 0; x < dimensions.x; x++)
{
Vector3 targetPos = GridToWorld(new IntVector2(x, y), new IntVector2(1, 1));
targetPos.z -= 1.0f;
PlacementTile newTile = Instantiate(tileToUse);
newTile.transform.parent = tilesParent.transform;
newTile.transform.position = targetPos;
newTile.transform.localRotation = Quaternion.identity;
m_Tiles[x, y] = newTile;
newTile.SetTileType(m_arrGridType[x, y]);
}
}
}
}
#if UNITY_EDITOR
///
/// On editor/inspector validation, make sure we size our collider correctly.
/// Also make sure the collider component is hidden so nobody can mess with its settings to ensure its integrity.
/// Also communicates the idea that the user should not need to modify those values ever.
///
void OnValidate()
{
// Validate grid size
if (gridSize <= 0)
{
Debug.LogError("Negative or zero grid size is invalid");
gridSize = 1;
}
// Validate dimensions
if (dimensions.x <= 0 ||
dimensions.y <= 0)
{
Debug.LogError("Negative or zero grid dimensions are invalid");
dimensions = new IntVector2(Mathf.Max(dimensions.x, 1), Mathf.Max(dimensions.y, 1));
}
// Ensure collider is the correct size
ResizeCollider();
GetComponent().hideFlags = HideFlags.HideInInspector;
}
///
/// Draw the grid in the scene view
///
void OnDrawGizmos()
{
Color prevCol = Gizmos.color;
Gizmos.color = Color.yellow;
Matrix4x4 originalMatrix = Gizmos.matrix;
Gizmos.matrix = transform.localToWorldMatrix;
// Draw local space flattened cubes
for (int y = 0; y < dimensions.y; y++)
{
float freePos = 0;
if ((y > 0) && (y == dimensions.y - 1))
freePos = gridFreePos;
else if (y > 0 && y == dimensions.y - 2)
freePos = gridFreePos2;
for (int x = 0; x < dimensions.x; x++)
{
var position = new Vector3((x + 0.5f) * gridSize, 0, (y + 0.5f) * gridSize + freePos);
Gizmos.DrawWireCube(position, new Vector3(gridSize, 0, gridSize));
}
}
Gizmos.matrix = originalMatrix;
Gizmos.color = prevCol;
// Draw icon too, in center of position
Vector3 center = transform.TransformPoint(new Vector3(gridSize * dimensions.x * 0.5f,
1,
gridSize * dimensions.y * 0.5f));
Gizmos.DrawIcon(center, "build_zone.png", true);
}
#endif
}
}