Canvas |如何从 X 轴移动物体创建 Y 轴轨迹
Canvas | How do I create a Y-axis trail, from an X-axis moving object
我目前正在 Canvas/Phaser 制作游戏,我正在寻找以下问题的解决方案。
我需要从一个只在 X 轴上移动的物体制作 Y 轴轨迹,这样它看起来就像留下了灰尘轨迹。
然而,无论我在哪里看到人们都在用弹跳球或其他 X/Y 移动物体创建轨迹,这不是我想要创建的。
我正在使用 Phaser 游戏框架开发游戏,如果在这个框架内有解决方案那将是非常棒的,但是如果你能帮我提供一个纯粹的 canvas solution/idea也会很棒!
我希望我选择了正确的词来解释,下面我添加了一张图片和一个小视频来可视化我想要的最终结果。
我不知道移相器,但由于您还要求简单的 canvas 示例,这里有一个:
FIFO缓冲区(数组)
您可以使用 FIFO 缓冲区 (first-in-first-out) 或 delay-buffer。根据您对缓冲区的需要存储 x and/or y 值。根据预定义的最大值,当缓冲区已满时,第一个值将被丢弃。
现在您有了尾部值,现在可以根据需要渲染它们。
演示
下面我们只存储x。对于尾部,定义了一个梯度。这将给出 best/smoothest 结果,但您也可以创建一个数组,其预定义颜色与 fifo-buffer 中的条目相匹配。
请注意,在这种情况下,您只需要渲染实体(无 alpha),否则每个线段之间的过渡将可见。
这就是它的全部内容。只需使其适合您的渲染周期即可。
性能提示:
- 如果您在 y-direction 中移动,则需要遵循渐变。不是每次都创建一个新的渐变,而是对玩家头部使用 translate() 。这也将翻译渐变线定义。
- 如果需要 many/long 尾巴,使用类型化数组可以提高性能。这些比 list/node 数组快,但没有移位,因此您需要使用循环指针。
- 对于视频中的游戏,只渲染一次尾巴,其他头部重复使用它。
- 不要像演示中那样使用阴影来发光,而是使用已应用发光的图像作为头部。
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>
我目前正在 Canvas/Phaser 制作游戏,我正在寻找以下问题的解决方案。
我需要从一个只在 X 轴上移动的物体制作 Y 轴轨迹,这样它看起来就像留下了灰尘轨迹。
然而,无论我在哪里看到人们都在用弹跳球或其他 X/Y 移动物体创建轨迹,这不是我想要创建的。
我正在使用 Phaser 游戏框架开发游戏,如果在这个框架内有解决方案那将是非常棒的,但是如果你能帮我提供一个纯粹的 canvas solution/idea也会很棒!
我希望我选择了正确的词来解释,下面我添加了一张图片和一个小视频来可视化我想要的最终结果。
我不知道移相器,但由于您还要求简单的 canvas 示例,这里有一个:
FIFO缓冲区(数组)
您可以使用 FIFO 缓冲区 (first-in-first-out) 或 delay-buffer。根据您对缓冲区的需要存储 x and/or y 值。根据预定义的最大值,当缓冲区已满时,第一个值将被丢弃。
现在您有了尾部值,现在可以根据需要渲染它们。
演示
下面我们只存储x。对于尾部,定义了一个梯度。这将给出 best/smoothest 结果,但您也可以创建一个数组,其预定义颜色与 fifo-buffer 中的条目相匹配。
请注意,在这种情况下,您只需要渲染实体(无 alpha),否则每个线段之间的过渡将可见。
这就是它的全部内容。只需使其适合您的渲染周期即可。
性能提示:
- 如果您在 y-direction 中移动,则需要遵循渐变。不是每次都创建一个新的渐变,而是对玩家头部使用 translate() 。这也将翻译渐变线定义。
- 如果需要 many/long 尾巴,使用类型化数组可以提高性能。这些比 list/node 数组快,但没有移位,因此您需要使用循环指针。
- 对于视频中的游戏,只渲染一次尾巴,其他头部重复使用它。
- 不要像演示中那样使用阴影来发光,而是使用已应用发光的图像作为头部。
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>