Communicating with pooled objects

Well, it’s been a rather long time since my last blog post. In my defense I’ve had an eventful few months. Firstly, the company where I was working let go of all the staff, and so I’m losing my job when my contract ends in March (anyone in Amsterdam/Utrecht looking for a programmer??). 3 days after finding out about that I went to Australia for 3 weeks to see friends + family. On my return to Amsterdam I put all my efforts into helping run Global Game Jam 2017 which was a great success – over 7000 games made in over 90 countries last weekend! Then the very next day I had a cycling accident, which I’m still recovering from. So, these excuses are at least a little legitimate, right?

I’ve actually done two lots of updates since my last commit. Firstly I completely overhauled the ComponentPool class (and renamed it ObjectPool, since I also wanted to pool things other than Components), and turned it into a “packed array” implementation that I stumbled across on this Bitsquid blog post. It took me a while to get my head around it, especially how it was possible to wrap around the index array to find a free spot. Turns out there was a bug, which one commenter pointed out. I added the suggested change, as well as an Update method.

Right, now that the ObjectPool class is done I can get on with my previous dilemma – finding a way for a BulletObject to let my BulletManager know when it should delete the BulletObject from the pool. I started off by trying to implement the Event class I linked to in that post. But after creating a basic implementation and refreshing my knowledge on function pointers I learned that non static class member functions can’t actually be pointed to by a function pointer. OK, that’s not strictly true – you can, but only if the function pointer is set up with the class type as well. Which is not really what I wanted, ideally I’d want any class to be able to use the Event system.

After tossing the Event implementation aside I crawled back to my trusty old friend: Game Programming Patterns (which I did actually purchase at some point). I decided that I should probably just go with the Observer pattern for now. So I created my Subject class and decided that all GameObjects should probably be Subjects. Then my BulletManager class inherits from Observer and I override the OnNotify function with the following:

void BulletManager::OnNotify(Subject *subject)
{
    BulletObject* bulletToRemove = reinterpret_cast<BulletObject*>(subject);
    if (bulletToRemove != nullptr) {
        bulletToRemove->RemoveObserver(this);
        m_bulletPool->Destroy(bulletToRemove);
    }
}

I also made sure that, when creating a bullet in the Shoot function, I add the BulletManager as an Observer.

Once that was done I headed back to my GameScreen class to see what else I still needed to do in my conversion to object pooling. The Draw function had been looping through the array of SpriteComponents and calling their Draw functions. Since I no longer had direct access to that array I had to change this. I decided (though I’m now rethinking that), that I would add a function to the ObjectPool that returns a pointer to an object if given an index:

template<typename T>
T* ObjectPool::GetObjectByIndex(const unsigned int a_uiIndex)
{
    if (m_pIndices[a_uiIndex].index < m_uiCount) {
        return &m_pComponent[m_pIndices[a_uiIndex].index];
    }
    return nullptr;
}

And then GameScreen::Draw loops through like so:

void GameScreen::Draw()
{
    Screen::Draw();
    for (unsigned int i = 0; i < m_pSpriteComponentPool->GetCurrentSize(); ++i) {
        SpriteComponent* pSpriteComponent = m_pSpriteComponentPool->GetObjectByIndex(i);
        if (pSpriteComponent != nullptr) {
            pSpriteComponent->Draw();
        }
    }
}

In hindsight, perhaps it would just be easier and more efficient to just hand the whole packed array back? My OOP training tells me no (bad idea to give other objects control over that packed array, right?), but my sliver of data oriented design learnings tell me handing over the packed array would be the better idea.
(And, note to self, sprite drawing should probably be handled in the base screen class so I don’t have to repeat this code in other screen classes).

OK, I think that’s enough for now. Next steps might be trying to make sure all my other Screen classes work in the same way as GameScreen. As well as taking a long hard look at how I’m adding components to gameObjects, because it seems a bit clunky and inefficient right now.

As always, please let me know if you have any thoughts/answers to my questions. And you can see my code on GitHub. Oh, also if you know of any C++ games programming jobs in or near Amsterdam/Utrecht then I would love to hear from you.

Advertisements

2 thoughts on “Communicating with pooled objects

  1. I seen your messaging system and cringed a bit. For thousands of bullets that could be insane (second of your posts I’ve read so not sure what you’re doing.

    But I use a Handle struct which holds a uint32 that is made up of 24bits for the index into an array and a version number in the last 8bits. This way I can reuse the same spot many times and old handles don’t work anymore even though their index is a valid one (maybe).

    I then made my Entity as such:
    struct Entity
    {
    uint32 mID = 0;
    std::bitset mComponstList;
    bool alive = true;
    };

    So the I has a components name and put that hash into an vector. The index in the vector tells me which bit to set to 1 to show the entity has at least one (can have multiple of the same type). At the beginning of each new iteration of the game, I call EntityManager::Update() that voids out all entities that had alive = false; That way two bullets can kill the same thing without any more branching (if (target_entity) ( … )

    I also reuse spots in the vectors for new components/entities without deleting/newing them. Just set them to zero, invalidate their handle and put alive to false.

    Just a few ideas that worked out awesome for me…. so far 🙂

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s