- Home /
How to use the same object more than once at the same time when using an "object pooling" pattern?
Hello,
I'm working on an endless runner and I created a SceneManager that has an array of references to environment sections prefabs.
For now I instantiate a new section and remove the section that left the camera view at runtime.
I know how to use an "object pooling" pattern for optimization, but as it happens I need to spawn the same section more than once at a time (and this is dynamically, not a fixed number of times) and if I instantiate each section only once when creating the object pool I cannot use it more than once in my scene. Adding more than one instances of the same section when creating the object pool won't work either, because then I will have a lot of overhead(redundant objects instantiated that will never be used).
Is there any way I could reuse an object from an object pool more than once? I think this can be done with Graphics.DrawMesh (I only want to apply this for the environment, so no colliders/scripts involved there - just want to draw it), but I am not sure.
Thank you in advance!
Answer by Kossuranta · Jun 01, 2017 at 08:47 AM
Adding more than one instances of the same section when creating the object pool won't work either, because then I will have a lot of overhead(redundant objects instantiated that will never be used).
Honestly just do that. Having instantiated objects that are not activated doesn't really create too much overhead. It will use somewhat more memory and loading the scene will take little bit longer, but I'm pretty sure that these will changes that you wont even be able to notice. Using some tricks to get same object showing twice at the same time will most likely be a lot more inefficient than just pooling stack of inactive objects that you might never need.
Object pools should usually also have option for Instantiate when you need a new object, but the pool is empty. This is case that generally should never happen, but it's better to be safe.
Thank you for the answer!
I have a defined number of sections active at a time and using the method you mentioned would mean duplicating each section that number of times while loading. I agree that loading time will be slightly longer, but that's ok because I use only one scene for the game and would instantiate all objects only once.
I might use this method in the end, after I run some tests on memory to make sure I don't use too much of it for this.
Thank you!
Answer by IgnoranceIsBliss · Jun 01, 2017 at 08:23 AM
A single GameObject can only be in a single position at any one time, but you can always use GameObject.Instantiate() to create an exact copy of an existing one.
Although it's a little less efficient, you could easily create your template sections, hide them, and then instantiate copies of them at runtime as you need them, destroying them when they fall back off-screen. This way you can repeat an object as many times as you want, and from what I can tell, the overhead of instantiating a new GameObject is relatively small, since all component assets are pre-loaded.
There will of course be a little more work for your garbage collector, but I don't think the losses will be pretty minor.
Thank you for the answer!
However creating an Instance of a Scene object is less efficient than creating an instance of a prefab. It might be because Unity will have to also serialize the Scene Object while the prefab is already serialized.
Check this test made by @frosted here: https://forum.unity3d.com/threads/gameobject-instantiate-prefab-vs-scene-instance.259408/#post-1716248
I could create a dynamic pool based on your idea, but just using the prefabs ins$$anonymous$$d when I need the same objects more than once. So in the end the pool will grow during gameplay, but it's size will come to a halt when enough objects to select from will be available.
Thank you for the answer!
Answer by FM-Productions · Jun 01, 2017 at 08:30 AM
My idea would be that if you want to use the same object more than once:
If the object does not change and is not on the screen more than once at any time: If you do not need it anymore, set it to inactive and put it back into your pool. (gameObject.setActive(false)). If you need it again, get it from the pool and set it to active.
If you do need it more than once at any given time: Just make a list containing the same objects when you set up your pool at the start of your game, then simply take your object from that list:
List<GameObject> duplicatedObjects = new List<GameObject>();
//filling the pool of same objects
for (int i = 0; i < 10; i++){
GameObject newObj = Instantiate(prefabObject);
newObj.setActive(false);
duplicatedObjects.Add(newObj);
}
//retrieve the object:
GameObject objectInScene = duplicatedObjects[0];
duplicatedObjects.RemoveAt(0);
objectInScene.setActive(true);
Just make sure that you have at least as many object in the list as you need, else perform a check if the Count of the list is greater than 0.
Thank you for the answer.
However this is not so different from just adding the duplicates to my pool, which I tried avoiding because in the end most of them will end up unused by the spawning algorithm (but all of them will have the same chance of being spawn at the same time, so I can't make the assumption that some objects shouldn't be duplicated because they won't be spawned more than once at a time).
I might use the method I mentioned in the end, after I run some tests on memory to make sure I don't use too much of it for this.
You can play around and check if there are really any performance issues when you have many inactive gameObjects stored in variables. Alternatively, like $$anonymous$$ossuranta mentioned, you can implement a mechanism that will create a new gameObject if your pool has run out of objects:
if (duplicatedObjects.Count == 0){
GameObject objectInScene = Instantiate(prefabObject);
}
This has the drawback that there may be performance issues or lag during the instantiation which I guess was the reason you wanted to use object pooling in the first place.
This would be an improvement, because at the moment I instantiate each section during gameplay every time I need it.
I don't see any lag or any issues even on lower end devices (android 4) when I run the game, but that doesn't mean I won't improve performance where there's room for improvement.
Your answer
Follow this Question
Related Questions
Need optimizing tips for mobile third person shooting game. 2 Answers
Code Optimization Question 1 Answer
Change name of Instantiate prefab 1 Answer
Unlimited Blood on Floor 1 Answer