Skip to content

Instantly share code, notes, and snippets.

@JakubNei
Last active June 10, 2017 06:48
Show Gist options
  • Save JakubNei/c4e65eed2638bf62ef0a to your computer and use it in GitHub Desktop.
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…
/*
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