如何创建 JS Canvas 自上而下的雨效果或反向扭曲速度

如何解决如何创建 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 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?