2
\$\begingroup\$

NOTE: I am not familiar with a lot of terminology. If I am naming things incorrectly, please correct me!

Making small game engine for learning. Mostly using inheritance, but the more my project grows, the more I feel like objects are inheriting to much.

Example of inheriting classes:

Body // Base for x/y and width/height
  ↪Moveable
    ↪Drawable
      ↪Collidable

Not very clean. Parents are interchangeable with their children. Basically using inheritance primarily to organize my code and dump all the functionality into a big monster class.

Sometimes, inheriting everything makes sense, but not always. For example:

  • A "Player" would inherit everything. It can move, it needs to be drawn and it collides with other objects in the game
  • A "Tree" would only need "Body", "Drawable" and "Collidable" since it does not move
  • An "Area" would need "Body" and "Collidable" since it is invisible, static and only needs to know if something comes within its range

After researching, composition seems to be a good solution. Saw examples, but not exactly like the one I opted for where instances require on other instances from the parent. Child instances also have references to their parent.

function Tree(x, y){
    this.body = new Body(this, x, y, 100, 100);
    this.draw = new Drawable(this);
}

function Body(parent, x, y, width, height){
    this.parent = parent;

    this.x = x;
    this.y = y;

    this.width = width;
    this.height = height;

    this.getPosition = function(){ /* Returns x and y */ };
    this.getDimensions = function(){ /* Returns width and height */ };
}

function Drawable(parent){
    this.parent = parent;

    this.image = function(image){
        var position = this.parent.body.getPosition();
        var dimensions = this.parent.body.getDimensions();
        // Use image, position and dimensions to draw an image on a canvas
    }
}

Now if I wanted to draw the tree, I would do something like

tree = new Tree(500, 500);
tree.draw.image('tree.jpg');

I'm not sure if I am abusing the fact that JS objects are passed by reference to create my objects. The main drawback I see if that you need to know what requires what, but that doesn't seem hard to overcome. For example, "Drawable" needs the parent to have an instance of "Body" to work.

Is there something I'm missing or is this a good solution to implement?

\$\endgroup\$
1
\$\begingroup\$

In a case like this I would use mixins (though not everyone agrees when it comes to mixins vs composition). I would write this something like:

let BodyMixin = {
    getPosition:   function(){ /* Returns x and y */ };
    getDimensions: function(){ /* Returns width and height */ };
}

let DrawableMixin = {
   image: function(image) {
        var position   = this.getPosition();
        var dimensions = this.getDimensions();
        // Use image, position and dimensions to draw an image on a canvas
   }
}

function Tree(x, y){
}
Object.assign(Tree.prototype, BodyMixin, DrawableMixin);

Then your call would just be:

tree.image('tree.jpg');

Note: if you are using TypeScript or something similar there are other ways to implement mixins.

-- Update 1:

It might also be worth doing something like:

let BodyMixin = {
    initializeBody:      function(x,y,w,h) { ... };
    ...
}

function Tree(x, y){
    this.initializeBody(x, y, 100, 100); 
}
Object.assign(Tree.prototype, BodyMixin, DrawableMixin);
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.