I’ll put the code ahead first to give some context.

GameObject.h

#pragma once

#include "GameObjectInstance.h"
#include <vector>

class GameObject
{
public:
	GameObject(GameObject&);
	
	static GameObject& Instantiate();
	static void Destroy(GameObject& ref);
	
	void printCopiesInfo();

	GameObjectInstance& operator *();
	GameObjectInstance* operator ->();
	bool operator ==(const GameObject* ptr);
	bool operator ==(const GameObject& ptr);

	~GameObject();
private:
	GameObjectInstance* _instance;
	GameObject();

	std::vector<GameObject*> copies;

	void clearCopies(GameObject* copy);
	//GameObject& operator *();
	void operator =(const GameObject& org);
};

GameObject.cpp

#include "pch.h"
#include "GameObject.h"


GameObject & GameObject::Instantiate()
{
	GameObject* go = new GameObject();
	go->_instance = new GameObjectInstance();

	return *go;
}

void GameObject::Destroy(GameObject & ref)
{
	delete ref._instance;
	ref._instance = nullptr;

	ref.clearCopies(&ref);
}

void GameObject::printCopiesInfo()
{
	if (copies.empty())
	{
		printf("%s has not been copied.\n", _instance->toString().c_str());
	}
	else
	{
		printf("%s has %i copies.\n", _instance->toString().c_str(), copies.size());
		for (int i = 0; i < copies.size(); ++i)
		{
			printf("Copy(%i): %s\n", i, copies[i]->_instance->toString().c_str());
		}
	}
}

GameObjectInstance & GameObject::operator*()
{
	// TODO: insert return statement here

	return *_instance;
}

GameObjectInstance * GameObject::operator->()
{
	return _instance;
}

bool GameObject::operator==(const GameObject * ptr)
{
	if (ptr == nullptr)
		return _instance == (void*)ptr;
	return _instance == ptr->_instance;
}

bool GameObject::operator==(const GameObject & ptr)
{
	return _instance == ptr._instance;
}

GameObject::GameObject()
{
}

GameObject::GameObject(GameObject & org)
{
	_instance = org._instance;
	org.copies.push_back(this);
	this->copies.push_back(&org);
}


GameObject::~GameObject()
{
}

void GameObject::clearCopies(GameObject * original)
{
	if (original->copies.empty())
	{
		original->_instance = nullptr;
		return;
	}
	else
	{
		while (!original->copies.empty())
		{
			GameObject* cp = original->copies[original->copies.size()-1];
			original->copies.pop_back();
			cp->_instance = nullptr;
			clearCopies(cp);
		}
	}
}

void GameObject::operator=(const GameObject & org)
{
	this->_instance = org._instance;
}

main.cpp

        GameObject go = GameObject::Instantiate();
	GameObject goCopy = go;
	GameObject goCopyCopy = goCopy;
	GameObject goCopyCopy2 = goCopy;
	printLine(go->toString());

	go.printCopiesInfo();
	goCopy.printCopiesInfo();
	
	GameObject::Destroy(goCopy);
	if (go == nullptr)
	{
		printLine("Game object original nulled.");
	}
	else
		printLine("Nope. Not null");

	if (goCopy == nullptr)
	{
		printLine("Game object copy nulled.");
	}
	else
		printLine("Nope. Copy not null");

Now, it isn’t elegant at all! There is some issues with cleaning up the actual GameObject container itself, but the factory would manage that. This code is in a clean project from my entity architecture project while I try and work out the solution. So this works now, it can wrangle all the copies and their pointers, and nullify them when a game object is destroyed, irrespective of if it is the original or a copy being destroyed.

Problems with it are:

  • Containers aren’t cleaned up
  • Memory requirement and allocation is disgusting. Lot’s of cache misses.
  • Not suited for massive lists of copies (if 1 were copied many times.)
  • Doesn’t have the use case of going out of scope handled elegantly (destructor not made use of yet)

For the mean time, I’m quite happy I finally figured something out for it. I’ll have to move to integrating it into my main project, and incorporating it with the factory system. Also will require me to refactor the GameObject class.

What a good victory for today!! 🙂

Last modified: May 6, 2019

Author