使用 HTML5 Canvas 实现动态蜈蚣动画

使用 HTML5 Canvas 实现动态蜈蚣动画

1. 项目概述

我们将通过 HTML 和 JavaScript 创建一个动态蜈蚣。蜈蚣由多个节段组成,每个节段看起来像一个小圆形,并且每个节段上都附带有"脚"。蜈蚣的头部会在画布上随机移动。
完整代码在底部!!!!!!!!!!!!

2. 项目实现步骤
2.1 设置 HTML 和 Canvas

首先,我们需要设置一个基本的 HTML 页面,并在页面中插入一个 <canvas> 元素。这是我们绘制动画的区域。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>动态蜈蚣动画</title>
    <style>
        body { margin: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #f0f0f0; }
        canvas { border: 1px solid #000; }
    </style>
</head>
<body>
    <canvas id="myCanvas" width="800" height="400"></canvas>
    <script src="script.js"></script>
</body>
</html>

在上面的代码中,我们定义了一个宽度为 800px,高度为 400px 的 canvas,并通过 script.js 文件来处理动画逻辑。

2.2 初始化蜈蚣的结构

蜈蚣的构成非常简单:它由多个节段组成,每个节段是一个小圆形。每个节段都有一个位置和角度,我们通过数组来保存每个节段的信息。在初始化时,蜈蚣的头部位于画布的中间,并且节段按顺序排列。

let segments = [];  // 存储每个节段的位置
const bodySegments = 20;    // 蜈蚣的节数
const segmentRadius = 10;   // 每个节段的半径
const segmentSpacing = 25;  // 节段之间的间距

// 初始化蜈蚣位置
function initMillipede() {
    for (let i = 0; i < bodySegments; i++) {
        segments.push({
            x: 100 + i * (segmentRadius * 2 + segmentSpacing), // 确保每个节段有间距
            y: canvas.height / 2,  // 初始化位置在画布中间
            angle: 0,  // 每个节段的初始角度
        });
    }
}
3. 绘制蜈蚣

蜈蚣的绘制分为多个部分:每个节段、头部、脚和尾巴。我们使用 canvas 的绘图 API 来绘制每个节段。每个节段是一个圆形,头部稍大,脚则是由短线条组成的。

function drawMillipede() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);  // 清除画布内容

    // 绘制蜈蚣的每一节
    for (let i = 0; i < segments.length; i++) {
        const segment = segments[i];
        ctx.save();
        ctx.translate(segment.x, segment.y);
        ctx.rotate(segment.angle);
        ctx.beginPath();
        ctx.arc(0, 0, segmentRadius, 0, Math.PI * 2);
        ctx.fillStyle = i % 2 === 0 ? "green" : "darkgreen"; // 交替颜色
        ctx.fill();
        ctx.restore();
    }

    // 绘制蜈蚣的头部(红色)
    ctx.save();
    ctx.translate(segments[0].x, segments[0].y);
    ctx.rotate(segments[0].angle);
    ctx.beginPath();
    ctx.arc(0, 0, segmentRadius * 1.5, 0, Math.PI * 2);
    ctx.fillStyle = "red"; // 蜈蚣头部的颜色
    ctx.fill();
    ctx.restore();
}
4. 蜈蚣的随机运动

蜈蚣的运动采用了随机的速度和方向。我们通过调整蜈蚣头部的速度(speedXspeedY)来实现蜈蚣在画布上随机移动。同时,我们对速度的变化进行了限制,以防蜈蚣的移动过快。

let speedX = 2;  // 蜈蚣头部水平方向的速度
let speedY = 2;  // 蜈蚣头部垂直方向的速度
let maxSpeed = 4; // 最大速度

function updateMillipede() {
    segments[0].x += speedX;
    segments[0].y += speedY;

    // 更新节段的位置和角度,逐步跟随前一个节段
    for (let i = segments.length - 1; i > 0; i--) {
        segments[i].x = segments[i - 1].x;
        segments[i].y = segments[i - 1].y;
        segments[i].angle = segments[i - 1].angle;
    }

    // 随机改变蜈蚣的运动速度,产生不规则的运动
    speedX += (Math.random() - 0.5) * 0.5;
    speedY += (Math.random() - 0.5) * 0.5;

    // 限制速度的范围
    speedX = Math.max(-maxSpeed, Math.min(maxSpeed, speedX));
    speedY = Math.max(-maxSpeed, Math.min(maxSpeed, speedY));

    // 如果蜈蚣头部超出画布的边界,则反弹
    if (segments[0].x > canvas.width || segments[0].x < 0) {
        speedX = -speedX;  // 反转水平方向的速度
    }
    if (segments[0].y > canvas.height || segments[0].y < 0) {
        speedY = -speedY;  // 反转垂直方向的速度
    }
}
5. 动画循环

为了实现持续的动画,我们使用 requestAnimationFrame 来创建一个动画循环。每一帧,我们更新蜈蚣的位置并重新绘制它。

function animate() {
    updateMillipede();  // 更新蜈蚣的位置和角度
    drawMillipede();    // 绘制蜈蚣

    requestAnimationFrame(animate);  // 请求下一帧
}

initMillipede();  // 初始化蜈蚣
animate();        // 启动动画循环
6. 完整代码

将上述代码整合,完整的实现如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>生动的蜈蚣动画</title>
    <style>
      body {
        margin: 0;
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
        background-color: black;
      }
      canvas {
        border: 1px solid white;
      }
    </style>
  </head>
  <body>
    <canvas id="myCanvas" width="800" height="400"></canvas>

    <script>
      // 获取 canvas 元素和上下文
      const canvas = document.getElementById('myCanvas');
      const ctx = canvas.getContext('2d');

      // 蜈蚣的参数
      const segmentRadius = 10; // 每个节段的半径
      const segmentSpacing = 1; // 节段之间的间距
      const bodySegments = 80; // 蜈蚣的节数
      const footLength = 15; // 脚的长度
      const footSpacing = 5; // 脚的间距

      let segments = []; // 存储每个节段的位置
      let angle = 0; // 角度,用于让蜈蚣做弯曲运动
      let speed = 5; // 蜈蚣移动的速度

      // 初始化蜈蚣位置
      function initMillipede() {
        for (let i = 0; i < bodySegments; i++) {
          segments.push({
            x: 100 + i * (segmentRadius + segmentSpacing),
            y: canvas.height / 2,
            angle: 0 // 每个节段的初始角度
          });
        }
      }
      // 绘制蜈蚣
      function drawMillipede() {
        // 清除之前的画布内容
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        // 绘制蜈蚣的每一节
        for (let i = 1; i < segments.length; i++) {
          const segment = segments[i];
          ctx.save();
          ctx.translate(segment.x, segment.y);
          ctx.rotate(segment.angle);
          ctx.beginPath();
          ctx.arc(0, 0, segmentRadius, 0, Math.PI * 2);
          ctx.fillStyle = `rgb(${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)})`; // 交替颜色
          ctx.fill();
          // 绘制脚
          drawFeet(segment, i);
          ctx.restore();
        }
        // 绘制蜈蚣的头部(红色)
        ctx.save();
        ctx.translate(segments[0].x, segments[0].y);
        ctx.rotate(segments[0].angle);
        ctx.beginPath();
        ctx.arc(0, 0, segmentRadius * 1.5, 0, Math.PI * 2);
        ctx.fillStyle = 'yellow'; // 蜈蚣头部的颜色
        ctx.fill();
        // 绘制头部触须
        drawAntennae(segments[0]);
        ctx.restore();
        // 绘制蜈蚣的尾巴
        drawTail(segments[segments.length - 1]);
      }
      // 绘制蜈蚣的脚
      function drawFeet(segment, index) {
        const footOffset = index % 2 === 0 ? -footSpacing : footSpacing;
        for (let i = 0; i < 2; i++) {
          // 每节有两只脚
          const angleOffset = i === 0 ? -Math.PI / 4 : Math.PI / 4; // 左右两只脚
          ctx.save();
          ctx.translate(0, 0);
          ctx.rotate(segment.angle + angleOffset);
          // 绘制脚
          ctx.beginPath();
          ctx.moveTo(0, segmentRadius);
          ctx.lineTo(footLength, segmentRadius + footOffset);
          ctx.lineWidth = 2;
          ctx.strokeStyle = 'white';
          ctx.stroke();
          ctx.restore();
        }
      }
      // 绘制头部的触须
      function drawAntennae(segment) {
        const antennaLength = 20;
        ctx.save();
        ctx.translate(0, 0);
        ctx.rotate(segment.angle);
        ctx.beginPath();
        ctx.moveTo(0, -segmentRadius * 1.5);
        ctx.lineTo(antennaLength, -segmentRadius * 1.5 - 10);
        ctx.moveTo(0, -segmentRadius * 1.5);
        ctx.lineTo(antennaLength, -segmentRadius * 1.5 + 10);
        ctx.lineWidth = 2;
        ctx.strokeStyle = 'white';
        ctx.stroke();
        ctx.restore();
      }
      // 绘制蜈蚣的尾巴
      function drawTail(segment) {
        const tailLength = 20;
        const tailAngle = Math.PI / 4; // 向下的角度
        ctx.save();
        ctx.translate(segment.x, segment.y);
        ctx.rotate(segment.angle + Math.PI);
        ctx.beginPath();
        ctx.moveTo(0, segmentRadius);
        ctx.lineTo(tailLength, segmentRadius + tailLength);
        ctx.lineWidth = 2;
        ctx.strokeStyle = 'green';
        ctx.stroke();
        ctx.restore();
      }
      // 更新蜈蚣的位置和角度
      function updateMillipede() {
        // 头部的运动轨迹:向右偏移
        segments[0].x += speed;
        segments[0].y += Math.sin(angle) * 3; // 头部上下波动

        // 更新节段的位置和角度,逐步跟随前一个节段
        for (let i = segments.length - 1; i > 0; i--) {
          segments[i].x = segments[i - 1].x;
          segments[i].y = segments[i - 1].y;
          segments[i].angle = segments[i - 1].angle;
        }
        // 更新头部的角度,给蜈蚣的运动加入弯曲感
        segments[0].angle += Math.sin(angle) * 0.1; // 使蜈蚣头部产生摇摆的效果
        // 改变角度来产生蜈蚣的弯曲运动
        angle += 0.1;
        // 如果蜈蚣头部超出画布的右边界,则回到左边
        if (segments[0].x > canvas.width) {
          segments[0].x = -segmentRadius * 2;
        }
      }
      // 动画循环
      function animate() {
        updateMillipede(); // 更新蜈蚣的位置和角度
        drawMillipede(); // 绘制蜈蚣
        requestAnimationFrame(animate); // 请求下一帧
      }
      // 初始化并开始动画
      initMillipede();
      animate();
    </script>
  </body>
</html>
7. 结尾

拜拜,彦祖,亦菲们

相关推荐
轻口味1 小时前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王2 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发2 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀2 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪3 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef4 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6415 小时前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻5 小时前
Vue(四)
前端·javascript·vue.js
蜜獾云5 小时前
npm淘宝镜像
前端·npm·node.js