js实现canvas模拟点击生成多个黑洞重力影响光子粒子运行轨迹动画效果代码

代码语言:html

所属分类:粒子

代码描述:js实现canvas模拟点击生成多个黑洞重力影响光子粒子运行轨迹动画效果代码

代码标签: canvas 物理 重力 黑洞 光子 粒子

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html lang="en">

<head>

    <meta charset="UTF-8">





    <style>
        body {
            font-family: Helvetica sans-serif;
            padding: 0;
            margin: 0;
            background-color: #222;
            overflow: hidden;
            -webkit-user-select: none;
               -moz-user-select: none;
                 -o-user-select: none;
                -ms-user-select: none;
                    user-select: none;
        }
        
        canvas {
            position: absolute;
            top: 0;
            left: 0;
        }
        
        .info {
            position: absolute;
            top: 0;
            left: 0;
            padding: 5px 15px;
            color: #eee;
            font-size: 13px;
            background-color: rgba(0, 0, 0, .5);
        }
    </style>



</head>

<body>
    <canvas id="c"></canvas>
    <div class="info">Click to add gravity point.</div>
    <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/dat.gui-min.js"></script>
    <script>
        /**
     * requestAnimationFrame
     */
    window.requestAnimationFrame = (function(){
        return  window.requestAnimationFrame       ||
                window.webkitRequestAnimationFrame ||
                window.mozRequestAnimationFrame    ||
                window.oRequestAnimationFrame      ||
                window.msRequestAnimationFrame     ||
                function (callback) {
                    window.setTimeout(callback, 1000 / 60);
                };
    })();
    
    
    /**
     * Vector
     */
    function Vector(x, y) {
        this.x = x || 0;
        this.y = y || 0;
    }
    
    Vector.add = function(a, b) {
        return new Vector(a.x + b.x, a.y + b.y);
    };
    
    Vector.sub = function(a, b) {
        return new Vector(a.x - b.x, a.y - b.y);
    };
    
    Vector.scale = function(v, s) {
        return v.clone().scale(s);
    };
    
    Vector.random = function() {
        return new Vector(
            Math.random() * 2 - 1,
            Math.random() * 2 - 1
        );
    };
    
    Vector.prototype = {
        set: function(x, y) {
            if (typeof x === 'object') {
                y = x.y;
                x = x.x;
            }
            this.x = x || 0;
            this.y = y || 0;
            return this;
        },
    
        add: function(v) {
            this.x += v.x;
            this.y += v.y;
            return this;
        },
    
        sub: function(v) {
            this.x -= v.x;
            this.y -= v.y;
            return this;
        },
    
        scale: function(s) {
            this.x *= s;
            this.y *= s;
            return this;
        },
    
        length: function() {
            return Math.sqrt(this.x * this.x + this.y * this.y);
        },
    
        lengthSq: function() {
            return this.x * this.x + this.y * this.y;
        },
    
        normalize: function() {
            var m = Math.sqrt(this.x * this.x + this.y * this.y);
            if (m) {
                this.x /= m;
                this.y /= m;
            }
            return this;
        },
    
        angle: function() {
            return Math.atan2(this.y, this.x);
        },
    
        angleTo: function(v) {
            var dx = v.x - this.x,
                dy = v.y - this.y;
            return Math.atan2(dy, dx);
        },
    
        distanceTo: function(v) {
            var dx = v.x - this.x,
                dy = v.y - this.y;
            return Math.sqrt(dx * dx + dy * dy);
        },
    
        distanceToSq: function(v) {
            var dx = v.x - this.x,
                dy = v.y - this.y;
            return dx * dx + dy * dy;
        },
    
        lerp: function(v, t) {
            this.x += (v.x - this.x) * t;
            this.y += (v.y - this.y) * t;
            return this;
        },
    
        clone: function() {
            return new Vector(this.x, this.y);
        },
    
        toString: function() {
            return '(x:' + this.x + ', y:' + this.y + ')';
        }
    };
    
    
    /**
     * GravityPoint
     */
    function GravityPoint(x, y, radius, targets) {
        Vector.call(this, x, y);
        this.radius = radius;
        this.currentRadius = radius * 0.5;
    
        this._targets = {
            particles: targets.particles || [],
            gravities: targets.gravities || []
        };
        this._speed = new Vector();
    }
    
    GravityPoint.RADIUS_LIMIT = 65;
    GravityPoint.interferenceToPoint = true;
    
    GravityPoint.prototype = (function(o) {
        var s = new Vector(0, 0), p;
        for (p in o) s[p] = o[p];
        return s;
    })({
        gravity:       0.05,
        isMouseOver:   false,
        dragging:      false,
        destroyed:     false,
        _easeRadius:   0,
        _dragDistance: null,
        _collapsing:   false,
    
        hitTest: function(p) {
            return this.distanceTo(p) < this.radius;
        },
    
        startDrag: function(dragStartPoint) {
            this._dragDistance = Vector.sub(dragStartPoint, this);
            this.dragging = true;
        },
    
        drag: function(dragToPoint) {
            this.x = dragToPoint.x - this._dragDistance.x;
            this.y = dragToPoint.y - this._dragDistance.y;
        },
    
        endDrag: function() {
            this._dragDistance = null;
            this.dragging = false;
        },
    
        addSpeed: function(d) {
            this._speed = this._speed.add(d);
        },
    
        collapse: function(e) {
            this.currentRadius *= 1.75;
            this._collapsing = true;
        },
    
        render: function(ctx) {
            if (this.destroyed) return;
    
            var particles = this._targets.particles,
                i, len;
    
            for (i = 0, len = particles.length; i < len; i++) {
                particles[i].addSpeed(Vector.sub(this, particles[i]).normalize().scale(this.gravity));
            }
    
            this._easeRadius = (this._easeRadius + (this.radius - this.currentRadius) * 0.07) * 0.95;
            this.currentRadius += this._easeRadius;
            if (this.currentRadius < 0) this.currentRadius = 0;
    
            if (this._collapsing) {
                this.radius *= 0.75;
                if (this.currentRadius < 1) this.destroyed = true;
                this._draw(ctx);
                return;
            }
    
            var gravities = this._targets.gravities,
                g, absorp,
                area = this.radius * this.radius * Math.PI, garea;
    
            for (i = 0, len = gravities.length; i < len; i++) {
                g = gravities[i];
    
                if (g === this || g.destroyed) continue;
    
                if (
                    (this.currentRadius >= g.radius || this.dragging) &&
                    this.distanceTo(g) < (this.currentRadius + g.radius) * 0.85
                ) {
                    g.destroyed = true;
                    this.gravity += g.gravity;
    
                    absorp = Vector.sub(g, this).scale(g.radius / this.radius * 0.5);
                    this.addSpeed(absorp);
    
                    garea = g.radius * g.radius * Math.PI;
                    this.currentRadius = Math.sqrt((area + garea * 3) / Math.PI);
                    this.radius = Math.sqrt((area + garea) / Math.PI);
                }
    
                g.addSpeed(Vector.sub(this, g).normalize().scale(this.gravity));
            }
    
            if (GravityPoint.interferenceToPoint && !this.dragging)
                this.add(this._speed);
    
            this._speed = new Vector();
    
            if (this.currentRadius > GravityPoint.RADIUS_LIMIT) this.collapse();
    
            this._draw(ctx);
        },
    
        _draw: function(ctx) {
            var grd, r;
    
            ctx.save();
    
            grd = ctx.createRadialGradient(this.x, this.y, this.radius, this.x, this.y, this.radius * 5);
            grd.addColorStop(0, 'rgba(0, 0, 0, 0.1)');
            grd.addColorStop(1, 'rgba(0, 0, 0, 0)');
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.radius * 5, 0, Math.PI * 2, false);
            ctx.fillStyle = grd;
            ctx.fill();
    
            r = Math.random() * this.currentRadius * 0.7 + this.currentRadius * 0.3;
            grd = ctx.createRadialGradient(this.x, this.y, r, this.x, this.y, this.currentRadius);
            grd.addColorStop(0, 'rgba(.........完整代码请登录后点击上方下载按钮下载查看

网友评论0