2

I want to add some trail effect to a moving object that will fade over time. This is what I've got so far:

game.Trail = me.Entity.extend({

  init:function (x, y, settings)
  {
    this._super(me.Entity, 'init', [
      x, y,
      {
        image: "ball",
        width: 32,
        height: 32
      }
    ]);

    (new me.Tween(this.renderable))
    .to({
        alpha : 0,
    }, 5000)
    .onComplete((function () {
        me.game.world.removeChild(this);
    }).bind(this))
    .start();
  },

  update : function (dt) {
    this.body.update(dt);
    return (this._super(me.Entity, 'update', [dt]) || this.body.vel.x !== 0 || this.body.vel.y !== 0);
  }
});

Demo (move with WASD or arrow keys)

Here is a link to the full project to test locally.

But I want to change the colors of the items in the trail in the same way the fading is done.

In phaser this could be done tinting the sprite, but I have no clue about how to achieve that on melonjs.

Note: if the effect can be done with basic shapes instead of images that will work too.

gman
  • 100,619
  • 31
  • 269
  • 393
chipairon
  • 2,031
  • 2
  • 19
  • 21

1 Answers1

2

With the melonJS canvas renderer, you'll have to add tinting by overriding the draw method on your sprite or renderable object. The CanvasRenderingContext2D API has some useful utilities for doing RGBA fills and so on that can tint the destination canvas. Since "tinting" is not built into melonJS, you'll need to keep a temporary canvas context to tint your sprites non-destructively.

Minimal example (non-destructive, but does not handle transparency well):

draw : function (renderer) {
    renderer.save();

    // Call superclass draw method
    this._super(me.Entity, "draw", [ renderer ]); // XXX: Assumes you are extending me.Entity

    // Set the tint color to semi-transparent red
    renderer.setColor("rgba(255, 0, 0, 0.5)");

    // Fill the destination rect
    renderer.fillRect(this.pos.x, this.pos.y, this.width, this.height);

    renderer.restore();
}

A more involved option is using the CanvasRenderingContext2D API to create the temporary canvas context; copy the original sprite to the texture, apply the tint while respecting transparency, using clip if you have to.


In the melonJS WebGL renderer, you just have to change the value of the global renderer color before the draw and restore the original value after. Minimal example:

draw : function (renderer) {
    renderer.save();

    // Set the tint color to semi-transparent red
    renderer.setColor("rgba(255, 128, 128, 1)");

    // Call superclass draw method
    this._super(me.Entity, "draw", [ renderer ]); // XXX: Assumes you are extending me.Entity

    renderer.restore();
}

This works in WebGL because the shader is already setup to multiply the source image by the global color value. You'll get a different color result from the CanvasRenderer option above because WebGL is happiest with premultiplied alpha. (In this example, the value of the blue and green components in the source image will be reduced by half, making the sprite appear more red.)

Feel free to play with it a bit, but in general you'll get far more control over rendering in WebGL, and in fact you have the option to customize the compositor and shaders if you need to do really crazy effects.

Jason Oster
  • 1,386
  • 1
  • 13
  • 17
  • This works perfectly. But why is the call to `this._super...` needed? I think it works without that line (check my link on your edited response). – chipairon Jul 16 '16 at 09:48
  • @chipairon Technically the existence of a "draw" method in a subclass will completely override the method in the superclass (from a classical inheritance point of view). The `draw` method on the `me.Entity` class does all of the drawing work, so if you forget to call this superclass method, your entity will not be drawn. Here is the documentation for melonJS's classical inheritance: http://melonjs.github.io/melonJS/docs/me.Object.html and the library on which it is based: https://github.com/parasyte/jay-extend#this_super – Jason Oster Jul 16 '16 at 18:39
  • Also, your entity in the [jsfiddle demo](https://jsfiddle.net/ruben_diaz/33pca05u/) does not have a sprite. The `draw` method on the superclass is a no-op in this specific case. – Jason Oster Jul 16 '16 at 18:47
  • Oh, I see. It didn't make sense to me because the `draw` method on me.Renderable is empty. Calling `this._super(me.Entity` does render my trail entity. Thanks! – chipairon Jul 17 '16 at 10:04
  • I've updated my answer with `me.Entity` to reduce confusion. – Jason Oster Jul 18 '16 at 00:21