simple object pooling for mobile games

Simple Object Pooling for Mobile Games

Being a developer is hard work. Being a new developer is even harder, because it means you haven’t figured out all of those niche best practices yet. But everyone has to start somewhere!

A long, long time ago, on a college campus far, far away, I was hand selected by one of my professors for my first real developer job. He picked me because I was currently learning how to develop video games for the Ouya, a console, that at the time, had enormous potential. (Another story at another time!) Because the Ouya was essentially an Android device, most of the development work for it was closely related to mobile development, so my professor saw an opportunity.

At the time, the Computer Game Design program I was in, had established a residency with a mobile application developer. The company hired students to work on their various mobile games. For my first real job, it was a nice set-up. I had been brought on near the end of one project, where I ended up doing a lot of bug fixing, but it was the next project that had our entire team jumping in and learning stuff the hard way.

From what I remember, the previous project I was fixing bugs on, was already half built by the time it got to the student team, so most of the framework for the game was already there. The other developers easily built off of the already established systems and the project went smoothly. The new project however, was completely from scratch. We only had the art assets and the Xbox 360 version of the game to go off of. Our job was to port (or translate) the game from the Xbox 360 to a shiny new mobile version.

During this experience, our entire team learned new things daily. A lot of those things dealt with how to properly optimize a mobile game. And this was all the way back in 2013, when phones were nowhere near what they are today. Back then, when a developer saw a 3D game running smoothly on a phone, it was big deal. It was magic. Nowadays, having a 3D game in your pocket isn’t that big of a deal, and because of all the great new hardware, it is actually really easy to accomplish.

Getting games to run smoothly in 2013 required the usage of a ton of tricks, some of which are still good practices today! One of these practices that we learned back then was the process of object pooling. Object pooling was a big deal, as it could be the difference between your mobile game running amazingly smooth with no hiccups, or your mobile game killing your phone. (I think we definitely killed a few phones before we fully figured object pooling out.)

The idea behind object pooling was to get by the sneaky garbage collector killer. For those unaware, most modern programming languages come with some sort of garbage collection system, that runs automatically to clean up all the unused “stuff” in memory that your application has created. Back in 2013, we were using the Unity Game Engine to build our mobile game, and since the Engine levies the .NET Framework, Garbage Collection happens, and Unity makes it really easy to fill up your garbage can.

Unity, as most game engines, has a built in Instantiate and Destroy system, which means that at any time, you can Instantiate an object into your application, and whenever you don’t need that object, you can Destroy it. The issue is that when you Destroy something, it goes into that magical garbage can. The game we were making was an “endless runner” type game which constantly had objects being created and moved across the screen. And in those pre-object-pooling days, we were Instantiating and Destroying everything that flew across the screen, that garbage can filled up. Constantly. So, the garbage collector ended up doing way too much work and way too often. It would consistently eat up our test phone’s memory to the point where the phone would hard crash. It was bad.

At the time, we were all young developers, and we had no idea what to do. We spent a few days analyzing our code and investigating ways on how to handle this issue and that is when we found it – object pooling. If we just added object pools that loaded on initial application start-up, we could have everything loaded into memory at once! And because object pooling is way to recycle objects without actually removing them from memory, garbage collection did not happen as much, and our game actually ran. No more crashes! It was a miracle!

So, with all that said, what is a good object pool set-up? Object pools, both implementation and code wise, are relatively easy to set-up, and as described, they can work miracles.

Let’s go through the creation of a simple object pool. All of the code you will see was built using the Unity Game Engine, but the general idea should be easy enough to port over to other engines. The code is also all in C#.

The first thing that needs to be made is the actual object pool. Note: This example is from a current spare time project where I needed to pool floating text numbers. I will not be going over the basics of Unity.

Here is what my “FloatingDamageTextManager.cs” looks like:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FloatingDamageTextManager : MonoBehaviour
{
    public static FloatingDamageTextManager instance = null;

    public GameObject playerDamageTextPrefab;
    
    public GameObject[] startingPlayerDamages;
    
    private Queue<GameObject> playerDamageTextQueue = new Queue<GameObject>();
    
    void Awake()
    {
        if (instance == null)
        {
            instance = this;
        }
        else if (instance != null)
        {
            Destroy(gameObject);
        }
    }

    // Start is called before the first frame update
    void Start()
    {
        foreach(GameObject go in startingPlayerDamages)
        {
            go.GetComponent<FloatingDamageText>().SetFloatingDamageTextManager(this);
            playerDamageTextQueue.Enqueue(go);
        }

    }

    public void SpawnPlayerDamageText(Transform target, string damage)
    {
        if(playerDamageTextQueue.Count > 0)
        {
            GameObject currentDamageText = playerDamageTextQueue.Dequeue();
            currentDamageText.transform.position = target.position;
            currentDamageText.GetComponent<FloatingDamageText>().SetAndActivateDamageText(damage);
        } else
        {
            Instantiate(playerDamageTextPrefab, target.position, target.rotation, this.transform).GetComponent<FloatingDamageText>().SetAndActivateDamageText(damage);
        }
    }

    
    public void QueuePlayerDamage(GameObject playerDamageText)
    {
        playerDamageTextQueue.Enqueue(playerDamageText);
    }
}

 

FloatingDamageTextManager.cs Explanation:

The first thing I like to do, with all of my object pools is to make them singletons – that is what the code in the Awake() function is doing – so I can access the object pool throughout my application.

The next step is setting up the Queue. I like to use queues as my pool containers, because they work perfectly for what a pool is supposed to be doing: getting an object from the start of a list and adding objects to the end of that list, over and over again.

For the setup phase, you’ll have to have all of the objects you want to pool already in your Unity Scene. I like to parent them to the object the pooler is on. You will need to have your objects added to your initial starting pool (my “startingPlayerDamages” variable above).

At runtime, the objects in your starting pool will be added to your object pool queue. You can then call a function (in this case, my “SpawnPlayerDamageText()” function) to grab the first item in the queue and process whatever you need to on that object. In this instance, it will grab the first object in the queue, move it to a certain screen location, and then set the value of the text. My function also checks to see if there are even objects in the queue to be pulled and if there are none, we will leverage Unity Instantiation system to create a new one and add it to the overall object pool. That way, we will never run into an issue of running out of objects and depending on how you are using an object pool, you will most likely hit a point where no new objects need to be created. (If you never hit that point, that is a bad sign.)

The final function I have in the object pooler is the requeue function (my “QueuePlayerDamage()” function above). This is a function that needs to be called by the objects you are pooling, preferably after your objects do what they need to do on their own.

And that’s all you really need! It is something incredibly simple that can make your mobile application run better – as long as you use it correctly. It is also incredibly flexible and can used for just about everything in your mobile game.

Object pooling saved me and my team’s project a long time ago, and maybe it can help save another project, or just help a project start off the right way.

We Are Hiring Developers!

Come work with our award winning team! We are looking for full stack, mid to senior level developers for positions in both Hampton Roads and Richmond VA. Check out our careers page for current openings and send us your resume today!

Andrew Sweeney

Andrew Sweeney is a web developer on the Digital Marketing Team at Marathon Consulting. He graduated from George Mason University with a Master of Arts in Computer Game Design. In the past, Andrew has worked for a couple start-up companies, working on mobile and serious games, as well as working for Booz Allen Hamilton as an applications developer before joining the team at Marathon. Outside of work, you can expect to see him working on his own computer games, as well as playing them.

Leave a Comment

Let's talk about your project.

We are full-service, flexible, and believe that successful projects are the result of working collaboratively with our clients. Are you looking for a better user experience for your website or application? Need an experienced database architect or business analyst? Let’s talk!

X