当前位置: 首页 > article >正文

HTML5+Canvas实现“飞蛇拜年”炫酷动画效果

HTML5+Canvas实现“飞蛇拜年”炫酷动画效果

先看运行效果:

源码如下:

<!DOCTYPE html>
<html>
<head>
    <title>飞蛇拜年</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            background: #000;
        }
        canvas {
            width: 100vw;
            height: 100vh;
        }
    </style>
</head>
<body>
<canvas id="canv"></canvas>
<script>
window.requestAnimFrame = (function() {
    return window.requestAnimationFrame ||
        function(callback) {
            window.setTimeout(callback, 1000 / 60);
        };
})();

// 核心变量
let c, ctx;
let H = 0; // 色相
let autoX = 0, autoY = 0; // 自动移动坐标
let angle = 0; // 旋转角度
let radius = 100; // 盘旋半径
const points = [];
const sparks = [];
let breath = 0; // 呼吸效果变量
let breathDirection = 1; // 呼吸方向(1为增大,-1为减小)

// 初始化
function init() {
    c = document.getElementById("canv");
    ctx = c.getContext("2d");
    c.width = window.innerWidth;
    c.height = window.innerHeight;
    
    // 窗口大小变化时重置
    window.addEventListener('resize', () => {
        c.width = window.innerWidth;
        c.height = window.innerHeight;
    });

    anim();

    // 每隔 3 秒变换一次 H,H 的变化会影响到蛇的颜色、火花颜色以及文字颜色。
    setInterval(() => {
        H = Math.random() * 360; // 随机生成新的色相
    }, 3000); // 3000 毫秒 = 3 秒
}

// 自动路径生成
function updateAutoPosition() {
    angle += 0.05; // 控制蛇的盘旋速度
    radius += Math.sin(angle*0.5)*0.2; // 运动半径随机波动路径
    
    // 中心点动态变化
    const centerX = c.width/2 + Math.sin(angle*0.7)*150;
    const centerY = c.height/2 + Math.cos(angle*0.5)*100;
    
    // 计算自动坐标
    autoX = centerX + Math.cos(angle) * radius;
    autoY = centerY + Math.sin(angle) * radius;
    
    // 随机生成火花
    if(Math.random() > 0.7) {
        sparks.push(new Spark(
            autoX, 
            autoY, 
            (Math.random()-0.5)*3, 
            (Math.random()-0.5)*3, 
            Math.random()*5
        ));
    }
}

// 动画循环
function anim() {
    updateAutoPosition();
    render();
    requestAnimFrame(anim);
}

// 渲染函数
function render() {
    ctx.globalCompositeOperation = "source-over";
    ctx.fillStyle = "hsla(0,0%,0%,0.1)";
    ctx.fillRect(0, 0, c.width, c.height);
    ctx.globalCompositeOperation = "lighter";
    
    ptSet(autoX, autoY);
    sprkSet();

    // 绘制呼吸效果的文字
    drawBreathingText();
}

// 点集处理
function ptSet(x, y) {
    if(points.length > 30) points.shift();
    points.push(new Point(x, y));
    
    if(points.length > 2) {
        for(let i=2; i<points.length; i++) {
            drawCurve(points[i-2], points[i-1], points[i]);
        }
    }

    // 绘制头部
    drawHead(x, y);
}

// 曲线(蛇)绘制
function drawCurve(p1, p2, p3) {
    ctx.beginPath();
    ctx.strokeStyle = `hsla(${H%360},95%,70%,0.8)`;
    ctx.shadowColor = `hsla(${H%360},100%,50%,0.5)`;
    ctx.shadowBlur = 15;
    ctx.lineWidth = 8;
    ctx.moveTo((p1.x + p2.x)/2, (p1.y + p2.y)/2);
    ctx.quadraticCurveTo(p2.x, p2.y, (p2.x + p3.x)/2, (p2.y + p3.y)/2);
    ctx.stroke();
}

// 绘制头部
function drawHead(x, y) {
    ctx.save();
    ctx.beginPath();
    ctx.arc(x, y, 12, 0, Math.PI * 2); // 头部是一个更大的圆
    ctx.fillStyle = `hsla(${H%360},100%,50%,1)`; // 头部颜色更亮
    ctx.shadowColor = `hsla(${H%360},100%,50%,0.8)`;
    ctx.shadowBlur = 20;
    ctx.fill();
    ctx.restore();
}

// 绘制呼吸效果的文字
function drawBreathingText() {
    ctx.save();
    ctx.font = `${60 + breath * 10}px Arial`; // 使用更大的字体
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    ctx.fillStyle = `hsla(${H%360},100%,50%,${0.8 + breath * 0.2})`; // 透明度
    ctx.shadowColor = `hsla(${H%360},100%,50%,0.5)`; // 文字阴影模糊
    ctx.shadowBlur = 4; // 文字阴影模糊半径
    ctx.fillText("蛇年快乐", Math.round(c.width / 2), Math.round(c.height / 2)); // 使用整数坐标
    ctx.restore();

    // 更新呼吸效果
    breath += 0.01 * breathDirection;
    if (breath > 1 || breath < 0) {
        breathDirection *= -1; // 反转呼吸方向
    }
}

// 点类
class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.color = `hsla(${H%360},95%,70%,0.8)`;
    }
}

// 火花系统
function sprkSet() {
    sparks.forEach((spark, i) => {
        spark.update();
        if(spark.y > c.height + 50) sparks.splice(i, 1);
    });
}

class Spark {
    constructor(x, y, vx, vy, life) {
        this.x = x;
        this.y = y;
        this.vx = vx;
        this.vy = vy;
        this.life = life;
        this.age = 0;
    }
    
    update() {
        this.x += this.vx;
        this.y += this.vy;
        this.vy += 0.15;
        this.age++;
        
        ctx.beginPath();
        ctx.arc(this.x, this.y, 2, 0, Math.PI*2);
        ctx.fillStyle = `hsla(${(H+this.age*2)%360},100%,50%,${1-this.age/30})`;
        ctx.fill();
    }
}

// 启动动画
init();
H = 250; // 初始色相值范围:0 到 360,对应色相环上的不同颜色
</script>
</body>
</html>

原文地址:https://blog.csdn.net/cnds123/article/details/145341240
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/522686.html

相关文章:

  • 3、从langchain到rag
  • 深入解析“legit”的地道用法——从俚语到正式表达:Sam Altman用来形容DeepSeek: legit invigorating(真的令人振奋)
  • 微机原理与接口技术期末大作业——4位抢答器仿真
  • ReentrantReadWriteLock源码分析
  • 90,【6】攻防世界 WEB Web_php_unserialize
  • SAP SD学习笔记28 - 请求计划(开票计划)之2 - Milestone请求(里程碑开票)
  • es数据同步
  • char 和 varchar
  • 初阶2 类与对象
  • 详细介绍 React Native 的动画系统。主要包括 Animated 组件的各种用法:
  • Java 大视界 -- Java 大数据与碳中和:能源数据管理与碳排放分析(66)
  • mysql索引 a
  • 本地Harbor仓库搭建流程
  • A7. Jenkins Pipeline自动化构建过程,可灵活配置多项目、多模块服务实战
  • 数据存储容量不足,查询性能下降的解决方法
  • 前端性能优化:HMR热更新和预获取加载
  • xxl-job面试题
  • 蓝桥杯:大小写转换(异或转换)
  • MoE的学习
  • hive:数据导入,数据导出,加载数据到Hive,复制表结构
  • DevEco Studio 4.1中如何创建OpenHarmony的Native C++ (NAPI)程序
  • 租房管理系统实现智能化租赁提升用户体验与运营效率
  • Businessman和businessmen
  • 使用PC版本剪映制作照片MV
  • 【PySide6快速入门】初识布局与QHBoxLayout、QVBoxLayout
  • 2021 年 6 月大学英语四级考试真题(第 2 套)——纯享题目版