https://github.com/S2DGames/S2DEC (https://github.com/S2DGames/S2DEC)
I have been working on this engine on and off for a while now. I mainly use it for game jams but I haven't really made any noteworthy games with it yet. I always seem to end up working on the engine more than the game whenever ludum dare comes around. Anyways back on topic.
I finally feel like the engine is at a point where someone else might be interested in using it if they knew about. So I'm not going to put off posting here any longer.
S2DEC is a 2d game engine that uses an entity component system for game objects and also utilizes box2d for physics.
I will edit this post tomorrow with a small tutorial because it is nearly 2am and I have to get up for work tomorrow. For now you can look in the game folder for am idea of how it works. https://github.com/S2DGames/S2DEC/tree/master/S2DEC/Games (https://github.com/S2DGames/S2DEC/tree/master/S2DEC/Games) pong is the best example in there. Snake runs like crap once you get a lot of segments and space invaders is not done or really even started.
Edit:
Here is a short overview of my engine. To use it, first create a game object passing the resolution and the window title like this Game game(1920, 1080, "Game title");
Next you can either initialize the game which will open the window, game.init();
or change other settings such as tell the game to open full screen game.setFullScreen();
Once we have the window set up the way we want, before or after initializing the window, we need to add our game objects to the game.
We do this by creating an entity Entity& entity = game.createEntity("entity name");
and add a component with entity.addComponent<SampleComponent>(/*paramaters to pass to the component constructor*/);
Here is the code for sample component which is just a box that moves around the screen depending on what arrow key you press. #pragma once
#include "Game.h"
using namespace S2D;
class SampleComponent : public Component{
private:
//stuff for box2d.
b2Body* body{nullptr};
b2BodyDef bodyDef;
b2PolygonShape shape;
b2Fixture* fixture{nullptr};
b2Vec2 velocity{0.0f, 0.0f};
sf::RectangleShape image;
sf::Vector2f size;
public:
SampleComponent(sf::Vector2f size) : size(size){
}
/**
* Called when this component is added to an Entity.
*/
void init() override{
//////////////////////////set up physics stuff////////////////////////////
bodyDef.type = b2_dynamicBody;
//start off in the center. note that we need to use this function to convert the window coordinates to physics world coordinates
bodyDef.position = sfTob2(game->getView().getCenter());
//Here we are using the same function on a single number as apposed to a vector
shape.SetAsBox(sfTob2(size.x / 2.0f), sfTob2(size.y / 2.0f));
//create the body
body = game->CreateBody(&bodyDef);
//we dont need this now but if this body were to collide with something, you need to set the user data so it is notified viea a callback function
body->SetUserData(this);
body->SetFixedRotation(true);
//create the fixture.
//a body does not have a shape unless it has a fixture
fixture = body->CreateFixture(&shape, 1.0f);
fixture->SetFriction(0.0f);
fixture->SetRestitution(1.0f);
//////////////////////////set up image stuff///////////////////////////////
image.setSize(size);
movesfTob2(image, body);
}
/**
* Called once every frame.
*/
void update(float frameTime) override{
//check keyboard keys. There are 4 states,
//KEY_PRESSED - The key was just pressed
//KEY_HELD - The key was pressed and is still being pressed
//KEY_RELEASED - The key was just released
//NOT_PRESSED - The key is not pressed and has not just been released
if(game->getKeyState(sf::Keyboard::Up) != NOT_PRESSED){
velocity.y -= 1.0f;
}
if(game->getKeyState(sf::Keyboard::Down) != NOT_PRESSED){
velocity.y += 1.0f;
}
if(game->getKeyState(sf::Keyboard::Left) != NOT_PRESSED){
velocity.x -= 1.0f;
}
if(game->getKeyState(sf::Keyboard::Right) != NOT_PRESSED){
velocity.x += 1.0f;
}
//set the velocity of the physics body
body->SetLinearVelocity(velocity);
//update the image position
movesfTob2(image, body);
//reser the velocity back to 0 so it only moves when a button is being pressed
velocity = {0.0f, 0.0f};
}
/**
* Called once every frame.
*/
void draw(sf::RenderTarget& target) override{
//lastly draw the image
target.draw(image);
}
};
Calling game.play();
will begin running the main loop of the game and will update and draw all objects that were added to the game. In this case, there is only one. You can also set the z of an entity which will determine the order it is drawn.
So you are basically adding another layer but also removing a little bit from Component. I'm not sure I like that.
The thing I have been trying to do while making this engine is minimize the code required to use any part as much as possible. Actually my first iteration of the engine was a non entity component engine that attempted to split up everything into pieces like have a PhysicsObject, DrawableObject, ManagerObject.... and it was a nightmare. Creating objects was really cool because you could do something like Object object<PhysicsObject, DrawableObject>();
and it would inherit those pieces. Then you would set the image and set up your physics stuff. But it was a pain to manage everything and I ran into a bunch of shortcomings that I couldn't get around. So i am trying to avoid splitting up things too much based off of that experience.
I think they were more of a result of the way I wanted to build game objects (like in my example). I used variadic templates to inherit different base classes. The biggest problem was with inter "component" communication. So essentialy my example would expand to something like this
public Object : public PhysicsObject, public DrawableObject...
Now, how do you go about moving the image to be in the same location as the physics body. You aren't writing the code in this class, it is being instantiated with the template parameters. Well you can put the position in a BaseObject class that all Objects will need to inherit then the physics object would modify this position and the image would pull from it. Because of that, you would not be able to have multiple images in an object or multiple physics objects either. It just got really restrictive and frustrating (to actually use to make a game with) not to mention it was not taking advantage of cpu caching nearly as much as data driven designs such as an entity component system does.
If you are using an entity component system and you are splitting up components successfully, then I say keep on working on it. You probably wont run into the same problems I was because I was trying to use variadic templates and template pack expansions and crazy c++11 features that I barely understood at the time.