Issue
I'm making a game in Canvas/Phaser at the moment and I'm looking for a solution for the following problem.
I need to make Y-axis trail from an object that only moves on the X-axis, so that it looks like it leaves a dust trail.
However, everywhere I look people are creating trail from bouncing balls or other X/Y moving objects, this is not what I want to create.
I am using the Phaser game framework to develop the game, if there is a solution within this framework that would be superb, but if you could help me with a pure canvas solution/idea that would be great too!
I hope I chose the right words for my explanation, below I added a picture and a small video that visualizes my wanted end result.
https://youtu.be/Fd7VOACEKig?t=22m32s
Solution
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>
Answered By - user1693593
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.