Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Good Practice: How can I ensure a JavaScript constructor has access to mixin functions?

As part of an RPG game back-end, I want to be able to apply temporary effects to the characters. The nature of these effects could vary quite a lot, but I want to keep the method of defining them very straightforward.

I'm using custom event handling as a mixin:

var EvtObject = {};
$rpg.Event.enable(EvtObject); // Add the 3 methods and set EvtObject._events = {}

I want to define Auras (the temporary effects) as a constructor with event handling code:

var MyAura = function(any, args){
  this.group = "classification";
  this.on( "tick", function(){} );
  this.on( "remove", function(){} );
};

Then applied as MyCharacter.addAura(new MyAura(any, args));. As you can see, I want the this.on() function to be available in the constructor. If I extend the MyAura prototype with the mixin ($rpg.Event.enable(MyAura.prototype)) then every instance of MyAura references the same _events object from the prototype.

I want to know if the following solution is good practice:

Aura.create = function(Constructor)
{
    Constructor.prototype = Aura.getPrototype(); // Aura specific prototype

    return function()
    {
        var newAura = Object.create(Constructor.prototype);
        $rpg.Event.enable( newAura );
        Constructor.apply( newAura, arguments );
        return newAura;
    };

};

// Then creating new Auras:
var MyAura = $rpg.Aura.create(function(any, args){
  // this.on() is available
};
like image 234
Traverse Avatar asked Oct 09 '15 23:10

Traverse


1 Answers

There are characters (instances) acting in this game. Occasionally there is the need of enriching them by additional behavior or applying new roles, like an aura, to some of them.

A clean approach already uses traits/mixins at this point ...

If I extend the MyAura prototype with the mixin $rpg.Event.enable(MyAura.prototype)

... as it happens with the OP's provided example.

Since JavaScript at it's core level does provide mixin mechanics for free by a Function and delegation based pattern, ...

I want to define Auras (the temporary effects) as a constructor with event handling code:

... an Aura's implementation should be switched from it's constructor approach towards the so called Flight Mixin approach ...

var withAura = (function (Event) { // mixin module implementation .

  var
    tickHandler   = function () {},
    removeHandler = function () {},

    Mixin = function withAura (config) { // not a constructor but a function based "flight mixin".
      var aura = this;

      Event.enable(aura);

      aura.group = config.group;

      aura.on("tick", tickHandler);     // referencing ...
      aura.on("remove", removeHandler); // ...  shared code.
    }
  ;
  return Mixin;

}($rpg.Event));


var Player = (function () { // factory module implementation.

  var
    // ...
    // ...
    createPlayer = function (config) { // factory.
      var player = {};
      // ...
      // ...
      return player;
    }
  ;

  return {
    create: createPlayer
  };

}());


var somePlayer = Player.create(/*config*/);

At any given point within the game, enriching a players skill or behavioral set with an Aura, will be as straightforward as a one line delegation call ...

withAura.call(somePlayer, {group: "classification"});

Removing such behavior is another task and can be discussed afterwards/separately.

like image 168
Peter Seliger Avatar answered Oct 17 '22 01:10

Peter Seliger