The inevitable God object

Started by
21 comments, last by 100GPing100 10 years, 1 month ago

Well in my current simple game engine I split out the rendering from the rest of the game engine. Its sort of like a MVC framework (Model-View-Controller)., with the Renderer being the "view" and the Engine being the "controller". I also have a Scene object which fits into the Model. The GameEngine class is probably the closest it comes to the God class, but at least with the rendering and scene stuff split out, this should be a fair balance between responsibilities.

Advertisement

Its not so much about where to pack the data, you can go OOP and have a player object handle its own data. You can have a PlayerManager store a map of players. But when you want something outside, like a collision system to do operations on the players you need access to the private player map inside the PlayerManger. Now you gotta develop a whole system of messages and methods between the collision system and the PlayerManager, a total pain. And these are maybe tens of systems to interact with eachother.

In C++ I just created four template classes for having the event functionality from C#. A class can have event A and then interested objects can register themselves (becoming listeners) by providing a callback. Once the event is fired all the listeners get their callback called.

These are the classes (without guards):

EventListener.h


#include <functional>

//==============================
// Event Listener With Event Args
template<typename ST, typename T>
class EventListener
{
	std::function<void(ST, T)> _callback;

public:
	void operator ()(ST sender, T e)
	{
		_callback(sender, e);
	}

	EventListener(std::function<void(ST, T)> callback)
		: _callback(callback)
	{
	}
};

//==============================
// Event Listener Without Event Args
template<typename ST>
class EventListener<ST, void>
{
	std::function<void(ST)> _callback;

public:
	void operator ()(ST sender)
	{
		_callback(sender);
	}

	EventListener(std::function<void(ST)> callback)
		: _callback(callback)
	{
	}
};

EventSource.h


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

//==============================
// Event Source With Event Args
template<typename ST, typename T>
class EventSource
{
	std::vector<EventListener<ST, T>> _listeners;

	EventSource(const EventSource& x);
	EventSource& operator=(const EventSource& x);
public:
	inline bool isEmpty() { return (_listeners.size() == 0); }

	void operator +=(EventListener<ST, T> listener)
	{
		_listeners.push_back(listener);
	}
	void operator -=(EventListener<ST, T> listener)
	{
		for (auto it = _listeners.begin(); it != _listeners.end(); it++) {
			if ((*it) == listener) {
				_listeners.erase(it);
				return;
			}
		}
	}
	void operator ()(ST sender, T e)
	{
		for (auto it = _listeners.begin(); it != _listeners.end(); it++) {
			(*it)(sender, e);
		}
	}

	EventSource()
	{
	}
	~EventSource()
	{
	}
};

//==============================
// Event Source Without Event Args
template<typename ST>
class EventSource<ST, void>
{
	std::vector<EventListener<ST, void>> _listeners;

	EventSource(const EventSource& x);
	EventSource& operator=(const EventSource& x);
public:
	inline bool isEmpty() { return (_listeners.size() == 0); }

	void operator +=(EventListener<ST, void> listener)
	{
		_listeners.push_back(listener);
	}
	void operator +=(std::function<void(ST)> func)
	{
		this->operator+=(EventListener<ST, void>(func));
	}
	void operator -=(EventListener<ST, void> listener)
	{
		for (auto it = _listeners.begin(); it != _listeners.end(); it++) {
			if ((*it) == listener) {
				_listeners.erase(it);
				return;
			}
		}
	}
	void operator -=(std::function<void(ST)> func)
	{
		this->operator-=(EventListener<ST, void>(func));
	}
	void operator ()(ST sender)
	{
		for (auto it = _listeners.begin(); it != _listeners.end(); it++) {
			(*it)(sender);
		}
	}

	EventSource()
	{
	}
	~EventSource()
	{
	}
};

Here is a usage example:

Window.h


class Window
{
public:
	EventSource<Window *, void> KeyboardGotFocus;
	EventSource<Window *, void> KeyboardLostFocus;
	EventSource<Window *, void> MouseEnter;
	EventSource<Window *, void> MouseLeave;
	EventSource<Window *, EKey> KeyDown;
	EventSource<Window *, EKey> KeyUp;
	EventSource<Window *, EMouseButton> MouseDown;
	EventSource<Window *, EMouseButton> MouseUp;
        
        // bla, bla, function declarations
}

Window.cpp


void CWindow::OnKeyDown(EKey key)
{
	KeyDown(this, key);
}
void CWindow::OnKeyUp(EKey key)
{
	KeyUp(this, key);
}
void CWindow::OnKeyboardLostFocus()
{
	KeyboardLostFocus(this);
}
void CWindow::OnKeyboardGotFocus()
{
	KeyboardGotFocus(this);
}

This topic is closed to new replies.

Advertisement