- Home /
[SOLVED] GameObject pooling is not returning enough objects!
SOLVED:
OOPS! Turns out I was forgetting to clear the list of segments per bolt. This meant that when Bolt A deactivated, it would deactivate Bolt B's segments that had been previously parented to A. This is a lesson to avoid tunnel-visioning on one potential cause of a bug, I guess, since it had nothing at all to do with the object pool.
Preface:
I've got a bit of an issue with my object pooling. I have a lightning bolt object composed of a number of gameObject segments (so that I can control the length of the bolt). It seems that at first, the pooling for these segment gameObjects works like a charm.
Pictured above: working as intended.
Issue
Eventually, though, it looks like either the pool is not big enough (unlikely as it should grow automatically) or retrieving the same object multiple times. The result is that the bolt object is set active and WAM! It's got missing segments.
Pictured above: example of the issue, with segments missing from the bolts, which points to an error in the pooling.
Code
Below is my code for object pooling. When an object is needed, it gets retrieved using the static GetObject method.
public static class Pool
{
private static Dictionary<GameObject, List<GameObject>> pools = new Dictionary<GameObject, List<GameObject>>();
public static List<GameObject> GetPool(GameObject gameObject)
{
// If pooled object list already exists, return it
if (pools.TryGetValue(gameObject, out List<GameObject> list))
return list;
// Otherwise, create a new list of pooled objects and
// add it to the pool dictionary, then return
list = new List<GameObject>();
pools.Add(gameObject, list);
return list;
}
public static GameObject GetObject(GameObject prefab)
{
// Get list of pooled gameObjects
List<GameObject> list = GetPool(prefab);
// Prepare a list for potential null objects that need to be
// removed from the pool.
List<GameObject> objectsToRemove = new List<GameObject>();
// Enumerate through list of pooled objects to find inactive
// object, then activate and return that instance
GameObject gameObject = null;
for (int i = 0; i < list.Count; i++)
{
GameObject o = list[i];
if (o && !o.activeSelf)
{
gameObject = o;
gameObject.SetActive(true);
break;
}
else if (!o)
objectsToRemove.Add(o);
}
// Remove null objects from the pool
objectsToRemove.ForEach(o => list.Remove(o));
// If no inactive instances were found, add a new instance
if (!gameObject)
{
gameObject = Object.Instantiate(prefab, Group.Pool);
if (!list.Contains(gameObject))
list.Add(gameObject);
}
// Return object
return gameObject;
}
}
Below is my code for the lightning bolt creation.
public static Bolt Strike(Vector3 start, Vector2 direction)
{
// Get bolt parent prefab
GameObject prefab;
try
{
prefab = Assets.prefabs["Bolt"];
}
catch
{
throw new NullReferenceException("Prefab 'Bolt' not found in asset dictionary!");
}
// Instantiate bolt parent
GameObject gameObject = Pool.GetObject(prefab);
gameObject.transform.position = start;
// Rotate bolt parent to attack angle
float angle = direction.ToAngle();
Quaternion rotation = Quaternion.identity;
Vector3 eulerAngles = rotation.eulerAngles;
eulerAngles.z = angle;
rotation.eulerAngles = eulerAngles;
gameObject.transform.rotation = rotation;
// Get the maximum length of the bolt
Bolt bolt = gameObject.GetComponent<Bolt>();
float maxLength = bolt.maxLength;
Vector3 end = start + (Vector3) (direction * maxLength);
// Check for collisions with entities
RaycastHit2D[] hits = Physics2D.RaycastAll(start, direction, maxLength, LayerMask.GetMask("Entities"));
float boltLength = maxLength;
// If collision, set target point to collision point +
// 72 pixels in bolt direction
foreach (RaycastHit2D hit in hits)
{
if (hit.collider.CompareTag("Player"))
continue;
float distance = hit.distance + Size;
if (distance < boltLength)
{
end = hit.point + (direction * Size);
boltLength = distance;
}
}
// Get bolt segment prefab
try
{
prefab = Assets.prefabs["Bolt Segment"];
}
catch
{
throw new NullReferenceException("Prefab 'Bolt Segment' not found in asset dictionary!");
}
// Construct bolt out of segments until length is reached
Transform parent = bolt.transform;
SpriteRenderer spriteRenderer = null;
boltLength -= Size;
int step = 0;
while (boltLength > 0)
{
start += (Vector3) (direction * Size);
gameObject = Pool.GetObject(prefab);
// Set parent to bolt object
gameObject.transform.SetParent(parent);
gameObject.transform.position = start;
// Set rotation to bolt angle
rotation = Quaternion.identity;
eulerAngles = rotation.eulerAngles;
eulerAngles.z = angle;
rotation.eulerAngles = eulerAngles;
gameObject.transform.rotation = rotation;
// Set sprite and choose whether to invert it
spriteRenderer = gameObject.GetComponent<SpriteRenderer>();
Sprite sprite = bolt.middleSprites[Random.Range(0, bolt.middleSprites.Length)];
spriteRenderer.sprite = sprite;
bool flipSprite = (Random.Range(0f, 1f) >= 0.5) ? true : false;
spriteRenderer.flipY = flipSprite;
spriteRenderer.flipX = flipSprite;
// Add to
bolt.segments.Add(gameObject);
boltLength -= Size;
step++;
if (step > MAX_STEPS)
break;
}
// Set end sprite
if (spriteRenderer)
{
spriteRenderer.flipX = false;
spriteRenderer.flipY = false;
spriteRenderer.sprite = bolt.endSprite;
}
// Return bolt parent script
return bolt;
}
Any help is greatly appreciated! Thank you for reading my silly wall of text.
Your answer
Follow this Question
Related Questions
I can't Implement the Pool system 1 Answer
enemy pooling 1 Answer
Pooling GameObjects with TextMesh ? 0 Answers
Pooling Issue 0 Answers