Can anybody provide a simple c++ pool of sprites?

Say we need to create a set of sprites of 20 and recreate them after they leave visible screen. What is the most proper way to do it? A simple example will help many people i think. Thank you in advance.

Hey @hgokturk

Check this out: http://gameprogrammingpatterns.com/object-pool.html

That book covers lots of game programming patterns and object pool is one of them.

Hope that helps.

@jonah1nine thank you. But i really need a simple example which achieves what i described in my first post.

just set the new position of the sprite when its position is left of the screen to a position to the right of the screen. Assuming its position is somehow being change so it moves left, it will then re-appear on the right hand side of the screen.

No need to recreate them - just create the ones you want and keep modifying the position.

Say you have all of your 20 sprites as children of a node, then you can iterate over the children, check the position against the left of the screen (taking into account the width of the sprite) and (in the simplest case) simply add on the screen width to the position.x of the sprite.

I’m talking about the example code of implementation of object pooling in cocos2dx. What you mentioned has nothing to do with it if i’m not mistaken.

Sorry - what you described has nothing to do with object pooling - perhaps you need to describe our problem differently?

the example you give (recreating objects after they leave the visible screen) doesn’t really make sense - as they won’t be destroyed when they leave the visible screen (unless you destroy them) - so there is simply no need for object pooling in this case.

O.K @Maxxx thank you.

I guess the post above means - in fact i don’t know how more clearly i can explain such a clear scenario - i have a scenario which 20 of sprites are involved, they must be created, retained, destroyed whatever using cocos2dx object pooling techniques and i want somebody to share a simple c++ code of it.
Thank you again for your guidance.

OK - my question is, “Why do you think you need to use object pooling?”
With object pooling you just create your sprites in advance and then use one when you need to; there are many, many different ways to implement it, and your choice depends on exactly what you want to do!

Say your 20 sprites are all different - then object pooling won’t help you at all.

If they are all the same (say you have 20 ‘baddies’ that you want to spawn at different times / in different places) then my description from earlier will suffice - when you want to spawn a new sprite, just look through the child sprites until you find one that is inactive, position it and make it active. That is object pooling.

Of course you can get cleverer than that (like, you can create your own object pooling classes that generically handle getting ‘unused’ objects out of a collection)

You say “we need to create a set of sprites of 20 and recreate them after they leave the visible screen”

When they leave the visible screen, why do you destroy them? Just make them inactive and leave them. then re-use them when you need to. As I said, that is object pooling - and for 20 sprites just going off screen, I think that’s all you need.

Any sample codes?

in ccConfig.h enable custom allocators by defining CC_ENABLE_ALLOCATOR to 1

Either subclass Sprite or modify the existing Sprite and implement a custom pool allocator for it.

#include "base/allocator/CCAllocatorStrategyPool.h"

class MySprite : public Sprite
{
public:

    static allocator::AllocatorStrategyPool<MySprite> _allocator;
    CC_USE_ALLOCATOR_POOL(MySprite, _allocator);    
}

@mannewalis

I saw your commit and discussion for custom allocator. Can you provide more info about this, how does it work etc.? And how to use it for Ref and non-Ref objects ?

Best

Simple example from game i going to open source soon that do exactly what you asked
PathHolder is object that inherent from Sprite
In my example it is singletone but it not have to be ,

//
//  PathObjectPool.cpp
//  TheLineCurve
//
//  Created by meir yanovich on 2/1/15.
//
//
 
#include "PathObjectPool.h"
#include "PathHolder.h"

PathObjectPool::PathObjectPool()
{
    
}

void PathObjectPool::InitObjectPoll()
{
    int sizeToFill = OBJECTS_SIZE;
    
    if(freeList.size() > 0)
    {
        sizeToFill = OBJECTS_SIZE - freeList.size();
    }
    
    for (int j=0; j< sizeToFill; j++) {
            freeList.push_back(PathHolder::create());
    };
    //log("free objects %d" ,freeList.size());
}

PathHolder* PathObjectPool::allocate()
{
    PathHolder* R;
    if (freeList.size() > 0)
    {
        R = freeList.front();
        // get the first one.
        freeList.pop_front();
        // remove it from the free list
        return R;
        // and pass it back to the client
    } else {
        return nullptr;
    };
}

void PathObjectPool::release(PathHolder* R) {
    //set to init state
     
    freeList.push_back(R);
};

int PathObjectPool::getFreeListSize()
{   
    return freeList.size();
}

//
//  PathObjectPool
//  TheLineCurve
//
//  Created by meir yanovich on 2/1/15.
//
//

#ifndef TheLineCurve_PathObjectPool_h
#define TheLineCurve_PathObjectPool_h

#include "cocos2d.h"
#include "UT.h"
#include "Singleton.h"
class PathHolder;
#define OBJECTS_SIZE 150
USING_NS_CC;

class PathObjectPool : public Singleton<PathObjectPool>
{
    friend class Singleton<PathObjectPool>;
    public:
    PathHolder* allocate();
    void release(PathHolder* R);
    int getFreeListSize();
    void InitObjectPoll();
    

    private:
        PathObjectPool();
        std::list<PathHolder* > freeList;
        
};

#endif

in code :
pPathHolder = PathObjectPool::get_instance()->allocate();

The best notes I have on this right now are the release notes. here

Reference counting has nothing to do with it, and will work as normal. When a reference count goes to 0, delete is called which calls the object’s custom delete which returns the object to the pool. You can even subclass an object in which case it will no longer be allocated from the pool (if the size is different).

1 Like

@mannewalis thank you for sharing.

Thanks for a feedback. I’ve implemented it in my Sprite subclass, and works perfectly. But i have problem when implementing in a derived class where base class is abstract one. When calling delete on derived class i’m getting crash that looks like object is twice deleted.

Can you post your implementation and a callstack?

Base class:

struct GameObject
{
    std::string name;
    cocos2d::Node *node;
    
    GameObject() : node(nullptr)
    {
        
    }
    
    std::string getName()
    {
        return name;
    }
    
    virtual ~GameObject()
    {
        node = nullptr;
    };
    
    virtual int getEntityType() = 0;
};

Derived class:
_allocator is properly initialized btw.

struct ThunderObject : public GameObject
{
    static cocos2d::allocator::AllocatorStrategyPool<ThunderObject> _allocator;
    CC_USE_ALLOCATOR_POOL(ThunderObject, _allocator);
    
    bool collected;
    
    ThunderObject() : GameObject()
    {
        collected = false;
        name = typeid(ThunderObject).name();
    }
    
    ~ThunderObject()
    {
        
    }
    
    int getEntityType() override
    {
        return 4;
    }
};
malloc: *** error for object 0x175a4e190: pointer being freed was not allocated
I've removed unnecessary stuff (path etc.)
malloc_error_break ()
free ()
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::~basic_string() ()
GameObject::~GameObject() at GameObjects.h:47
GameObject::~GameObject() at GameObjects.h:45
cocos2d::allocator::ObjectTraits<ThunderObject, 4ul>::destroy(ThunderObject*) at ios_mac/../cocos2d/cocos/base/allocator/CCAllocatorStrategyPool.h:74
cocos2d::allocator::AllocatorStrategyPool<ThunderObject, cocos2d::allocator::ObjectTraits<ThunderObject, 4ul>, cocos2d::allocator::lockless_semantics>::deallocate(void*, unsigned long) at ios_mac/../cocos2d/cocos/base/allocator/CCAllocatorStrategyPool.h:146
ThunderObject::operator delete(void*, unsigned long) at GameObjects.h:119
ThunderObject::~ThunderObject() at GameObjects.h:130

How are you creating and destroying your ThunderObject?

I did find a small bug that causes a similar crash.

When you declare the static _allocator instance, provide a name to id the allocator like this…

allocator::AllocatorStrategyPool<ThunderObject> ThunderObject::_allocator("ThunderObjectAllocator", 40);

The 40 is the number of objects to initialize the pool with. You can leave it out or set it to something meaningful. You can even connect to the app with the console and get it to display the high water mark for allocator type.

Amazing , why over engineer it ?
what is wrong with simple map/vector/list ?
i Really scared to run cocos2d-x engine with Valgrind … with all those allocates and macros that are scattered all around
keep it simple guys