I do not know phaser, but since you are also asking for plain canvas example, here is one for that:
FIFO buffer (array)
You can use a FIFO buffer (first-in-first-out) or a delay-buffer. Store the x and/or y value depending on your needs to the buffer. When the buffer is full according to predefined max value, the first value is thrown out.
Now you have the tail values you and they can now be rendered anyway you want.
Demo
Below we store just x. For the tail a gradient is defined. This will give the best/smoothest result, but you can also create an array with predefined color matching the entries in the fifo-buffer.
Just be aware that in that case you need to render solids only (no alpha) or the transition between each line segment will be visible.
And that is basically everything there is to it. Just make it fit in with your render cycle.
Performance tips:
- If you move in y-direction the gradient need to follow. Instead of creating a new gradient every time, use translate() for the player head. This will also translate the gradient line definition.
- Using typed array can improve performance if you need many/long tails. These are faster than list/node arrays but does not come with shift so you need to use a cyclic pointer instead.
- For the game in the video, just render a single tail once, the reuse it for the other heads.
- Instead of using shadow for glow as in the demo, use an image for the head with glow already applied.
var ctx = document.querySelector("canvas").getContext("2d");
ctx.fillStyle = "#fff";
var fifo = [], // fifo buffer to cycle older x values through
max = 30, // max positions stored in the buffer
i = 0, // just for demo, make x cycle on screen
size = 8, // draw size
x = 300, // x-pos from mousemove event
y = 30, // y-pos for player head
// make gradient for the tail stroke:
// Adjust range as needed
gradient = ctx.createLinearGradient(0, 30, 0, 280);
// brightest color on top, transparent color at bottom.
gradient.addColorStop(0, "#ccd");
gradient.addColorStop(1, "rgba(200,200,240,0)");
// set up canvas
ctx.strokeStyle = gradient;
ctx.lineWidth = 10;
ctx.lineJoin = "round";
ctx.lineCap = "square";
// glow effect (because we can.. :) )
ctx.shadowColor = "rgba(255,255,255,0.5)";
ctx.shadowBlur = 20;
ctx.canvas.onmousemove = function(e) {
var rect = this.getBoundingClientRect();
x = e.clientX - rect.left;
};
// main loop -
(function loop() {
// push new value(s) to fifo array (for demo, only x)
fifo.push(x);
// fifo buffer full? Throw out the first value
if (fifo.length > max) fifo.shift();
// render what we got;
ctx.clearRect(0, 0, 600, 480);
ctx.beginPath();
ctx.moveTo(fifo[0], y + fifo.length * size);
for(var t = 1; t < fifo.length; t++) {
ctx.lineTo(fifo[t], y + (fifo.length - t) * size);
}
ctx.stroke();
// draw main player head
ctx.translate(x, y);
ctx.rotate(0.25*Math.PI);
ctx.fillRect(-size*0.5, -size*0.5, size*2, size*2);
ctx.setTransform(1,0,0,1,0,0);
requestAnimationFrame(loop)
})();
canvas {background:#000}
<canvas width=600 height=360></canvas>