using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// Grids list.
/// This script, having m_pItemPrefab and m_pGridPrefab attached
/// allows to manage the scroll dynamically (via multiple grid components)
/// </summary>
[System.Serializable]
public class ScrollGridsView : MonoBehaviour
{
/// <summary>
/// Data about Grid
/// Only its gameObject for now
/// </summary>
[System.Serializable]
private class GridData
{
public UIGrid grid;
public Vector3 m_vPosition
{
get {return grid.gameObject.transform.localPosition;}
set {grid.gameObject.transform.localPosition = value;}
}
}
//item prefab to be created in the grid
public GameObject m_pItemPrefab;
//prefab of the UIGrid, that will contain m_pItemPrefab-s in quantity of m_iGridItemsCount
public GameObject m_pGridPrefab;
//items quantity inside the each grid
public int m_iGridItemsCount = 12;
//existing grid index and its data
private Dictionary
<int, GridData
> _grids
= new Dictionary
<int, GridData
>();
//how close grid border to the view the next grid should be created
//the larger the TRESHOLD, the earlier the grid will be created
public int m_iGridCreateTreshold = 100;
//When new grid is created, the grids, standing by distance of _gridDestroyRange will be destroyed
public int m_iGridDestroyRange = 2;
//Todo: generic
protected int _itemsCount;
//view position parameters
private Vector3 _startingPosition;
private float _clipRange;
private UIGrid _grid;
private UIPanel _panel;
private Transform _transform;
//how many items in line (considering UIGrid maxPerLine prop.)
private int _gridItemsLen;
//width of each grid
private float _gridLen;
//the first created grid,
//other grids positions will be counted from it
private bool firstGridExists = false;
private int _firstGridIndx = 0;
//this is set on Awake
private bool Horisontal = true;
private Vector3 _vGridOffest;
/// <summary>
/// Get UIPanel and UIGrid properties
/// </summary>
void Awake()
{
//save transform for optimization
_transform = transform;
//set if list is horisontal
UIDraggablePanel dragPanel = gameObject.GetComponent<UIDraggablePanel>();
Horisontal = dragPanel.scale.x > 0;
_panel = gameObject.GetComponent<UIPanel>();
_startingPosition
= transform
.localPosition + new Vector3
(_panel
.clipRange.x, _panel
.clipRange.y, 0f
); _clipRange = (Horisontal)? _panel.clipRange.z : _panel.clipRange.w;
//round up
_grid = m_pGridPrefab.GetComponent<UIGrid>();
if(_grid.maxPerLine != 0)
_gridItemsLen = (m_iGridItemsCount + _grid.maxPerLine - 1)/_grid.maxPerLine;
else
_gridItemsLen = m_iGridItemsCount;
_gridLen = _gridItemsLen * ((Horisontal)? _grid.cellWidth : _grid.cellHeight);
_vGridOffest
=(Horisontal
)? new Vector3
(_gridLen,
0,
0) : new Vector3
(0,
-_gridLen,
0); }
/// <summary>
/// Check if user scrolled to the border of the grid
/// </summary>
void LateUpdate ()
{
if (!Application.isPlaying) return;
//delta is panel offset relative to original position.
float delta = (Horisontal) ? //scrolling right-left
(_transform.localPosition.x - _startingPosition.x) :
-(_transform.localPosition.y - _startingPosition.y);
//grids will be created later (after foreach)
List
<int> GridsToCreate
= new List
<int>();
foreach(int indx in _grids.Keys)
{
//left(up) and right(left) edges relative to the view (depending on Horisontal property)
float firstPos = delta + (indx - _firstGridIndx)*_gridLen;
float secondPos = firstPos + _gridLen;
if(firstPos > -m_iGridCreateTreshold)
{
GridsToCreate.Add(indx - 1);
}
if(secondPos < m_iGridCreateTreshold + _clipRange)
{
GridsToCreate.Add(indx + 1);
}
}
foreach(int indx in GridsToCreate)
{
CreateGrid(indx);
}
}
/// <summary>
/// Creates the grid
/// Destroyes distant grids
/// </summary>
private void CreateGrid(int indx)
{
if(indx >= 0 && !_grids.ContainsKey(indx))
{
GridData newGridData = CreateGridGameObject(indx);
if(newGridData == null) return;
//add new grid
_grids.Add(indx, newGridData);
//one of the adjasent grids should exist and have the position
if(_grids.ContainsKey(indx-1))
newGridData.m_vPosition = _grids[indx-1].m_vPosition + _vGridOffest;
else
newGridData.m_vPosition = _grids[indx+1].m_vPosition - _vGridOffest;
//destroy distant grids
DestroyGrid(indx - m_iGridDestroyRange);
DestroyGrid(indx + m_iGridDestroyRange);
}
}
/// <summary>
/// Destroies the grid.
/// </summary>
private void DestroyGrid(int indx)
{
if(_grids.ContainsKey(indx))
{
_grids[indx].grid.gameObject.SetActiveRecursively(false);
Destroy(_grids[indx].grid.gameObject);
_grids.Remove(indx);
}
}
/// <summary>
/// Shows the first grid of items
/// </summary>
public void Show(int itemsCount)
{
_itemsCount = itemsCount;
GridData newGrid = CreateGridGameObject(0);
if(newGrid != null)
_grids.Add(0, newGrid);
}
/// <summary>
/// Shows the grid of items, that contains item from the data with passed index
/// </summary>
public void Show(int itemsCount, int indexToFocusOn)
{
int indx = indexToFocusOn / m_iGridItemsCount;
_itemsCount = itemsCount;
GridData newGrid = CreateGridGameObject(indx);
if(newGrid != null)
_grids.Add(indx, newGrid);
}
/// <summary>
/// Creates the grid with index.
/// </summary>
/// <returns>
/// GridData or null if no items left to show
/// </returns>
private GridData CreateGridGameObject(int gridIndx)
{
//get the items range
int startIndx = gridIndx * m_iGridItemsCount;
int lastIndx = startIndx + m_iGridItemsCount;
int min = (_itemsCount < lastIndx) ? _itemsCount : lastIndx;
//no items for the grid
if(startIndx >= min) return null;
GameObject nextGridObj = UIToolsInstantiate(m_pGridPrefab, this.gameObject);
nextGridObj.name = "Grid " + gridIndx.ToString();
UIGrid nextGrid = nextGridObj.GetComponent<UIGrid>();
for(int i = startIndx; i < min; i++)
{
UIToolsInstantiate(m_pItemPrefab, nextGridObj);
}
GridData gridData
= new GridData
{
grid = nextGrid,
};
//position items on the grid
nextGrid.Reposition();
//get indx if it is the first created grid
if(!firstGridExists)
{
firstGridExists = true;
_firstGridIndx = gridIndx;
}
return gridData;
}
static public GameObject UIToolsInstantiate(GameObject prefab, GameObject parent)
{
if(prefab != null)
{
var obj = UnityEngine.Object.Instantiate(prefab) as GameObject;
if(obj != null)
{
if(parent != null)
{
obj.transform.parent = parent.transform;
}
obj.transform.localPosition = prefab.transform.position;
obj.transform.localScale = Vector3.one;
return obj;
}
}
return null;
}
}