SwarmItemManager 才是重中之重 前面和后面的东西都是小菜一碟 -,-
public class SwarmItemManager : MonoBehaviour
{
//首先,他通过这个列表类
protected class PrefabItemLists
{
public LinkedList<SwarmItem> activeItems;
public Stack<SwarmItem> inactiveItems;
public int itemCount;
public float inactivePruneTimeLeft; 栈中存在的时间
public PrefabItemLists ()
{
activeItems = new LinkedList<SwarmItem>();
inactiveItems = new Stack<SwarmItem>();
}
}
[Serializable]
public class PrefabItem
{
public GameObject prefab;
public int maxItemCount = 0; //最大的个数
public float inactiveThreshold = 1.0f; //门槛? 无效的项目数,如果超过这一比例,则定时器立刻触发,默认是1.0,则所有都用完才会修剪 范围是0-1
public float inactivePruneTimer = 0.0f; //在垃圾栈中的板凳时间 还没被删除的存在时间
public float inactivePrunePercentage = 0.0f; //垃圾栈中所占的项目百分比
}
private SwarmItem _item;
private GameObject _go;
private Transform _transform;
private Transform _activeParentTransform;
private Transform _inactiveParentTransform;
private int _itemCount;
protected PrefabItemLists [] _prefabItemLists;、、//拿到每一个list的数量
public bool debugEvents;
public PrefabItem [] itemPrefabs;
public virtual void Initialize()
{
if (itemPrefabs.Length == 0) //必须要有list的项目
{
Debug.Log("WARNING! No Item Prefabs exists for " + gameObject.name + " -- Errors will occur.");
}
foreach (PrefabItem itemPrefab in itemPrefabs)
{
itemPrefab.inactiveThreshold = Mathf.Clamp01(itemPrefab.inactiveThreshold);
itemPrefab.inactivePrunePercentage = Mathf.Clamp01(itemPrefab.inactivePrunePercentage);
}
_prefabItemLists = new PrefabItemLists[itemPrefabs.Length];
for (int i=0; i<_prefabItemLists.Length; i++)
{
_prefabItemLists[i] = new PrefabItemLists();
_prefabItemLists[i].itemCount = 0;
_prefabItemLists[i].inactivePruneTimeLeft = 0;
}
_go = new GameObject("Active Items");
_activeParentTransform = _go.transform;
_activeParentTransform.parent = this.transform;
_activeParentTransform.localPosition = Vector3.zero;
_activeParentTransform.localRotation = Quaternion.identity;
_activeParentTransform.localScale = Vector3.one;
_go = new GameObject("Inactive Items");
_inactiveParentTransform = _go.transform;
_inactiveParentTransform.parent = this.transform;
_inactiveParentTransform.localPosition = Vector3.zero;
_inactiveParentTransform.localRotation = Quaternion.identity;
_inactiveParentTransform.localScale = Vector3.one;
}
//生成一个新活动项目
public virtual SwarmItem ActivateItem()
{
return ActivateItem(0);
}
///生成一个新活动项目,总的来说较为复杂orz
public virtual SwarmItem ActivateItem(int itemPrefabIndex)
{
if (_prefabItemLists[itemPrefabIndex].activeItems.Count == itemPrefabs[itemPrefabIndex].maxItemCount && itemPrefabs[itemPrefabIndex].maxItemCount > 0)
{
if (debugEvents)
Debug.Log("Could not activate item because the count [" + _prefabItemLists[itemPrefabIndex].activeItems.Count + "] is at the maximum number for this item type at frame: " + Time.frameCount);
return null;
}
if (_prefabItemLists[itemPrefabIndex].inactiveItems.Count > 0)
{
// there is an inactive item so we recycle it
// pop off the inactive stack
_item = _prefabItemLists[itemPrefabIndex].inactiveItems.Pop();
// queue to the end of the active list
_prefabItemLists[itemPrefabIndex].activeItems.AddLast(_item);
if (debugEvents)
Debug.Log("Recycled item " + _item.name + " at frame: " + Time.frameCount);
}
else
{
// no inactive item availble, so create a new one
// instantiate item
_item = InstantiateItem(itemPrefabIndex);
// queue to the end of the active list
_prefabItemLists[itemPrefabIndex].activeItems.AddLast(_item);
if (debugEvents)
Debug.Log("Instantiated a new item " + _go.name + " at frame: " + Time.frameCount);
}
// move the item to active parent transform.
// this is mainly just for visual reference in the editor
SetItemParentTransform(_item, _activeParentTransform);
// set the state to active
_item.State = SwarmItem.STATE.Active;
// if the prune timer is runnning
if (_prefabItemLists[itemPrefabIndex].inactivePruneTimeLeft > 0)
{
// if the inactive item count dropped below the threshold
if (((float)_prefabItemLists[itemPrefabIndex].inactiveItems.Count / (float)_prefabItemLists[itemPrefabIndex].itemCount) < itemPrefabs[itemPrefabIndex].inactiveThreshold)
{
if (debugEvents)
Debug.Log("Dropped below inactive threshold [" + (itemPrefabs[itemPrefabIndex].inactiveThreshold * 100) + "%] for " + itemPrefabs[itemPrefabIndex].prefab.name + " list before timer expired. Stopping prune timer at frame: " + Time.frameCount);
// turn the prune timer off
_prefabItemLists[itemPrefabIndex].inactivePruneTimeLeft = 0;
}
}
return _item;
}
/// 把一个 SwarmItem从 激活列表转移到不激活的列表,并改变父对象,超时和超门槛百分比都会白消掉
public virtual void DeactiveItem(SwarmItem item)
{
// remove from the active linked list
_prefabItemLists[item.PrefabIndex].activeItems.Remove(item);
// push onto the inactive stack
_prefabItemLists[item.PrefabIndex].inactiveItems.Push(item);
SetItemParentTransform(item, _inactiveParentTransform);
if (debugEvents)
Debug.Log("Deactivated " + item.name + " at frame: " + Time.frameCount);
if (_prefabItemLists[item.PrefabIndex].inactivePruneTimeLeft == 0 && itemPrefabs[item.PrefabIndex].inactivePrunePercentage > 0)
{
// if the inactive item count exceeds the threshold
if (((float)(_prefabItemLists[item.PrefabIndex].inactiveItems.Count) / (float)_prefabItemLists[item.PrefabIndex].itemCount) >= itemPrefabs[item.PrefabIndex].inactiveThreshold)
{
if (debugEvents)
Debug.Log("Inactive threshold [" + (itemPrefabs[item.PrefabIndex].inactiveThreshold * 100) + "%] reached for " + itemPrefabs[item.PrefabIndex].prefab.name + " list. Starting prune timer [" + itemPrefabs[item.PrefabIndex].inactivePruneTimer + " seconds] at frame: " + Time.frameCount);
// if the prune timer is set to expire immediately
if (itemPrefabs[item.PrefabIndex].inactivePruneTimer == 0)
{
// don't wait for a countdown, just prune immediately
PruneList(item.PrefabIndex, itemPrefabs[item.PrefabIndex].inactivePrunePercentage);
}
else
{
// turn the prune timer on
_prefabItemLists[item.PrefabIndex].inactivePruneTimeLeft = itemPrefabs[item.PrefabIndex].inactivePruneTimer;
}
}
}
}
//实例化一个项目
protected virtual SwarmItem InstantiateItem(int itemPrefabIndex)
{
SwarmItem item;
// instantiate
_go = (GameObject)Instantiate(itemPrefabs[itemPrefabIndex].prefab);
// change the name of the gameobject with an index and take off the 'Clone' postfix
_go.name = "[" + _itemCount.ToString("0000") + "] " + _go.name.Replace("(Clone)", "");
// get the SwarmItem component from the gameobject
item = (SwarmItem)_go.GetComponent(typeof(SwarmItem));
// initialize the SwarmItem
item.Initialize(this, itemPrefabIndex, debugEvents);
// increase the item count for this prefab
_prefabItemLists[itemPrefabIndex].itemCount++;
// increment the total item count for this manager
_itemCount++;
return item;
}
// 移动项目的父对象物体
private void SetItemParentTransform(SwarmItem item, Transform parentTransform)
{
// reparent this item's transform
item.ThisTransform.parent = parentTransform;
// reset the position, rotation, and scale to unit values
item.ThisTransform.localPosition = Vector3.zero;
item.ThisTransform.localRotation = Quaternion.identity;
item.ThisTransform.localScale = Vector3.one;
// if the position, rotation, or scale need to be changed after reparenting, do it in the
// item's OnSetParentTransform method
item.OnSetParentTransform();
}
//帧更新
public virtual void FrameUpdate()
{
// iterate through each SwarmItem type
for (int i=0; i<_prefabItemLists.Length; i++)
{
// only bother if the active list has some items
if (_prefabItemLists[i].activeItems.Count > 0)
{
// we don't iterate through the active list using foreach here
// because there would be errors if the item was killed in its FrameUpdate method.
// instead we manually move to the next linkedlist node
LinkedListNode<SwarmItem> item;
LinkedListNode<SwarmItem> nextItem;
item = _prefabItemLists[i].activeItems.First;
// while there are items left to process
while (item != null)
{
// cache the next item in case this item is killed in its FrameUpdate
nextItem = item.Next;
// update and move to the next item
item.Value.FrameUpdate();
item = nextItem;
}
}
// if this list has its prune timer turned on
if (_prefabItemLists[i].inactivePruneTimeLeft > 0)
{
// decrement the prune timer
_prefabItemLists[i].inactivePruneTimeLeft -= Time.deltaTime;
// if the timer has expired
if (_prefabItemLists[i].inactivePruneTimeLeft <= 0)
{
// prune the list
PruneList(i, itemPrefabs[i].inactivePrunePercentage);
}
}
}
}
/// Removes inactive items from the list after the inactive item count exceeds a threshold and
/// no new items are activated from the list before the prune timer countdown expires. Alternatively,
/// you could call this manually to free up memory at any time.
修剪list列表
public void PruneList(int itemPrefabIndex, float prunePercentage)
{
// turn off the prune timer
_prefabItemLists[itemPrefabIndex].inactivePruneTimeLeft = 0;
// get the number of items to prune based on the prune percentage.
// the amount is a percentage of the inactive items, not the total item count for this list
int pruneCount = Mathf.FloorToInt(prunePercentage * (float)_prefabItemLists[itemPrefabIndex].inactiveItems.Count);
SwarmItem item;
if (debugEvents)
Debug.Log("Pruning " + pruneCount + " items [" + (itemPrefabs[itemPrefabIndex].inactivePrunePercentage*100) + "% of " + _prefabItemLists[itemPrefabIndex].inactiveItems.Count + "] from inactive " + itemPrefabs[itemPrefabIndex].prefab.name + " list at frame: " + Time.frameCount);
// prune each item
while (pruneCount > 0)
{
// pop an item from the inactive stack
item = (SwarmItem)_prefabItemLists[itemPrefabIndex].inactiveItems.Pop();
// call the overloaded PreDestroy function to let the inherited objects
// free any memory
item.PreDestroy();
if (debugEvents)
Debug.Log("Destroyed " + item.name + " at frame: " + Time.frameCount);
// destroy the item
Destroy(item.gameObject);
item = null;
// decrement this list's item count and the manager's total item count
_prefabItemLists[itemPrefabIndex].itemCount--;
_itemCount--;
// move to the next item to prune
pruneCount--;
}
}
}