用canvas实现“鲤鱼跃龙门”~

# 创意投稿大赛 龙年春节

废话不多说,先看效果图

实现代码与思路如下:

第一步 添加canvas画布

html 复制代码
<body style="background-color: rgb(216, 249, 250);margin: 0px;">
    <canvas id="tutorial" width="1520" height="699"></canvas>
    <div class="text">
        <p>鲤鱼跃龙门</p>
        <p>冲呀!</p>
    </div>
</body>

第二步 获取canvas元素

js 复制代码
let canvas = document.getElementById("tutorial");
    //检查支持性
    if (canvas.getContext) {
        var ctx = canvas.getContext("2d"); // 获取渲染上下文
        // ToDo ...
    }

第三步 关于白云部分的绘制和动画

  • 白云的绘制
    用position数组统一设置白云的位置
js 复制代码
    var img = new Image();
    img.src = "./public/cloud.svg";
    var position = [{ x: 20, y: 520 }, { x: 350, y: 560 }, { x: 650, y: 490 }, { x: 930, y: 550 }, { x: 1230, y: 570 }]; //设置白云的位置
    
    img.onload = function () {
            // 开始动画    
        for (let i = 0; i < position.length; i++) {
            ctx.drawImage(img, position[i].x, position[i].y); // 每个图片间隔300像素
       }
    };
  • 白云的动画
    整体的思路就是,结合周期定时器动态设置globalAlpha属性去控制元素的显示与隐藏。
js 复制代码
        // 淡入淡出动画
        function fadeInOut(index) {
            var opacity = 1; // 初始透明度为1
            var increasing = true;
            // 每隔10毫秒执行一次淡入淡出效果
            var intervalId = setInterval(function () {
                var randomNum = Math.random();

                if (increasing) {
                    opacity += randomNum * 0.01; // 透明度逐渐增加
                    if (opacity >= 1) {
                        increasing = false; // 达到最大透明度后开始减少
                    }
                } else {
                    opacity -= randomNum * 0.01; // 透明度逐渐减小
                    if (opacity <= 0) {
                        // increasing = true;
                        clearInterval(intervalId); // 透明度减小到0后清除定时器
                        setTimeout(() => fadeInOut(index), 100); // 等待100ms后重新执行淡入淡出
                    }
                }
                imageOpacities[index] = opacity; // 更新图片透明度
                drawImage(); // 重新绘制

            }, 60);
        }

         // 绘制图片
        function drawImage() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            ctx.save(); // 保存当前绘制状态

            // 绘制之前的内容
            ctx.beginPath();
            ctx.moveTo(75, 25);
            //二次贝塞尔曲线
            ctx.quadraticCurveTo(25, 25, 25, 62.5);
            ctx.quadraticCurveTo(25, 100, 50, 100);
            ctx.quadraticCurveTo(50, 120, 30, 125);
            ctx.quadraticCurveTo(60, 120, 65, 100);
            ctx.quadraticCurveTo(125, 100, 125, 62.5);
            ctx.quadraticCurveTo(125, 25, 75, 25);
            ctx.stroke();

            ctx.drawImage(imgDoor, 250, -120);


            // ctx.drawImage(imgFish, 1150, 450, 200, 200);

            for (let i = 0; i < position.length; i++) {
                ctx.globalAlpha = imageOpacities[i];
                ctx.drawImage(img, position[i].x, position[i].y); // 每个图片间隔300像素
            }

            // 绘制鱼
            ctx.globalAlpha = fishOpacity;
            ctx.drawImage(imgFish, fishX, fishY, fishWidth, fishHeight);
            ctx.globalAlpha = 1 - fishOpacity;
            ctx.drawImage(imgDragon, 250, 100, 600, 600);
            ctx.restore(); // 恢复之前保存的绘制状态
        }
        
        
        
        //用处
        img.onload = function () {
            // 开始动画
            position.forEach((item, index) => {
                fadeInOut(index);
            });
        };

第四步 关于鱼的绘制和动画

js 复制代码
        // Fish 图片的初始位置和大小
        var fishX = 1150;
        var fishY = 450;
        var fishWidth = 200;
        var fishHeight = 200;
        // 鱼的透明度
        var fishOpacity = 1;
        
        // 跳跃动画
        function jumpAnimation() {
            var startY = fishY;
            var startx = fishX;
            var maxHeight = startY - 150; // 鱼的最高跳跃高度
            var speed = 2; // 跳跃速度
            var gravity = 0.1; // 重力加速度
            var isRising = true; // 是否处于上升状态

            var jumpInterval = setInterval(function () {
                // 鱼上升
                if (isRising) {
                    fishY -= speed;
                    fishX -= speed + 3;
                    if (fishY <= maxHeight) {
                        isRising = false;
                    }
                }
                // 鱼下落
                else {
                    fishY += speed;
                    fishX -= speed + 3;
                    if (fishY >= startY) {
                        clearInterval(jumpInterval);
                        // 开始消失效果
                        fadeOut();
                    }
                }

                drawImage(); // 重新绘制鱼
            }, 30);
        }

        // 消失效果
        function fadeOut() {
            var opacityDecrement = 0.05; // 透明度减少的步长
            var fadeInterval = setInterval(function () {
                fishOpacity -= opacityDecrement; // 透明度逐渐减小
                if (fishOpacity <= 0) {
                    fishOpacity = 0;
                    clearInterval(fadeInterval);
                }
                drawImage(); // 重新绘制鱼
            }, 50);
        }
 

        //用处
        imgFish.onload = function () {
            // 图片加载完成后开始动画
            setTimeout(function () {
                jumpAnimation(); // 1秒后开始跳跃动画
            }, 1000);
        };

第五步 关于对文字的样式

html 复制代码
<style>
    .text {
        position: absolute;
        top: 28px;
        left: 25px;
    }

    p {
        text-align: center;
        margin: 10px;
    }
</style>

就这,over over ~

祝大家新的一年 诸事顺遂 心想事成!

相关推荐
scc2140几秒前
spark的学习-06
javascript·学习·spark
焚琴煮鹤的熊熊野火2 分钟前
前端垂直居中的多种实现方式及应用分析
前端
我是苏苏22 分钟前
C# Main函数中调用异步方法
前端·javascript·c#
转角羊儿33 分钟前
uni-app文章列表制作⑧
前端·javascript·uni-app
大G哥40 分钟前
python 数据类型----可变数据类型
linux·服务器·开发语言·前端·python
hong_zc1 小时前
初始 html
前端·html
小小吱1 小时前
HTML动画
前端·html
Bio Coder1 小时前
学习用 Javascript、HTML、CSS 以及 Node.js 开发一个 uTools 插件,学习计划及其周期
javascript·学习·html·开发·utools
糊涂涂是个小盆友2 小时前
前端 - 使用uniapp+vue搭建前端项目(app端)
前端·vue.js·uni-app
浮华似水2 小时前
Javascirpt时区——脱坑指南
前端