The inheritance pattern has changed significantly, moving from John Resig Simple Inheritance to the new and fast Jay Inheritance, forcing various adjustments in the code. In the melonJS 1.0 and previous, you have something like:
// Before melonJS 1.1
var sprite = me.SpriteObject.extend({
// Property
active: yes,
// Constructor
init : function(x, y, sprite) {
this.parent(x, y, sprite);
},
// Draw
draw: function(context) {
// Draw only if is active
if (this.active)
this.parent(context);
}
});
To make performance improvements and enforce better rules you need to invoke a _super method (instead of parent), passing the base class itself, a string representing the method name, and an array of the arguments:
// After melonJS 1.1
var sprite = me.Sprite.extend({
// Constructor
init : function(x, y, sprite) {
this._super(me.Sprite, "init", [x, y, sprite]);
// Properties must be set in the init method only!
this.active = yes;
},
// Draw
draw: function(renderer) {
// Draw only if is active
if (this.active)
this._super(me.Sprite, "draw", [renderer]);
}
});
At first this change can scare, but the benefits with increased performance and reduced memory consumption compensate. For a more detailed explanation of the great new inheritance pattern, see the post about
Jay Inheritance.
For better performance, the me.Renderable, me.Rect, me.PolyShape and me.Ellipse now requires (x,y) integer values over a me.Vector2d instance:
// Before melonJS 1.1
var myRenderable = new me.Renderable(new me.Vector2d(20, 50), 200, 300);
var myRect = new me.Rect(new me.Vector2d(30, 60), 150, 50);
// After melonJS 1.1
var myRenderable = new me.Renderable(20, 50, 200, 300);
var myRect = new me.Rect(30, 60, 150, 50);
The
me.AnimationSheet now requires x, y and a settings hash to its constructor:
// Before melonJS 1.1
var animation = new me.AnimationSheet(10, 20, me.loader.getImage("sprite"), 64, 32);
// After melonJS 1.1
var animation = new me.AnimationSheet(10, 20, {
image: me.loader.getImage("sprite"),
spritewidth: 64,
spriteheight: 32
});
Come Get Some
For a faster execution time, the me.Entity (me.ObjectEntity in the previous version) has been redesigned using a composition approach (lowering the amount of object properties), instead of inheritance based design used in the previous version. In this way, the me.Entity has a new me.Body child object that will hold all physic and collision properties and functions.
// Before melonJS 1.1
var entity = me.ObjectEntity.extend({
// Constructor
init: function(x, y, settings) {
this.parent(x, y, settings);
// Set the gravity
this.gravity = 2;
// Set the velocity
this.setVelocity(5, 8);
},
// Update logic
update: function(dt) {
// Apply gravity
this.vel.y += this.gravity;
// Update entity Position
this.updateMovement();
this.parent(dt);
return true;
}
});
// After melonJS 1.1
var entity = me.Entity.extend({
// Constructor
init: function(x, y, settings) {
this._super(me.Entity, "init", [x, y, settings]);
// Set the gravity
this.body.gravity = 2;
// Set the velocity
this.body.setVelocity(5, 8);
},
// Update logic
update: function(dt) {
// Apply gravity
this.body.vel.y += this.body.gravity;
// Update entity Position
this.body.update();
this._super(me.Entity, "update", [dt])
return true;;
}
});
Thus, the following functions have been renamed or assigned through the me.Body child object:
// Physics Old Code -> Physics New Code
this.accel -> this.body.accel
this.canBreakTile -> this.body.canBreakTile
this.disableTopLadderCollision -> this.body.disableTopLadderCollision
this.falling -> this.body.falling
this.gravity -> this.body.gravity
this.jumping -> this.body.jumping
this.maxVel -> this.body.maxVel
this.onladder -> this.body.onladder
this.onslope -> this.body.onslope
this.shapes -> this.body.shapes
this.vel -> this.body.vel
this.addShape -> this.body.addShape
this.getShape -> this.body.getShape
this.setShape -> this.body.setShape
this.setFriction -> this.body.setFriction
this.setMaxVelocity -> this.body.setMaxVelocity
this.setVelocity -> this.body.setVelocity
this.collisionMap -> this.body.collisionMap
// Collision Old Code -> Collision New Code
this.updateMovement() -> this.body.update()
me.game.world.collide(this) -> me.collision.check(this, true, this.collideHandler.bind(this), true)
The melonJS 1.1 has now a full SAT collision algorithm, for polygon collision detection and more accurate collision response. The previous collision check function has therefore been deprecated and replaced by a new me.collision.check function. Refined collision filtering is now possible through the use of me.body.setCollisionMask function (that defines what should collide with what).
// Before melonJS 1.1
var entity = me.ObjectEntity.extend({
init: function(x, y, settings) {
// Call the constructor
this.parent(x, y , settings);
// Default velocity
this.setVelocity(3, 15);
},
// Update logic
update: function(dt) {
// Change velocity
this.vel.x -= this.accel.x * me.timer.tick;
// Check for collision with environment
this.updateMovement();
// Check for collision with enemies or objects
var res = me.game.world.collide(this);
if (res) {
// Change velocity
this.vel.y -= this.maxVel.y * me.timer.tick;
// Change position
this.pos.x -= 20;
}
this.parent(dt);
return true;
},
// Collision callback
onCollision: function() {
// Disable collision
this.collidable = false;
// Remove from game
me.game.world.removeChild(this);
}
});
// After melonJS 1.1
var entity = me.Entity.extend({
init: function(x, y, settings) {
// Call the constructor
this._super(me.Entity, 'init', [x, y , settings]);
// Default velocity
this.body.setVelocity(3, 15);
// Set the collision callback function
this.body.onCollision = this.onCollision.bind(this);
},
// Update logic
update: function(dt) {
// Change velocity
this.body.vel.x -= this.body.accel.x * me.timer.tick;
// Check for collision with environment
this.body.update();
// Check for collision with enemies or objects
me.collision.check(this, true, this.collideHandler.bind(this), true);
this._super(me.Entity, "update", [dt]);
return true;
},
// Collision handler
collideHandler: function(response) {
// Change velocity
this.body.vel.y -= this.body.maxVel.y * me.timer.tick;
// Change position
this.pos.x -= 20;
// Update the entity bounds since we manually changed the position
this.updateBounds();
},
// Collision callback
onCollision: function(res, obj) {
// Disable collision
this.body.setCollisionMask(me.collision.types.NO_OBJECT);
// Remove from game
me.game.world.removeChild(this);
}
});
In preparation to support WebGL, the me.video is now agnostic of rendering target, by adding the me.CanvasRenderer object, passing it to the draw calls of all the objects added to the world container and other subsequent containers.
// Before melonJS 1.1
draw: function(context) {
// Set the context color
context.fillStyle = "#FFFFFF";
// Draw a simple rectangle
context.fillRect(this.pos.x, this.pos.y, this.width, this.height);
}
// After melonJS 1.1 - Getting directly the context
draw: function(renderer) {
// Get the renderer context
var context = renderer.getContext();
// Set the context color
context.fillStyle = "#FFFFFF";
// Draw a simple rectangle
context.fillRect(this.pos.x, this.pos.y, this.width, this.height);
}
// After melonJS 1.1 - Using me.CanvasRenderer methods (recommended)
draw: function(renderer) {
// Draw a simple rectangle, using the integrated function
renderer.fillRect(this.pos.x, this.pos.y, this.width, this.height, "#FFFFFF");
}
Work Done
After the completion of the steps above, you must run the game performing various tests to detect possible adjustments or fixes to be made. For possible questions, use the
melonJS Forum or analyze directly the source code on
GitHub Repo.
Even with the extra work, the upgrade compensates for the awesome collision detection, fast inheritance, bug fixes and performance enhancements, in addition to being better prepared for the next melonJS version (in development), with the replacement of the current limited tile collision layer by a shape based collision layer and the probable addition of WebGL support! And you can enjoy to review some "obscure" or "hackish" code, using the best practices you acquired in recent times or to implement new features in your game.