实现带有轨迹的动态五角星动画效果 - 使用HTML5 Canvas

今天有位群友遇到一个流行拖尾的特效,实现的方法有很多,也可以直接让PE和UI直接实现,但是我们Html5 Canvas也可以实现,在本文中,我们将通过一个简单的HTML5 Canvas动画项目,介绍如何绘制动态五角星并为它们添加拖尾效果。通过这一过程,我们不仅能实现星星的动态运动,还能看到它们留下一条渐变消失的轨迹,创造出令人惊叹的星空效果。

一、HTML结构

HTML文档的结构非常简洁,主要包含了一个canvas元素,它用于呈现所有的绘图内容。我们将通过JavaScript来操作这个canvas,并动态更新其中的图形。

xml 复制代码
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Star with Trail</title>
    <style>
      body, html {
        margin: 0;
        height: 100%;
        overflow: hidden;
      }
      canvas {
        display: block;
        background: black;
      }
    </style>
  </head>
  <body>
    <canvas id="starCanvas"></canvas>
  </body>
</html>

二、Canvas设置与样式

首先,我们为canvas设置了一个全屏大小,使其填充整个浏览器窗口。通过window.innerWidthwindow.innerHeight获取窗口的宽高,确保动画在不同屏幕上都能完整显示。

ini 复制代码
const canvas = document.getElementById("starCanvas");
const ctx = canvas.getContext("2d");

// 设置画布大小
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

为了确保背景是黑色的,同时避免滚动条出现,我们在CSS中做了如下样式调整:

css 复制代码
body, html {
  margin: 0;
  height: 100%;
  overflow: hidden;
}
canvas {
  display: block;
  background: black;
}

三、五角星绘制函数

在这个动画中,我们使用了一个drawStar函数来绘制五角星。五角星是通过计算五个顶点位置来绘制的,顶点之间的角度是固定的。函数接受四个参数:x(星星的X坐标),y(Y坐标),radius(星星的半径),color(星星的颜色)。

ini 复制代码
function drawStar(x, y, radius, color) {
  const spikes = 5; // 五个尖刺
  const step = Math.PI / spikes;
  const rotation = (Math.PI / 2) * 3; // 初始旋转角度
  const outerRadius = radius;
  const innerRadius = radius / 2;

  ctx.beginPath();
  ctx.moveTo(x, y - outerRadius);

  for (let i = 0; i < spikes; i++) {
    ctx.lineTo(
      x + Math.cos(rotation + step * i) * outerRadius,
      y + Math.sin(rotation + step * i) * outerRadius,
    );
    ctx.lineTo(
      x + Math.cos(rotation + step * i + step / 2) * innerRadius,
      y + Math.sin(rotation + step * i + step / 2) * innerRadius,
    );
  }

  ctx.closePath();
  ctx.fillStyle = color;
  ctx.fill();
}

四、星星对象与轨迹

为了使星星具有动态效果,我们创建了一个Star类,包含了星星的位置、大小、速度以及其轨迹。星星会随时间不断更新其位置,并在其移动的过程中留下轨迹。

轨迹的消失效果通过记录每个轨迹点的时间戳来实现,随着时间的推移,轨迹的透明度会逐渐减小,直到完全消失。

kotlin 复制代码
class Star {
  constructor(x, y, size, speedX, speedY) {
    this.x = x;
    this.y = y;
    this.size = size;
    this.speedX = speedX;
    this.speedY = speedY;
    this.trail = []; // 存储轨迹
    this.trailLifetime = 1000; // 轨迹存活时间 3 秒
  }

  // 绘制星星和轨迹
  draw() {
    // 添加新的轨迹点
    this.trail.push({ x: this.x, y: this.y, time: Date.now() });

    // 清除已过期的轨迹点
    this.trail = this.trail.filter((point) => Date.now() - point.time < this.trailLifetime);

    // 绘制轨迹点
    for (let i = 0; i < this.trail.length; i++) {
      const trailPoint = this.trail[i];
      const alpha = 1 - (Date.now() - trailPoint.time) / this.trailLifetime; // 轨迹的透明度随时间变化
      ctx.beginPath();
      ctx.arc(trailPoint.x, trailPoint.y, this.size / 3, 0, Math.PI * 2);
      ctx.fillStyle = `rgba(255, 255, 255, ${alpha})`; // 轨迹点透明度
      ctx.fill();
    }

    // 绘制五角星
    drawStar(this.x, this.y, this.size, "white");
  }

  // 更新星星位置
  update() {
    this.x += this.speedX;
    this.y += this.speedY;

    // 随机改变速度,模拟不规则的运动
    this.speedX += (Math.random() - 0.5) * 0.2;
    this.speedY += (Math.random() - 0.5) * 0.2;

    // 如果星星超出屏幕,重置其位置
    if (this.x > canvas.width) this.x = 0;
    if (this.x < 0) this.x = canvas.width;
    if (this.y > canvas.height) this.y = 0;
    if (this.y < 0) this.y = canvas.height;
  }
}

五、创建并更新星星

我们创建了一个星星数组,数组中的每个星星对象都有独立的运动轨迹和动态效果。星星的位置和速度是随机生成的,但为了简化展示,我们先只生成一个较大的星星。

ini 复制代码
const stars = [];
for (let i = 0; i < 1; i++) {
  const size = Math.random() * 5 + 1;
  const speedX = Math.random() * 2 - 1;
  const speedY = Math.random() * 2 - 1;
  const star = new Star(
    canvas.width / 4,
    canvas.height / 4,
    10,
    Math.random() * 2 - 1,
    Math.random() * 2 - 1,
  );
  stars.push(star);
}

六、动画循环

为了让动画不断循环,我们使用requestAnimationFrame来创建一个平滑的动画效果。在每一帧,我们都清除画布,更新并绘制所有星星。

scss 复制代码
function animate() {
  ctx.clearRect(0, 0, canvas.width, canvas.height); // 清空画布
  for (let i = 0; i < stars.length; i++) {
    stars[i].update();
    stars[i].draw();
  }
  requestAnimationFrame(animate);
}

animate();

七、完整代码

ini 复制代码
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Star with Trail</title>
    <style>
      body,
      html {
        margin: 0;
        height: 100%;
        overflow: hidden;
      }
      canvas {
        display: block;
        background: black;
      }
    </style>
  </head>
  <body>
    <canvas id="starCanvas"></canvas>

    <script>
      const canvas = document.getElementById("starCanvas");
      const ctx = canvas.getContext("2d");

      // 设置画布大小
      canvas.width = window.innerWidth;
      canvas.height = window.innerHeight;

      // 五角星绘制函数
      function drawStar(x, y, radius, color) {
        const spikes = 5;
        const step = Math.PI / spikes;
        const rotation = (Math.PI / 2) * 3;
        const outerRadius = radius;
        const innerRadius = radius / 2;

        ctx.beginPath();
        ctx.moveTo(x, y - outerRadius);

        for (let i = 0; i < spikes; i++) {
          ctx.lineTo(
            x + Math.cos(rotation + step * i) * outerRadius,
            y + Math.sin(rotation + step * i) * outerRadius,
          );
          ctx.lineTo(
            x + Math.cos(rotation + step * i + step / 2) * innerRadius,
            y + Math.sin(rotation + step * i + step / 2) * innerRadius,
          );
        }

        ctx.closePath();
        ctx.fillStyle = color;
        ctx.fill();
      }

      // 星星对象
      class Star {
        constructor(x, y, size, speedX, speedY) {
          this.x = x;
          this.y = y;
          this.size = size;
          this.speedX = speedX;
          this.speedY = speedY;
          this.trail = []; // 存储轨迹
          this.trailLifetime = 1000; // 轨迹存活时间 3 秒
        }

        // 绘制星星和轨迹
        draw() {
          // 添加新的轨迹点
          this.trail.push({ x: this.x, y: this.y, time: Date.now() });

          // 清除已过期的轨迹点
          this.trail = this.trail.filter((point) => Date.now() - point.time < this.trailLifetime);

          // 绘制轨迹点
          for (let i = 0; i < this.trail.length; i++) {
            const trailPoint = this.trail[i];
            const alpha = 1 - (Date.now() - trailPoint.time) / this.trailLifetime; // 轨迹的透明度随时间变化
            ctx.beginPath();
            ctx.arc(trailPoint.x, trailPoint.y, this.size / 3, 0, Math.PI * 2);
            ctx.fillStyle = `rgba(255, 255, 255, ${alpha})`; // 轨迹点透明度
            ctx.fill();
          }

          // 绘制五角星
          drawStar(this.x, this.y, this.size, "white");
        }

        // 更新星星位置
        update() {
          this.x += this.speedX;
          this.y += this.speedY;

          // 随机改变速度,模拟不规则的运动
          this.speedX += (Math.random() - 0.5) * 0.2;
          this.speedY += (Math.random() - 0.5) * 0.2;

          // 如果星星超出屏幕,重置其位置
          if (this.x > canvas.width) this.x = 0;
          if (this.x < 0) this.x = canvas.width;
          if (this.y > canvas.height) this.y = 0;
          if (this.y < 0) this.y = canvas.height;
        }
      }

      // 创建星星
      const stars = [];
      for (let i = 0; i < 1; i++) {
        const size = Math.random() * 5 + 1;
        const speedX = Math.random() * 2 - 1;
        const speedY = Math.random() * 2 - 1;
        //   const star = new Star(Math.random() * canvas.width, Math.random() * canvas.height, size, speedX, speedY);
        // 创建一个大的星星
        const star = new Star(
          canvas.width / 4,
          canvas.height / 4,
          10,
          Math.random() * 2 - 1,
          Math.random() * 2 - 1,
        );

        stars.push(star);
      }

      // 动画循环
      function animate() {
        ctx.clearRect(0, 0, canvas.width, canvas.height); // 清空画布
        for (let i = 0; i < stars.length; i++) {
          stars[i].update();
          stars[i].draw();
        }
        requestAnimationFrame(animate);
      }

      animate();
    </script>
  </body>
</html>

八、总结

通过这段代码,我们成功实现了一个带有动态轨迹的五角星动画效果。你可以看到,每个星星都有自己的运动轨迹,并且随着时间的推移,轨迹会逐渐消失,给人一种真实的星星划过夜空的感觉。通过canvasarcbeginPath等方法,我们能够精确控制每个星星的外形和动画效果。此外,我们还通过随机的速度和位置来模拟星星的不规则运动,增加了动画的趣味性。

完结 撒花~

相关推荐
web组态软件2 小时前
BY组态-低代码web可视化组件
前端·低代码
react_in2 小时前
webpack 题目
前端·webpack
MarisolHu2 小时前
前端学习笔记-Vue篇-02
前端·vue.js·笔记·学习
学前端的小朱2 小时前
Webpack的基础配置
前端·webpack·node.js
小周同学_丶3 小时前
解决el-select数据量过大的3种方法
前端·vue.js·elementui
先知demons3 小时前
uniapp开发微信小程序笔记10-触底加载
前端·笔记·微信小程序·小程序·uni-app
每一天,每一步3 小时前
react antd不在form表单中提交表单数据,而是点查询按钮时才将form表单数据和其他查询条件一起触发一次查询,避免重复触发请求
前端·javascript·react.js
NoneCoder4 小时前
HTML5系列(9)-- Web Components
前端·html·html5
花之亡灵4 小时前
(笔记)vue3引入Element-plus
前端·javascript·vue.js
是程序喵呀4 小时前
CSS 盒子模型
前端·css