zoukankan      html  css  js  c++  java
  • canvas烟花-娱乐

    网上看到一个释放烟花的canvas案例,很好看哦。

    新建文本,把下面代码复制进去,后缀名改为html,用浏览器打开即可。

    看懂注释后,可以自己修改烟花的各个效果。我试过让烟花炸成了心型。:-)

    <!DOCTYPE html>
    <html dir="ltr" lang="zh-CN">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width" />
        <title>HTML5 Canvas烟花特效 场景十分华丽在线演示</title>
        <style>
            /* basic styles for black background and crosshair cursor */
            body {
                background: #000;
                margin: 0;
            }
    
            canvas {
                cursor: crosshair;
                display: block;
            }
        </style>
    
    </head>
    <body>
        <div style="text-align:center;clear:both">
            <script src="/gg_bd_ad_720x90.js" type="text/javascript"></script>
            <script src="/follow.js" type="text/javascript"></script>
        </div>
        <canvas id="canvas">Canvas is not supported in your browser.</canvas>
        <script>
            // 当动画在canvas上,最好使用requestAnimationFrame代替setTimeout和setInterval
            // 不支持在所有的浏览器,有时需要一个前缀,所以我们需要一个重置
            window.requestAnimFrame = (function () {
                return window.requestAnimationFrame ||
                            window.webkitRequestAnimationFrame ||
                            window.mozRequestAnimationFrame ||
                            function (callback) {
                                window.setTimeout(callback, 1000 / 60);
                            };
            })();
    
            // 设置基本变量
            var canvas = document.getElementById('canvas'),
                    ctx = canvas.getContext('2d'),
                    // 全屏幕尺寸
                    cw = window.innerWidth,
                    ch = window.innerHeight,
                    // firework collection 烟花集合
                    fireworks = [],
                    // particle collection 爆炸粒子集合
                    particles = [],
                    // starting hue 开始色调
                    hue = 120,
                    // when launching fireworks with a click, too many get launched at once without a limiter, one launch per 5 loop ticks
                    // 通过点击释放烟花没有限制,每5次循环释放一次
                    limiterTotal = 5,
                    limiterTick = 0,
                    // this will time the auto launches of fireworks, one launch per 80 loop ticks
                    // 自动发射80循环一次
                    timerTotal = 20,
                    timerTick = 0,
                    mousedown = false,
                    // mouse x coordinate  X坐标
                    mx,
                    // mouse y coordinate  Y坐标
                    my;
    
            // set canvas dimensions 设置画布尺寸
            canvas.width = cw;
            canvas.height = ch;
    
            // now we are going to setup our function placeholders for the entire demo
    
            // get a random number within a range
            // 获取范围内随机数
            function random(min, max) {
                return Math.random() * (max - min) + min;
            }
    
            // calculate the distance between two points
            // 计算两点距离
            function calculateDistance(p1x, p1y, p2x, p2y) {
                var xDistance = p1x - p2x,
                        yDistance = p1y - p2y;
                return Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
            }
    
            // 创建烟花
            function Firework(sx, sy, tx, ty) {
                // actual coordinates  实际坐标
                this.x = sx;
                this.y = sy;
                // starting coordinates  开始坐标
                this.sx = sx;
                this.sy = sy;
                // target coordinates  目标坐标
                this.tx = tx;
                this.ty = ty;
                // distance from starting point to target  计算飞行距离
                this.distanceToTarget = calculateDistance(sx, sy, tx, ty);
                this.distanceTraveled = 0;
                // track the past coordinates of each firework to create a trail effect, increase the coordinate count to create more prominent trails
                // 追踪每个烟花经过的坐标,来创建一个跟踪效果,增加坐标数量来创造更多杰出的轨迹
                this.coordinates = [];
                this.coordinateCount = 3;
                // populate initial coordinate collection with the current coordinates
                // 填充初始坐标集合与当前坐标
                while (this.coordinateCount--) {
                    this.coordinates.push([this.x, this.y]);
                }
                this.angle = Math.atan2(ty - sy, tx - sx); // 从x轴到指定坐标点(x, y)的角度(以弧度为单位)
                this.speed = 2;  // 速度
                this.acceleration = 1.05;  // 加速度
                this.brightness = random(50, 70);  // 亮度
                // circle target indicator radius
                // 圆形目标指示器半径
                this.targetRadius = 1;
            }
    
            // update firework  更新烟花
            Firework.prototype.update = function (index) {
                // remove last item in coordinates array 删除烟花坐标数组里最后一个坐标
                this.coordinates.pop();
                // add current coordinates to the start of the array 当前的坐标添加到烟花坐标数组的开始
                this.coordinates.unshift([this.x, this.y]);
    
                // 循环圆形目标指示器半径
                if (this.targetRadius < 8) {
                    this.targetRadius += 0.3;
                } else {
                    this.targetRadius = 1;
                }
    
                // speed up the firework  烟花速度
                this.speed *= this.acceleration;
    
                // get the current velocities based on angle and speed
                // 获取x,y两个方向的速度
                var vx = Math.cos(this.angle) * this.speed,
                        vy = Math.sin(this.angle) * this.speed;
                // how far will the firework have traveled with velocities applied?
                // 烟花会随速度飞行多远
                this.distanceTraveled = calculateDistance(this.sx, this.sy, this.x + vx, this.y + vy);
    
                // if the distance traveled, including velocities, is greater than the initial distance to the target, then the target has been reached
                // 如果距离, 包括速度大于初始距离的目标, 那么目标已经达到
                if (this.distanceTraveled >= this.distanceToTarget) {
                    createParticles(this.tx, this.ty); // 创建粒子
                    // remove the firework, use the index passed into the update function to determine which to remove
                    // 删除烟花,使用索引传递到更新函数来确定删除
                    fireworks.splice(index, 1);
                } else {
                    // target not reached, keep traveling 目标没有达到,继续飞行
                    this.x += vx;
                    this.y += vy;
                }
            }
    
            // draw firework 绘制烟花
            Firework.prototype.draw = function () {
                ctx.beginPath();
                // move to the last tracked coordinate in the set, then draw a line to the current x and y
                // 移动到最后一个跟踪坐标,然后画一条线到当前的x和y
                ctx.moveTo(this.coordinates[this.coordinates.length - 1][0], this.coordinates[this.coordinates.length - 1][1]);
                ctx.lineTo(this.x, this.y);
                // 色调(0或360表示红色,120表示绿色,240表示蓝色);饱和度;亮度
                ctx.strokeStyle = 'hsl(' + hue + ', 100%, ' + this.brightness + '%)';
                ctx.stroke();
    
                ctx.beginPath();
                // draw the target for this firework with a pulsing circle
                // 使用圆跳动画这个烟花的目标点
                ctx.arc(this.tx, this.ty, this.targetRadius, 0, Math.PI * 2); // 画圆
                ctx.stroke();
            }
    
            // create particle  创建爆炸粒子
            function Particle(x, y) {
                this.x = x;
                this.y = y;
                // track the past coordinates of each particle to create a trail effect, increase the coordinate count to create more prominent trails
                // 追踪每个爆炸粒子经过的坐标,来创建一个跟踪效果,增加坐标数量来创造更多杰出的轨迹
                this.coordinates = [];
                this.coordinateCount = 5;
                while (this.coordinateCount--) {
                    this.coordinates.push([this.x, this.y]);
                }
                // set a random angle in all possible directions, in radians
                // 在所有可能的方向,设置一个随机角弧度
                this.angle = random(0, Math.PI * 2);
                this.speed = random(1, 10);
                // friction will slow the particle down 摩擦会使粒子慢下来
                this.friction = 0.95;
                // gravity will be applied and pull the particle down  重力将应用粒子拉下来
                this.gravity = 2;
                // set the hue to a random number +-20 of the overall hue variable
                // 在烟花色度范围内随机取爆炸粒子色度
                this.hue = random(hue - 50, hue + 50);
                this.brightness = random(50, 80);
                this.alpha = 1;
                // set how fast the particle fades out  设置粒子消失的速度
                this.decay = random(0.015, 0.03);
            }
    
            // update particle  更新爆炸粒子
            Particle.prototype.update = function (index) {
                // remove last item in coordinates array  删除爆炸粒子坐标数组里最后一个坐标
                this.coordinates.pop();
                // add current coordinates to the start of the array  当前的坐标添加到爆炸粒子坐标数组的开始
                this.coordinates.unshift([this.x, this.y]);
                // slow down the particle  减缓粒子
                this.speed *= this.friction;
                // apply velocity
                this.x += Math.cos(this.angle) * this.speed;
                this.y += Math.sin(this.angle) * this.speed + this.gravity;
                // fade out the particle 粒子消失参数
                this.alpha -= this.decay;
    
                // remove the particle once the alpha is low enough, based on the passed in index
                // 删除粒子,使用索引传递到更新函数来确定删除
                if (this.alpha <= this.decay) {
                    particles.splice(index, 1);
                }
            }
    
            // draw particle  绘制爆炸粒子
            Particle.prototype.draw = function () {
                ctx.beginPath();
                // move to the last tracked coordinates in the set, then draw a line to the current x and y
                // 移动到最后一个坐标跟踪设置,然后画一条线到当前的x和y
                ctx.moveTo(this.coordinates[this.coordinates.length - 1][0], this.coordinates[this.coordinates.length - 1][1]);
                ctx.lineTo(this.x, this.y);
                // 色调(0或360表示红色,120表示绿色,240表示蓝色);饱和度;亮度
                ctx.strokeStyle = 'hsla(' + this.hue + ', 100%, ' + this.brightness + '%, ' + this.alpha + ')';
                ctx.stroke();
            }
    
            // create particle group/explosion  创建爆炸粒子组
            function createParticles(x, y) {
                // increase the particle count for a bigger explosion, beware of the canvas performance hit with the increased particles though
                // 增加粒子数创造更大的爆炸,谨防增加粒子造成canvas与性能影响
                var particleCount = parseInt(random(20, 50));
                while (particleCount--) {
                    particles.push(new Particle(x, y));
                }
            }
    
            // 主循环
            function loop() {
                // this function will run endlessly with requestAnimationFrame
                // 这个函数将无限运行requestAnimationFrame
                requestAnimFrame(loop);
    
                // increase the hue to get different colored fireworks over time
                // 增加颜度,随着时间的推移得到不同颜色的烟火
                hue += random(0.5,10);
    
                // normally, clearRect() would be used to clear the canvas
                // we want to create a trailing effect though
                // setting the composite operation to destination-out will allow us to clear the canvas at a specific opacity, rather than wiping it entirely
                // 设置复合操作destination-out将使我们能够把画布清理在在一个特定的不透明度,而不是完全抹去它
                ctx.globalCompositeOperation = 'destination-out'; // 在源图像外显示目标图像。只有源图像外的目标图像部分会被显示,源图像是透明的。
                // decrease the alpha property to create more prominent trails
                // 降低alpha属性来创建更加显著的轨迹(0.5是透明度)
                ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
                ctx.fillRect(0, 0, cw, ch);
                // change the composite operation back to our main mode  改变复合操作回到我们的主要模式
                // lighter creates bright highlight points as the fireworks and particles overlap each other
                ctx.globalCompositeOperation = 'lighter'; // 显示源图像 + 目标图像。
    
                // loop over each firework, draw it, update it
                // 循环绘制烟花
                var i = fireworks.length;
                while (i--) {
                    fireworks[i].draw();
                    fireworks[i].update(i);
                }
    
                // 循环绘制粒子
                var i = particles.length;
                while (i--) {
                    particles[i].draw();
                    particles[i].update(i);
                }
    
                // launch fireworks automatically to random coordinates, when the mouse isn't down
                // 当鼠标不点击,自动随机坐标发射烟火
                if (timerTick >= timerTotal) {
                    if (!mousedown) {
                        var sw = random(0, cw);
                        // start the firework at the bottom middle of the screen, then set the random target coordinates, the random y coordinates will be set within the range of 
    
    the top half of the screen
                        // 启动烟花在屏幕中间的底部, 然后设置随机目标坐标, 随机y坐标将范围内的屏幕的上半部分
                        fireworks.push(new Firework(sw, ch, sw, random(0, ch / 2)));
                        timerTick = 0;
                    }
                } else {
                    timerTick++;
                }
    
                // limit the rate at which fireworks get launched when mouse is down
                // 限制鼠标点击时烟花发射的速度
                if (limiterTick >= limiterTotal) {
                    if (mousedown) {
                        // start the firework at the bottom middle of the screen, then set the current mouse coordinates as the target
                        // 启动烟花在屏幕中间的底部,然后将鼠标当前坐标设置为目标
                        fireworks.push(new Firework(mx, ch, mx, my));
                        limiterTick = 0;
                    }
                } else {
                    limiterTick++;
                }
            }
    
            // mouse event bindings
            // update the mouse coordinates on mousemove
            // 更新鼠标当前坐标
            canvas.addEventListener('mousemove', function (e) {
                mx = e.pageX - canvas.offsetLeft;
                my = e.pageY - canvas.offsetTop;
            });
    
            // toggle mousedown state and prevent canvas from being selected
            // 切换mousedown状态,防止canvas被选中
            canvas.addEventListener('mousedown', function (e) {
                e.preventDefault();
                mousedown = true;
            });
    
            canvas.addEventListener('mouseup', function (e) {
                e.preventDefault();
                mousedown = false;
            });
    
            // 登录启动
            window.onload = loop;
        </script>
    </body>
    </html>
  • 相关阅读:
    topcoder srm 681 div1
    topcoder srm 683 div1
    topcoder srm 684 div1
    topcoder srm 715 div1
    topcoder srm 685 div1
    topcoder srm 687 div1
    topcoder srm 688 div1
    topcoder srm 689 div1
    topcoder srm 686 div1
    topcoder srm 690 div1 -3
  • 原文地址:https://www.cnblogs.com/ariter/p/5983370.html
Copyright © 2011-2022 走看看