Sign in to follow this  
Solid_Spy

How to create unique_pointer lists for game objects?

Recommended Posts

Hello, I am trying to figure out the best way to manage my game objects.

 

I have tried using unique_pointer, but to no avail...

 

I want to have multiple lists to reference the same objects, for example:

 

I want to have a main list for all my objects, but a seperate list that only references objects that I want to have rendered, like this

 

std::vector<std::unique_ptr<Object>> ObjectList;
std::vector<std::unique_ptr<Object>> RendeObjects;

 

I've tried adding objects to the lists, but cannot remove them, and don't know how to remove objects from the second list that no longer exist in the first.

 

Here's a simple program I've made that is supposed to create two vectors, and add objects and delete them:

#include <iostream>
#include <vector>
#include <memory>

class Object
{
public:
	float x;
	float y;
	float z;
	bool dynamic;

	Object(bool canCollide)
	{
		dynamic = canCollide;

		if(dynamic == true)
		{
			std::cout << "Dynamic Object Created" << std::endl;
		}

		if(dynamic == false)
		{
			std::cout << "Object Created" << std::endl;
		}
	}
};

int main()
{
	std::vector<std::unique_ptr<Object>> ObjectList;
	std::vector<std::unique_ptr<Object>> CollidableObjects;

	Object o(true);
	std::unique_ptr<Object> obj(&o);

	ObjectList.push_back(std::move(obj));

	Object oo(false);
	std::unique_ptr<Object> oobj(&oo);

	ObjectList.push_back(std::move(oobj));

	Object ooo(false);
	std::unique_ptr<Object> ooobj(&ooo);

	ObjectList.push_back(std::move(ooobj));

	Object oooo(false);
	std::unique_ptr<Object> oooobj(&oooo);

	ObjectList.push_back(std::move(oooobj));

	for(int i = 0; i < ObjectList.size(); i++)
	{
		ObjectList.erase(ObjectList.begin() + i);
	}

	for(int i = 0; i < ObjectList.size(); i++)
	{
		std::cout << "object is left";
	}

	while(true)
	{
	}

	return 0;
}

It is just so confusing. Does anyone know where I can find a tutorial on game data management or something? Thanks.

Edited by Solid_Spy

Share this post


Link to post
Share on other sites

 

std::unique_ptr is an object that holds a unique pointer; a pointer that no other std::unique_ptr can hold. Depending on the lifetimes of the objects, and the behavior of dead objects, you have some different options:

  1. If you the lifetime of objects in the master list is guaranteed to be longer than the lifetime of the pointers in the secondary list, then the secondary list can simply store plain pointers to the unique objects in the master list.
  2. If the objects can disappear from the master list and you want the secondary list to know about that, then I believe a master list of shared pointers and a secondary list of weak pointers is the way to go.
  3. If the objects can disappear from the master list but you want to keep them around as long as they are also in the in the secondary list, then two containers of shared pointers is the way to go.

 

Thanks for the help!

Share this post


Link to post
Share on other sites

I would exploit the behavior of constructors and destructors to manage the list for you.  Here is a toy example:

 

First the Collectable class, primary class types will inherit from this:

template<class tType> class Collectable
{
public:

	Collectable(void)
	{
		m_nMyIndex = ms_lstObjects.size();
		ms_lstObjects.push_back(this);
		
	}

	~Collectable(void)
	{
		if(ms_lstObjects.size() > 1)
		{
			Collectable* pTemp = ms_lstObjects.back();
			pTemp->m_nMyIndex = m_nMyIndex;
			ms_lstObjects[m_nMyIndex] = pTemp;
		}

		ms_lstObjects.pop_back();
	}

	static int32 NumObjects(void)
	{
		return (int32)ms_lstObjects.size();
	}

	static tType* GetObject(int32 a_nIndex)
	{
		return ms_lstObjects[a_nIndex];
	}

protected:
private:

	int32				m_nMyIndex;
	static std::vector<tType*>	ms_lstObjects;
};

template<class tType> std::vector<tType*> Collectable<tType>::ms_lstObjects;

Using Collectable would look something like this:

class ICollidable : public Collectable<ICollidable>
{
public:
	virtual void OnCollision(ICollidable* a_pObject) = 0;
};

class IUpdatable : public Collectable<IUpdatable>
{
public:
	virtual void Update(float32 a_fDeltaT) = 0;
};

bool Collide(ICollidable* a_pObjectA, ICollidable* a_pObjectB)
{
	bool bCollision = true; // perform collision code here

	if(bCollision)
		a_pObjectA->OnCollision(a_pObjectB);

	if(bCollision)
		a_pObjectB->OnCollision(a_pObjectA);

	return false;
}

Finally, game side code will take the convenient form:

	// Update...
	for(int32 i = 0; i < IUpdatable::NumObjects(); i++)
		IUpdatable::GetObject(i)->Update(1.0f / 3.0f);

	// Collision detection and response...
	for(int32 i = 0;   i < ICollidable::NumObjects(); i++)
	for(int32 j = i+1; j < ICollidable::NumObjects(); j++)
	{
		ICollidable* pObjectI = ICollidable::GetObject(i);
		ICollidable* pObjectJ = ICollidable::GetObject(j);
		Collide(pObjectI, pObjectJ);
	}

	// Render
	for(int32 i = 0; i < IRenderable::NumObjects(); i++)
		IRenderable::GetObject(i)->Render();

With this type of setup you can new and delete objects at will and not have to worry about managing lists of pointers for them.  There are subtleties involved; the ugliest one is that you can't call delete on object of a particular type while using the Collectable interface to iterate over that type without adjust the current iteration index.  This can be dealt with easily enough by deactivating objects and differing the actual deletion until the end of the frame.  Since each object knows where it is in each list you can easily shuffle or defrag the list from time to time (while executing deletions for example) so in-order iterations traverse linearly through memory improving cache performance.  Another advantage of this setup up is that Collectable forces you to deal with a single vtable at time (your initial stab at the problem has this advantage as well) also helping with cache performance.

Edited by nonoptimalrobot

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this