如何解决如何创建 JS Canvas 自上而下的雨效果或反向扭曲速度
我想弄清楚如何创建画布雨效果,但从自上而下的角度来看。基本上这就像你低头看着地面,你看着雨在你周围落下,并以一个角度略微落到中心,但它在结束前落下很短的距离。除了一些非画布的游戏开发之外,我在搜索中没有看到任何内容。
我也在寻找不需要外部库的解决方案。
我已经能够修改一些扭曲速度效果代码来反转粒子的方向以落到背景而不是屏幕外,但它继续向中心无限远,而不是重绘或循环即将到来的粒子从屏幕外。
我认为这与这部分代码中粒子没有从屏幕上掉下来有关。我在这里是在正确的轨道上还是无法使用当前代码实现此效果?
clear();
const cx = w / 2;
const cy = h / 2;
const count = stars.length;
for (var i = 0; i < count; i++) {
const star = stars[i];
const x = cx + star.x / (star.z * 0.001);
const y = cy + star.y / (star.z * 0.001);
if (x < 0 || x >= w || y < 0 || y >= h) {
continue;
}
const d = star.z / 1000.0;
const b = 1000 - d * d;
putPixel(x,y,b);
}
这是我正在查看的完整代码。尝试解决此问题的任何帮助将不胜感激。
const canvas = document.getElementById("canvas");
const c = canvas.getContext("2d");
let w;
let h;
const setCanvasExtents = () => {
w = document.body.clientWidth;
h = document.body.clientHeight;
canvas.width = w;
canvas.height = h;
};
setCanvasExtents();
window.onresize = () => {
setCanvasExtents();
};
const makeStars = count => {
const out = [];
for (let i = 0; i < count; i++) {
const s = {
x: Math.random() * 1600 - 800,y: Math.random() * 900 - 450,z: Math.random() * 1000
};
out.push(s);
}
return out;
};
let stars = makeStars(1000);
const clear = () => {
c.fillStyle = "black";
c.fillRect(0,canvas.width,canvas.height);
};
const putPixel = (x,brightness) => {
const intensity = brightness * 255;
const rgb = "rgb(" + intensity + "," + intensity + "," + intensity + ")";
c.fillStyle = rgb;
c.fillRect(x,5,5);
};
const moveStars = distance => {
const count = stars.length;
for (var i = 0; i < count; i++) {
const s = stars[i];
s.z += distance;
while (s.z <= 1) {
s.z -= 10;
}
}
};
let prevTime;
const init = time => {
prevTime = time;
requestAnimationFrame(tick);
};
const tick = time => {
let elapsed = time - prevTime;
prevTime = time;
moveStars(elapsed * 1.5);
clear();
const cx = w / 2;
const cy = h / 2;
const count = stars.length;
for (var i = 0; i < count; i++) {
const star = stars[i];
const x = cx + star.x / (star.z * 0.001);
const y = cy + star.y / (star.z * 0.001);
if (x < 0 || x >= w || y < 0 || y >= h) {
continue;
}
const d = star.z / 1000.0;
const b = 1000 - d * d;
putPixel(x,b);
}
requestAnimationFrame(tick);
};
requestAnimationFrame(init);
body {
position: fixed;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
overflow: hidden;
margin: 0;
padding: 0;
}
<canvas id="canvas" style="width: 100%; height: 100%; padding: 0;margin: 0;"></canvas>
解决方法
除了你想要达到的效果,代码中还有一些其他的问题:
-
希望这个循环条件永远不会为真,否则它将无限运行:
while (s.z <= 1) { s.z -= 10; }
对于您想要实现的目标,此循环毫无意义。它应该被删除。
-
putPixel
的亮度参数需要一个介于 0 和 1 之间的值,但您传递给它的值通常会超出该范围:const d = star.z / 1000.0; const b = 1000 - d * d;
你需要在那里做
1 - d * d
。
然后为了您想要的效果,您需要:
- 保持按
z
排序的星星,这样您就可以轻松提取太远的星星,并将它们从数组中删除 - 每当您移除一颗星时,添加一个出现在“下一个”
z
层的新星,即当前第一颗星之前的星(最少z
)。 - 允许水滴从窗口外开始,因为当距离增加时,它们可能仍然可见
- 减少“像素”的大小也会很好,因为它们更远。
这是您的代码更新后的想法:
const canvas = document.getElementById("canvas");
const c = canvas.getContext("2d");
let w;
let h;
const setCanvasExtents = () => {
w = document.body.clientWidth;
h = document.body.clientHeight;
canvas.width = w;
canvas.height = h;
};
setCanvasExtents();
window.onresize = () => {
setCanvasExtents();
};
const makeStars = count => {
const out = [];
for (let i = 0; i < count; i++) {
const star = {
x: (Math.random() - 0.5) * w * 2,y: (Math.random() - 0.5) * h * 2,z: i * 1000 / count
};
out.push(star);
}
return out;
};
let stars = makeStars(4000);
const clear = () => {
c.fillStyle = "black";
c.fillRect(0,canvas.width,canvas.height);
};
const putPixel = (x,y,brightness,size) => {
const intensity = brightness * 255;
const rgb = "rgb(" + intensity + "," + intensity + "," + intensity + ")";
c.fillStyle = rgb;
c.fillRect(x,size,size);
};
const moveStars = distance => {
const count = stars.length;
for (let star of stars) {
star.z += distance;
}
for (let i = 0; stars[count - 1].z > 1000; i++) {
// Replace star
stars.pop();
stars.unshift({
x: (Math.random() - 0.5) * w * 2,z: stars[0].z - 1000/count // keep z ordered
});
}
};
let prevTime;
const init = time => {
prevTime = time;
requestAnimationFrame(tick);
};
const tick = time => {
let elapsed = time - prevTime;
prevTime = time;
moveStars(elapsed * 1.5);
clear();
const cx = w / 2;
const cy = h / 2;
const count = stars.length;
for (let star of stars) {
const x = cx + star.x / (star.z * 0.001);
const y = cy + star.y / (star.z * 0.001);
if (x < 0 || x >= w || y < 0 || y >= h) {
continue;
}
const distance = star.z / 1000;
const brightness = 1 - distance * distance;
const size = brightness * 5;
putPixel(x,size);
}
requestAnimationFrame(tick);
};
requestAnimationFrame(init);
body {
position: fixed;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
overflow: hidden;
margin: 0;
padding: 0;
}
<canvas id="canvas"></canvas>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。