I'm trying to make a game with inheritance & interfaces and I'm wondering if my system could be working without ECS. (I explain at the end why I'm not using components).To make it easier to understand there are three core class families in the code:Engine related classes:Graphics, Inputs, Audio, Physics,...Using E~~~ as a prefix for each classInterfaces:I'm using them like properties, they don't contain data, they're contracts, like C# interfaces (and Java I believe?):Transformable, Destroyable, ...Using I~~~ as a prefix for each classConcrete classes:They contain data and implements the interfaces. The could be Player, Bullet, etc.Using C~~~ as a prefix for each classPlus a class named Engine that contains every E~~~ class so it makes it easy to access Engine elements.Engine-related code:class EInput {public:    enum { keyCount = 64 };    char state[keyCount];    char previousState[keyCount];};class EGraphics {public:    int width, height;};class EPhysics {public:    float gravity;};class EEngine {public:    EInput* input;    EGraphics* graphics;    EPhysics* physics;    EEngine() {        input = new EInput();        graphics = new EGraphics();        physics = new EPhysics();    }    ~EEngine() {        delete input;        delete graphics;        delete physics;    }};Interface-related code:class ITransformable {public:    virtual float getX() = 0;    virtual float getY() = 0;    virtual void setX(float x) = 0;    virtual void setY(float x) = 0;    virtual ~ITransformable() {}}; class IDestroyable {public:    virtual float getHp() = 0;    virtual void setHp(float hp) = 0;    virtual void hurt(float amount) = 0;    virtual void kill() = 0;    virtual bool isAlive() = 0;    virtual ~IDestroyable() {}};class IEngine {public:    virtual void provideEngine(EEngine* engine) = 0;    virtual ~IEngine() {}};class ITeam {public:    virtual int getTeam() = 0;    virtual void setTeam(int team) = 0;    virtual ~ITeam() {}};Concrete classes-related code:class CCharacter : public IEngine, public ITransformable, public IDestroyable, public ITeam {private:    /* IEngine */    EEngine* engine;    /* ITransformable */    float x, y;    /* IDestroyable */    float hp;    /* ITeam */    int team;public:    CCharacter() : engine(nullptr), x(0.f), y(0.f), hp(0.f) {}    /* IEngine */    void provideEngine(EEngine* engine) override { this->engine = engine; }    /* ITransformable */    virtual float getX() override { return x; }    virtual float getY() override { return y; }    virtual void setX(float x) override { this->x = x; }    virtual void setY(float x) override { this->y = y; }    /* IDestroyable */    virtual float getHp() override { return hp; }    virtual void setHp(float hp) override { this->hp = hp; }    virtual void hurt(float amount) override { this->hp -= amount; }    virtual void kill() override { this->hp = 0.f; }    virtual bool isAlive() override { return this->hp > 0.f; }    /* ITeam */    virtual int getTeam() override { return this->team; };    virtual void setTeam(int team) override { this-> team = team; };    virtual void update() = 0;    virtual void draw() = 0;};class CPlayer : public CCharacter {public:    CPlayer() {        setHp(100.f); //...    }    void update() override {}    void draw() override {}};enum { T_NONE, T_ALLY, T_ENEMY };class CAIPlayer : public CCharacter {private:    int team;public:    CAIPlayer() : team(T_NONE) {}    void update() override {}    void draw() override {}};And a game would be similar to this, removing the game loop:int main() {    EEngine engine;    //Initialize some values    {        EGraphics& g = *engine.graphics;        g.width = 512;        g.height = 288;        EPhysics& p = *engine.physics;        p.gravity = 0.4f;    }    //Create our characters, a factory would be used, this is just to show the idea    //Our hero    CPlayer sam; sam.provideEngine(&engine);    //Two friendlies    CAIPlayer lambert; lambert.provideEngine(&engine);    lambert.setTeam(T_ALLY);    CAIPlayer wilkes; wilkes.provideEngine(&engine);    wilkes.setTeam(T_ALLY);    wilkes.kill();    //The bad guy    CAIPlayer nikoladze; nikoladze.provideEngine(&engine);    nikoladze.setTeam(T_ENEMY);}Is this code clean?What are the limits of such a system? I mean, I don't see any duplicated behaviour.I read some really nice articles and questions on the net, including Stack Overflow, about entity-components-systems and how amazing it is, but it seems (to me) that it is overdone by people, the code is a big mess with templates everywhere and yet there are no results on the screen.I know that this code might be weak compared to ECS, but at which point?I'm trying to keep it simple.
Simple game engine layout
c++;game
I had a few thoughts whilst reading through your code:NamingI don't mind the I prefix for interfaces, I've never really liked C as a prefix for classes although I can live with it.  Having another prefix of E for engine specific classes feels wrong/confusing.  EEngine is a concrete class, that does stuff, why isn't it ECEngine / CEEngine for example?InterfacesSome of your interfaces don't really feel like interfaces.  For example, IEngine has one method provideEngine.  This isn't what I think of when I think of an Engine interface.  It could be an IEngineUser interface but it still feels a bit wrong.  I'd expect IEngine to define operations that were then implemented in EEngine.InitialisationYou're declaring variables and calling methods on them at the same time:CAIPlayer lambert; lambert.provideEngine(&engine);This seems error prone.  It also flags up a possible design error.  Does it make sense for a CAIPlayer to exist without an engine / without a team?  If not, then I would expect it to be passed into the constructor, rather than passed in immediately after every construction.  It seems like you've done it this way because of the interfaces you've declared which specify class dependencies rather than what a class can do...Public fieldsYou're passing an instance of EEngine into every class it has public pointers to other engine classes that have public fields.  This feels like way too much exposure of your engines implementation.  I would hide this information behind getter methods.  Then either pass the intial values into the constructor or provide setter methods.  Whilst they may be simple pass throughs initially it will easier in the future if you want to make changes such as supporting different gravity zones  Does it really make sense that at the moment any CCharacter can change the gravity in the game?