Hi,
as some here i'm working on my own, little and insignificant game engine based on sfml. It's more as a general training than anything else.
I've got to a decent point, here's what i already have if you dont want to go straight to the quesiton:
-
Game engine class
- Game objects list (list<Object*>)
-
Main game loop, fixed timestep dynamic drawing. Each step:
- Call input(event) passing sfml events as they're polled for each object.
- Call move (see later)
- Call step for each object
- Handle objects destruction (objects aren't explicitely destroyed by user code, instead they set a flag and are deleted here.
-
Object class
- virtual functions for input, step, draw.
- animated sprite class
- Resource manager
- Async logger
Now, each Object has a private "move" method that is called each step for movement.
I then wanted to give a simple interface for collisions, but its getting difficult to do. (collision itself is already ready).
Ideally i wanted an actual game to define its own objects as children of Object, overriding the desired methods and adding any variable the user needs. However this goes in conflict with the way i wanted to structure collision. My idea for collision was:
- Add a list of "collider list" to game engine.
- Each "collider list" is a list of objects.
- When you create an object that will need to be checked for collision with by something, you add it to a collider list (for example i could have a collider list holding all walls).
- When i create a moving object which must perform a specific action on collision with a specific collider list, i add a pointer to that collider list to that object's "collisions list", and a function pointer to a function that takes (here comes the difficult part) Object* other as argument?
- While the game is running, when applying movement to a specific object a, the engine internally checks if there's a collision for each object b of each "collider list" c inside a's "collisions list", and for each b which collides, call the function associated with that c inside a.
Simplified base classes to follow this sequence (c++ looking pseudocode written on the fly, i might have missed something and don't look at memory management or private/public things, it's not actual code i'm using):
class Collider_list
{
std::list<Object*> list;
void remove(std::list<Object*>::iterator it)
{ list.erase(it); }
void insert(Object* o)
{ list.push_back(o); }
}
class Collisions_list
{
std::vector<Collider_list*> collider_lists;
std::vector<std::function<void(Object*, Object*)> > functions;
void add_collision(Collider_list* collider_list, std::function<void(Object*> function)
{
collider_lists.push_back(collider_list);
functions.push_back(function);
}
void check(Object* self)
{
for(size_t i = 0; i<collider_lists.size(); i++)
{
auto list = collider_lists[i];
for(auto other : list)
{
if(self.bounding_box.collide(other.bounding_box)
{
*(functions[i])(self, other);
}
}
}
}
}
class Object
{
std::vector<Collider_list::iterator> collider_lists; //know your position in all collider lists to remove yourself.
std::vector<Collider_list*> collider_lists_it; //know your position in all collider lists to remove yourself.
Collisions_list collisions_list;
~Object
{
for(size_t i = 0; i<collider_lists.size(); i++)
{ collider_lists[i].remove(collider_lists_it[i]); }
}
void move()
{
x += x_speed;//it's more complex but doesnt matter here
y += y_speed;
collisions_list.check(this);
}
public:
void add_collision(Collider_list* collider_list, std::function<void(Object*, Object*)> function)
{ collisions_list.add_collision(collider_list, function); }
}
The problem is i can only have Object* as an argument for collisions, and the user should instead be able to access the variables he set on his class that inherits from Object. Also even if i knew (and i dont) all the classes that a game based on the engine was going to make, i wouldn't be able to put the functions in that list, because the list specifies std::function<void(Object*, Object*)>, and not std::function<void(Ball*, Wall*)>
Example:
class Wall : public Object { bool sticky = false; } //sitcky is needed to explain the problem i have
class Ball : public Object{}
...
Collider_list* walls = Engine.create_collider_list();
Wall* tmp = nullptr;
for(size_t i=0; i<10; i++)
{
//create at {x, y} coordinates
tmp = Engine.create(new Wall({i, 0}));
walls.insert(tmp);
}
tmp->sticky = true; //here's a variable specific to Wall, not present in Object, that Ball will need when it handles the collision.
Ball* ball = Engine.create(new Ball({30, 30});
ball.add_collision(walls, /*some bouncing function that stops ball's movement if the wall has sticky set to bool*/);
I'm not sure if it's possible to work around this through some template metaprogramming. I never dug into that, and if it's possible i'd gladly take some advices for that.
The other option that came to my mind (which solves everything but i dont like), is the following:
A game actually uses Object directly, no inheritance with virtual functions overriding etcc. Instead Object will have a function pointer for all custom events that previously were virtual (input, step, etcc), and a map string-to-float. The user will always deal with Object, and "defining a new class" like a Ball would consist in creating a new instance of Object and assigning it a defined set of functions and pseudo-variables in the map.
Assuming the user knows what he's doing it's perfect, but the result is a sadly javascript-object feeling, which i totally dislike, with no safety nor type checks, where anything can be anything and you have to manually keep track of what is what. Yeah it would work, but yeah i'd prefer solutions that don't make c++ become javashit javascript for the rest of the program.
So, can templates do the magic?