Холст создает красивый эффект дождя

внешний интерфейс Canvas
Холст создает красивый эффект дождя

инструкция

В этой статье рассказывается о том, как использовать холст для рисования красивого эффекта дождя.Давайте сначала взглянем на окончательный эффект.
визуализация

объяснять

Посмотрите на картинку, чтобы проанализировать, какого эффекта нам нужно добиться.
1. Эффект падения капли дождя, перемещайте мышь, чтобы контролировать направление падения.
2. Капли дождя падают на маленькие капли воды, и направление движения маленьких капель воды такое же, как у мыши.
3. Капли дождя попадают в определенный диапазон координат мыши и распадаются на мелкие капли воды, направление движения которых совпадает с направлением движения мыши.

Хорошо, мы грубо разбиваем весь эффект на три эффекта, реализуем эти три эффекта, и все готово. Делаем шаг за шагом.

1. Эффект падения капли дождя, перемещайте мышь, чтобы контролировать направление падения.

Идея достижения всего эффекта заключается в том,
Изначально
Используйте массив для хранения объектов капли дождя.
Объект капли дождя имеет различные атрибуты для представления: координату x, координату y, длину, скорость падения, цвет капли и флаг, определяющий, следует ли ее удалить.
При обновлении анимации
Добавьте в массив определенное количество объектов с каплями дождя, затем пройдитесь по массиву, измените координаты x и y каждого объекта с каплями дождя и используйте холст для рисования двух точек в соответствии с координатами объекта с каплями дождя, которые подключены к образуют дождевую каплю.

Таким образом, основное внимание при достижении эффекта уделяется координатам.
При инициализации капли дождя
Координата капли дождя x: случайное число
Координата капли дождя по оси y: -100, это позволяет каплям дождя попадать из-за пределов видимой области.
При обновлении анимации
Капля дождя x координата:原x坐标的值 + speed * speedx
скорость — это фиксированное значение, представляющее скорость падения капель дождя,
speedx — это переменная, связанная с направлением движения мыши,
speedx = speedx + (maxspeedx - speedx) / 50

А maxspeedx — это значение, полученное в зависимости от направления движения мыши.
maxspeedx = (e.clientX - canvasEl.clientWidth / 2) / (canvasEl.clientWidth / 2),
e.clientX: значение расстояния мыши слева от видимой области
canvasEl.clientWidth: ширина всей видимой области
То есть speedx — это значение, которое постепенно приближается к maxspeedx.
Диапазон значений maxspeedx составляет от -1 до 1. Чем ближе значение к -1, тем левее направление, а чем ближе значение к 1, тем правее направление.
Почему бы просто не использовать maxspeedx?
Это сделано для того, чтобы скорость капель дождя не меняла направление так быстро, чтобы не сразу менять направление мыши, а чтобы была небольшая задержка, которая выглядит лучше.
Если используется maxspeedx, это эффект

Если вы используете speedx, это эффект

Координата y капли дождя:原y坐标的值 + speed
скорость такая же, как указано в координате x выше, это фиксированное значение, указывающее скорость падения капель дождя,

Хорошо, наконец, я использую холст для рисования двух точек в соответствии с координатами объекта капли дождя, а затем соединяю их, чтобы нарисовать каплю дождя.
Координаты первой точки относительно просты, непосредственно получаются координаты x и y объекта капли дождя, которые являются координатами этой точки.
Координаты второй точки:
x坐标 = 雨滴x坐标的值 + 雨滴长度 * speedx
y坐标 = 雨滴y坐标的值 + 雨滴长度
Наконец, когда эти две точки соединяются, получается линия, представляющая собой каплю дождя.

При установке координаты x снова используется переменная speedx, которая должна сделать направление капли дождя и направление падения капли одинаковым,
Когда speedx не используется, это тот случай

При использовании speedx это так

2. Капли дождя падают на маленькие капли воды, и направление движения маленьких капель воды такое же, как у мыши.

Идея здесь на самом деле несколько похожа на эффект выше
Изначально
Используйте массив для хранения объекта глобуса.
Маленькая капля воды на самом деле рисует дугу.
Небольшой объект капли воды имеет различные атрибуты для представления: координаты маленькой капли воды, скорость движения по оси x, скорость движения по оси y, радиус круга и флаг, чтобы определить, следует ли удали это.
При обновлении анимации
Добавьте в массив определенное количество объектов с небольшими каплями воды, затем пройдитесь по массиву, измените координаты x и y каждого объекта с небольшими каплями воды и используйте холст для рисования дуги в соответствии с атрибутами координат и атрибутами радиуса объекта. небольшой объект капли воды.

Поэтому в фокусе достижения эффекта по-прежнему находятся координаты
При инициализации маленькой капли воды
Маленькие капли воды появляются, когда капли дождя исчезают, поэтому координаты маленьких капель воды также основаны на координатах капель дождя.Удалите каплю дождя, и появятся несколько маленьких капель воды, а направление движения маленьких капель воды также является направлением капли дождя.Направление движения то же, поэтому упомянутая выше переменная скоростьx все равно понадобится,
小水珠x坐标: 删除的雨滴x坐标 + 删除的雨滴长度 * speedx
小水珠y坐标:删除的雨滴y坐标 + 删除的雨滴长度
При обновлении анимации
Здесь используются два свойства объекта «маленькая капля воды»: vx (скорость изменения значения по оси x) и vy (скорость изменения значения по оси y).
X-координата капли
vx = vx + speedx / 2
小水珠的x坐标 =原x坐标 + vx,

speedx: упомянутая выше переменная, связанная с направлением движения мыши.Функция здесь состоит в том, чтобы контролировать направление движения маленьких капель воды в том же направлении, что и в других направлениях.
speedx / 2, за исключением 2, чтобы сделать расстояние движения маленькой капли воды по оси x немного короче и выглядеть более реальным

Y-координата капли
vy = vy + gravity
小水珠的y坐标 = 原y坐标 + vy;,
ви: отрицательное число
гравитация: гравитация, положительное число, установленное на 0,5 в полном коде
Поскольку исходная координата y является положительным числом, значение координаты y маленькой капли воды будет сначала уменьшаться, а затем увеличиваться, чтобы достичь эффекта, при котором маленькая капля воды сначала поднимается, а затем падает.

Последнее, что нужно сделать, это использовать холст для рисования дуги в соответствии с атрибутами координат и атрибутами радиуса маленьких капель воды.Дуга является случайной.

3. Капли дождя попадают в определенный диапазон координат мыши и распадаются на мелкие капли воды, направление движения которых совпадает с направлением движения мыши.


Размер окружности на рисунке легко определить.Приняв, что радиус окружности равен 35, мы можем получить координаты мыши.Приняв координаты мыши за центр окружности и 35 за радиус , определяется размер круга.
Ключ в том, как определить, вошли ли капли дождя в этот диапазон, для чего требуется теорема Пифагора, см. рисунок.

Поскольку капля дождя представляет собой линию, соединяющую две точки, это зависит от того, входит ли капля в этот диапазон, то есть от координат точки ниже капли дождя, и от расстояния по прямой линии от мыши, которое является длиной линии АВ. сегмент на рисунке.

Теорема Пифагора: сумма квадратов двух прямоугольных сторон прямоугольного треугольника равна квадрату гипотенузы.

AB = Math.sqrt(BC*BC + AC * AC)

BC = капля дождя x координата - мышь x координата
AC = координата y капли дождя - координата y мыши
Метод Math.sqrt() используется для вычисления квадратного корня числа.

После того, как мы знаем расстояние по прямой линии от капли дождя до мыши по сравнению с радиусом круга, если оно больше радиуса, оно не находится в пределах диапазона, в противном случае это так.
Если он находится в пределах досягаемости, удалите капли дождя и нарисуйте несколько маленьких капель воды.

Суммировать

Для достижения этого эффекта проблема заключается в направлении, направлении капель дождя, направлении падения капель дождя, направлении движения маленьких капель воды, и они связаны с направлением движения мыши.После определения различных направлениях, в зависимости от расстояния, используйте холст для непрерывного рисования линий и рисует дугу.

полный код

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <style>
    * {
      margin: 0;
      padding: 0;
    }
  </style>
</head>
<body>
  <canvas id="canvas" style="position: absolute; height: 100%; width:100%;"></canvas>
  <script>
    window.onload = main;
    function main() {
      // 获取canvas元素
      var canvasEl = document.getElementById('canvas');
      var ctx = canvasEl.getContext('2d');
      // canvas画布的 背景颜色
      var backgroundColor = '#000';

      // canvas画布的宽 等于 可视区域的宽
      canvasEl.width = canvasEl.clientWidth;
      // canvas画布的高 等于 可视区域的高
      canvasEl.height = canvasEl.clientHeight;

      // 保存小水珠的数组
      // 雨滴下落后散成小水珠,小水珠就是一些圆弧
      var dropList = [];

      // 重力
      // 雨滴下落后散成小水珠,小水珠会先上升后下降,主要是因为 gravity 这个变量的缘故
      var gravity = 0.5;

      // 保存雨滴的数组
      // 每个雨滴 都是 画的一条线 
      var linelist = [];

      // 保存鼠标的坐标 
      // mousePos[0] 代表x轴的值,mousePos[1] 代表y轴的值 
      var mousePos = [0, 0];

      // 跟随鼠标, mouseDis 大小区域内的雨滴会消失,形成散落效果
      // 以mousePos为圆心,mouseDis为半径,这个范围内的雨滴 都会散开,形成许多小水珠
      var mouseDis = 35;

      // 更新一次动画,画lineNum 条雨滴,lineNum 值越大,下雨就越密集
      var lineNum = 3;

      // 跟随鼠标方向 变化下雨方向的 速度
      // 鼠标移动后,下雨的方向 会慢慢改变,主要靠speedx 这个变量
      var speedx = 0;

      // maxspeedx 为 speedx 可以取的最大值
      // 当 speedx = maxspeedx时,下雨方向 会 随鼠标移动方向立即改变
      var maxspeedx = 0;

      // 页面大小发生变化时,重置canvas画布大小
      window.onresize = function () {
        canvasEl.width = canvasEl.clientWidth;
        canvasEl.height = canvasEl.clientHeight;
      }

      //移动鼠标触发事件
      window.onmousemove = function (e) {
        //  设置mousePos 等于 鼠标坐标
        //  e.clientX 为距离 浏览器窗口可视区域 左边的距离
        //  e.clientY 为距离 浏览器窗口可视区域 上边的距离
        mousePos[0] = e.clientX;
        mousePos[1] = e.clientY;

        // 通过鼠标位置,设置 maxspeedx的值,取值范围是 -1 到 1
        // maxspeedx的值,关系到 
        // 1、雨滴的方向
        // 2、雨滴下落的方向
        // 3、雨滴下落方向 跟随 鼠标移动方向变化的速度
        // 4、小水珠的移动方向
        // 值越接近1,表示方向越向右
        // 值越接近-1,表示方向越向左
        maxspeedx = (e.clientX - canvasEl.clientWidth / 2) / (canvasEl.clientWidth / 2);
      }

      // 根据参数,返回一个rgb颜色,用于给雨滴设置颜色
      function getRgb(r, g, b) {
        return "rgb(" + r + "," + g + "," + b + ")";
      }

      // 画 一滴雨(一条线)
      function createLine(e) {
        // 随机生成 雨滴的长度
        var temp = 0.25 * (50 + Math.random() * 100);
        // 一个 line 对象,代表一个雨滴
        var line = {
          // 雨滴下落速度  
          speed: 5.5 * (Math.random() * 6 + 3),
          // 判断是否删除,值为true就删除
          die: false,
          // 雨滴x坐标 
          posx: e,
          // 雨滴y坐标 
          posy: -50,
          // 雨滴的长度
          h: temp,
          // 雨滴的颜色
          color: getRgb(Math.floor(temp * 255 / 75), Math.floor(temp * 255 / 75), Math.floor(temp * 255 / 75))
        };
        // 把创建好的line(雨滴)对象,添加到保存雨滴的数组
        linelist.push(line);
      }

      // 画一个小水珠(雨滴散开后的小水珠就是一个个的圆弧)
      function createDrop(x, y) {
        // 一个 drop 对象,代表一个圆弧
        var drop = {
          // 判断是否删除,值为true就删除
          die: false,
          // 圆弧圆心的x坐标 
          posx: x,
          // 圆弧圆心的y坐标 
          posy: y,
          // vx 表示 x轴的值 变化的速度
          vx: (Math.random() - 0.5) * 8,
          // vy 表示 y轴的值 变化的速度 取值范围:-3 到 -9
          vy: Math.random() * (-6) - 3,
          // 圆弧的半径
          radius: Math.random() * 1.5 + 1
        };
        return drop;
      }

      // 画一定数量的小水珠
      function madedrops(x, y) {
        // 随机生成一个数 maxi
        // maxi 代表要画小水珠的数量
        var maxi = Math.floor(Math.random() * 5 + 5);
        for (var i = 0; i < maxi; i++) {
          dropList.push(createDrop(x, y));
        }
      }

      // 开始调用update函数,更新动画
      window.requestAnimationFrame(update);
      // 更新动画
      function update() {
        // 如果保存小水珠的数组有内容
        if (dropList.length > 0) {
          // 遍历保存小水珠的数组
          dropList.forEach(function (e) {
            //设置e.vx,vx表示x坐标变化的速度
            // (speedx)/2 是为了,让小水珠 在x轴的移动距离短一点,看上去更真实点
            // 也使 小水珠的移动方向 和 雨滴方向,雨滴下落方向,鼠标移动方向相同
            e.vx = e.vx + (speedx / 2);
            e.posx = e.posx + e.vx;
			
			//设置e.vy,vy表示y坐标变化的速度
            // e.vy的范围是-3 到 -9,而这时e.posy(y坐标)一定是正值,所以 e.posy的值会先减小后增大
            // 也就是实现 雨滴散成小水珠,小水珠会先上升后下降的效果
            e.vy = e.vy + gravity;
            e.posy = e.posy + e.vy;

            // 如果 小水珠y坐标 大于 可视区域的高度,设置die属性为true
            // 小水珠如果超出可视区域就删除掉
            if (e.posy > canvasEl.clientHeight) {
              e.die = true;
            }
          });
        }

        // 删除 die属性为ture 的数组成员
        // 可视区域外的小水珠删除掉
        for (var i = dropList.length - 1; i >= 0; i--) {
          if (dropList[i].die) {
            dropList.splice(i, 1);
          }
        }

        // 设置下雨方向变换的速度,取值范围: -1 到 1
        // 当 speedx = maxspeedx时,下雨方向 会 随鼠标移动方向立即改变
        speedx = speedx + (maxspeedx - speedx) / 50;

        // 根据lineNum的值,画一定数量雨滴
        for (var i = 0; i < lineNum; i++) {
		  // 调用createLine 函数,参数是雨滴x坐标
          createLine(Math.random() * 2 * canvasEl.width - (0.5 * canvasEl.width));
        }

        // 设置结束线,也就是雨滴散开 形成许多小水珠的位置
        var endLine = canvasEl.clientHeight - Math.random() * canvasEl.clientHeight / 5;

        // 遍历保存雨滴的数组
        linelist.forEach(function (e) {

          // 利用勾股定理 确定一个范围,在这个范围内雨滴会散开形成小水珠
          // e.posx + speedx * e.h 是雨滴x坐标
          // e.posy + e.h 是雨滴y坐标
          var dis = Math.sqrt(((e.posx + speedx * e.h) - mousePos[0]) * ((e.posx + speedx * e.h) - mousePos[0]) + (e.posy + e.h - mousePos[1]) * (e.posy + e.h - mousePos[1]));

          // 如果在mouseDis区域内,就删除雨滴,画一些小水珠(圆弧)
          // 实现鼠标碰到雨滴,雨滴散成小水珠的效果
          if (dis < mouseDis) {
            // 删除 雨滴
            e.die = true;
            // 画一些小水珠(圆弧)
            madedrops(e.posx + speedx * e.h, e.posy + e.h);
          }

          // 如果雨滴超过 结束线,删除雨滴,画一些小水珠(圆弧)
          if ((e.posy + e.h) > endLine) {
            e.die = true;
            madedrops(e.posx + speedx * e.h, e.posy + e.h);
          }

          // 如果 雨滴 y坐标 大于 可视区域的高度,设置die属性为true
          // 如果 雨滴 超出可视区域就删除掉
          if (e.posy >= canvasEl.clientHeight) {
            e.die = true;
          } else {
            // 逐渐增加 雨滴 y坐标的值
            e.posy = e.posy + e.speed;

            // 变化雨滴 x坐标
            // * speedx 用来控制雨滴 下落 方向
            // 使 雨滴下落方向 和 鼠标移动方向相同
            e.posx = e.posx + e.speed * speedx;
          }
        });

        // 删除 die属性为ture 的数组成员
        // 鼠标区域内的,超过结束线的,可视区域外的雨滴删除掉
        for (var i = linelist.length - 1; i >= 0; i--) {
          if (linelist[i].die) {
            linelist.splice(i, 1);
          }
        }

        // 渲染
        render();
        // 递归调用 update,实现动画效果
        window.requestAnimationFrame(update);
      }

      // 渲染
      function render() {
        // 画一个和可视区域一样大的矩形
        ctx.fillStyle = backgroundColor;
        ctx.fillRect(0, 0, canvasEl.width, canvasEl.height);

        // 画雨滴效果
        ctx.lineWidth = 5;
        linelist.forEach(function (line) {
          ctx.strokeStyle = line.color;
          ctx.beginPath();
          ctx.moveTo(line.posx, line.posy);

          // * speedx 用来控制雨滴方向
          // 使 雨滴方向 和 鼠标移动方向相同
          ctx.lineTo(line.posx + line.h * speedx, line.posy + line.h);
          ctx.stroke();
        });

        // 画雨滴散开形成小水珠效果
        ctx.lineWidth = 1;
        ctx.strokeStyle = "#fff";
        dropList.forEach(function (e) {
          ctx.beginPath();
          ctx.arc(e.posx, e.posy, e.radius, Math.random() * Math.PI * 2, 1 * Math.PI);
          ctx.stroke();
        });

        // 解开注释,可看见鼠标范围
        /*
          ctx.beginPath();
          ctx.arc(mousePos[0], mousePos[1], mouseDis, 0, 2 * Math.PI);
          ctx.stroke();
        */
      }
    }
  </script>
</body>

</html>

Последнее слово
Этот эффект отsxq111 божествоЯ узнал это от великого бога, и друзья, которым это нравится, тоже могут пойти тудаgithubдай ему немногоstarОй.