Using CoffeeScript style function bindings with MelonJS classes

MelonJS, if you haven't heard of it, is a nice little HTML5 game engine that I've been playing around with a bit lately. I haven't delved too deep yet, but it looks like the most appealing of the free options in that space so far.

While the experience has been mostly good, I had a minor hiccup: I've grown fond of CoffeeScript's ternseness, but MelonJS (and every other game engine) is very much JavaScript focused. Not that there's anything wrong with that.

MelonJS uses John Resig's neat little class implementation to handle inheritance. I'm a fan of this approach, (I used it myself before making the CoffeeScript switch), but it doesn't work all that well with CoffeeScript's fat arrow function bindings.

What will happen is something like the following:

me.ObjectEntity.extend({

  init: (x, y, settings) ->
    @parent(x, y, settings)
    me.input.registerPointerEvent('mousemove', me.game.viewport, @onHover)

  thinOnHover: (e) ->
    console.log '@ is the calling object. Doh'

  onHover: (e) =>
    console.log '@ is bound to window. Doh'
})

I ran in to the problem of not being able to use CoffeeCript's function bindings in these classes at all, which is a right pain. I don't mind not using CoffeeScript's classes in this case - the Resig style class implementation does much the same thing, so that's ok. But I'm spoiled, and not prepared to give up simple context bindings.

Not to worry, we can do something a little tricky to take advantage of CoffeeScript and still provide MelonJS with the right type of Objects. They can all get along.

All that's needed is to create CoffeeScript style classes and use them as a base for creating the MelonJS style ones:

class CustomerEntity

  constructor: (x, y, settings) ->
    @parent(x, y, settings)


  onHover: (e) =>
    console.log '@ is bound correctly, yay'


CustomerEntity.prototype.init = CustomerEntity
CustomerEntity = me.ObjectEntity.extend(CustomerEntity.prototype)

Here I'm creating a CoffeeScript class as normal, then copying the constructor method to its init. This way it has an init method with all the nice CoffeeScript method bindings in place.

The next step is to extend the MelonJS class with thi class prototype, and bam - everything's available, bound up nicely, and good to go.


comments powered by Disqus