Last active
June 10, 2017 06:48
-
-
Save JakubNei/c4e65eed2638bf62ef0a to your computer and use it in GitHub Desktop.
Simple generic object pooler, mostly useful for Unity. Example usages shows some Unity specific use cases. Entries are created (createObj) as needed with GetNext method. Then once they run out of live they are set to dead (setDeadObj). If they are dead for timeToDestroyOnceDead seconds they are destroyed (destroyObj). If they are needed again b…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Simple generic object pooler, mostly useful for Unity. | |
Example usages shows some Unity specific use cases. | |
Entries are created (createObj) as needed with GetNext method. | |
Then once they run out of live they are set to dead (setDeadObj). | |
If they are dead for timeToDestroyOnceDead seconds they are destroyed (destroyObj). | |
If they are needed again before their timeToDestroyOnceDead timer runs out they are set alive (setAliveObj). | |
license: WTFPL (http://www.wtfpl.net/) | |
author: aeroson | |
*/ | |
// example usage: | |
/* | |
pool.timeToDestroyOnceDead = 10.0f; | |
pool.createObj = () => | |
{ | |
var lr = this.gameObject.AddComponent<LineRenderer>(); | |
lr.material = lineRendererMat; | |
lr.SetWidth(0.25f, 0.25f); | |
lr.SetVertexCount(2); | |
lr.useWorldSpace = true; | |
return lr; | |
}; | |
pool.destroyObj = (LineRenderer lr) => | |
{ | |
Destroy(lr); | |
}; | |
pool.setAliveObj = (LineRenderer lr) => | |
{ | |
lr.enabled = true; | |
}; | |
pool.setDeadObj = (LineRenderer lr) => | |
{ | |
lr.enabled = false; | |
}; | |
pool.maxCount = maxDecalsCount; | |
pool.timeToDestroyOnceDead = 10.0f; | |
pool.createObj = () => | |
{ | |
var decal = ctx.world.InstantiateLocal(decalPrefab); | |
return decal; | |
}; | |
pool.destroyObj = (GameObject go) => { Destroy(go); }; | |
pool.setAliveObj = (GameObject go) => { go.SetActive(true); }; | |
pool.setDeadObj = (GameObject go) => { go.SetActive(false); }; | |
*/ | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
public class ObjectPooler<T> | |
{ | |
public Func<T> createObj; | |
public Action<T> destroyObj; | |
public Action<T> setAliveObj; | |
public Action<T> setDeadObj; | |
public float timeToDestroyOnceDead = 10.0f; | |
public int maxCount = int.MaxValue; | |
class Entry | |
{ | |
public T obj; | |
public float timeToLive; | |
public float timeToDestroyOnceDead; | |
public bool isDead { get { return timeToLive <= 0; } } | |
} | |
Stack<Entry> entries = new Stack<Entry>(); | |
public T GetNext(float timeToLive) | |
{ | |
Entry entry = null; | |
if (entries.Count >= maxCount) | |
{ | |
// find entry with lowest timeToLive | |
float lowest = float.MaxValue; | |
foreach (var e in entries) | |
{ | |
if (e.timeToLive < lowest) | |
{ | |
lowest = e.timeToLive; | |
entry = e; | |
if(lowest == -2) | |
{ | |
// entry is dead, no point in looking for anything else | |
break; | |
} | |
} | |
} | |
} | |
else | |
{ | |
// foreach (var e in entries) // stack entries.GetEnumerator() start from top to bottom | |
foreach (var e in entries.Reverse()) // stack entries.GetEnumerator().Reverse() start from bottom to top | |
{ | |
if (e.timeToLive < 0) | |
{ | |
entry = e; | |
break; | |
} | |
} | |
} | |
if (entry == null) | |
{ | |
entry = new Entry(); | |
entry.obj = createObj(); | |
entries.Push(entry); | |
} | |
else | |
{ | |
setAliveObj(entry.obj); | |
} | |
entry.timeToLive = timeToLive; | |
entry.timeToDestroyOnceDead = timeToDestroyOnceDead; | |
return entry.obj; | |
} | |
public void Update(float deltaTime) | |
{ | |
foreach (var e in entries) | |
{ | |
if (e.timeToLive >= 0) | |
{ | |
e.timeToLive -= deltaTime; | |
if (e.timeToLive < 0) | |
e.timeToLive = -1; | |
} | |
else if (e.timeToLive == -1) | |
{ | |
setDeadObj(e.obj); | |
e.timeToLive = -2; | |
} | |
else if (e.timeToDestroyOnceDead >= 0) | |
{ | |
e.timeToDestroyOnceDead -= deltaTime; | |
} | |
} | |
do | |
{ | |
if (entries.Count == 0) return; | |
var entry = entries.Peek(); | |
if (entry.timeToDestroyOnceDead < 0) | |
{ | |
destroyObj(entry.obj); | |
entries.Pop(); | |
} | |
else | |
{ | |
break; | |
} | |
} while (true); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment