JS引力小球代码

小球两两存在引力;两个球碰撞后变成一个,其质量等于两个球之和;如果小球质量太大会爆炸产生碎片。下面代码粘贴进文件后缀改为html直接运行。

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
      
      
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
        }
    </style>
</head>

<body>
    <canvas id="canvas" width="500" height="500"></canvas>
</body>
<script>
    const LOST = 0.6;
    var canvas = document.getElementById('canvas');
    var context = canvas.getContext('2d');
    var planets = [];
    const MAX_MASS = 500;
    const PLANET_COUNT = 300;
    const FRAGMENT_COUNT = 29;
    const FRAGMENT_SPEED = 1;
    const MAX_SPEED = 8;
    const G = 0.25;
    var maxLineLength = 45;
    const DEFAULT_MASS = 20;
    const LOCK_TIME = 10;
    const COLOR = '#333';
    const LINE_COLOR = '#3334';
    const MOUSE_MASS = 100;
    var mousepoint = {
      
       x: 0, y: 0 };
    function init(count) {
      
      
        var w = canvas.clientWidth;
        var h = canvas.clientHeight;
        for (var i = 0; i < count; i++) {
      
      
            planets.push({
      
       x: Math.random() * w, y: Math.random() * h, mass: DEFAULT_MASS, vx: Math.random() * 2 - 1, vy: Math.random() * 2 - 1, lock: 0 });
        }
    }
    function fillRound(cx, cy, r, color) {
      
      
        context.beginPath();
        context.fillStyle = color;
        context.arc(cx, cy, Math.sqrt(r) / Math.PI, 0 * Math.PI, 2 * Math.PI, true);
        context.fill();
    }
    function drawLine(x1, y1, x2, y2, color) {
      
      
        context.beginPath();
        context.moveTo(x1, y1);
        context.strokeStyle = color;
        context.lineTo(x2, y2);
        context.stroke();
    }
    function collide() {
      
      
        for (var i = 0, count = planets.length; i < count; i++) {
      
      
            if (planets[i].lock <= 0) {
      
      
                for (var i1 = 0; i1 < count; i1++) {
      
      
                    if (i1 != i && planets[i1] && planets[i1].lock <= 0) {
      
      
                        var r = Math.sqrt(Math.pow((planets[i].x - planets[i1].x), 2) + Math.pow((planets[i].y - planets[i1].y), 2));
                        if (r <= Math.max(Math.sqrt(planets[i1].mass) / Math.PI + Math.sqrt(planets[i].mass) / Math.PI) && planets[i1].mass >= planets[i].mass) {
      
      
                            planets[i1].vy = (planets[i1].mass * planets[i1].vy + planets[i].mass * planets[i].vy) / (planets[i1].mass + planets[i].mass);
                            planets[i1].vx = (planets[i1].mass * planets[i1].vx + planets[i].mass * planets[i].vx) / (planets[i1].mass + planets[i].mass);
                            planets[i1].mass += planets[i].mass;
                            planets[i] = null;
                            break;
                        }
                    }
                }
            }
        }
    }
    function explode() {
      
      
        for (var i = 0, count = planets.length; i < count; i++) {
      
      
            if (planets[i] && planets[i].mass >= MAX_MASS) {
      
      
                for (var i1 = 0; i1 < FRAGMENT_COUNT; i1++) {
      
      
                    planets.push({
      
      
                        x: planets[i].x + Math.random(),
                        y: planets[i].y + Math.random(),
                        mass: planets[i].mass / FRAGMENT_COUNT,
                        vx: FRAGMENT_SPEED * (Math.random() * 2 - 1),
                        vy: FRAGMENT_SPEED * (Math.random() * 2 - 1),
                        lock: LOCK_TIME
                    });
                }
                planets[i] = null;
            }
        }
    }

    canvas.onmousemove = function (event) {
      
      
        var e = event || window.event;
        mousepoint = {
      
       'x': e.clientX, 'y': e.clientY };
    }

    function step() {
      
      
        var w = canvas.clientWidth;
        var h = canvas.clientHeight;
        collide();
        explode();
        for (var i = 0, count = planets.length; i < count; i++) {
      
      
            if (planets[i]) {
      
      
                if (planets[i].vx === NaN) {
      
      
                    planets[i].vx = 0
                }
                if (planets[i].vy === NaN) {
      
      
                    planets[i].vy = 0
                }
            }
        }
        planets = planets.filter(e => e && e.x !== NaN && e.y !== NaN && e.vx !== NaN && e.vy !== NaN && e.mass !== NaN);

        for (var i = 0, count = planets.length; i < count; i++) {
      
      
            if (planets[i].x > w) {
      
      
                planets[i].x -= (planets[i].x - w) * 2;
                planets[i].vx *= -(1 - LOST);
            } else if (planets[i].x < 0) {
      
      
                planets[i].x += planets[i].x * -2;
                planets[i].vx *= -(1 - LOST);
            }
            if (planets[i].y > h) {
      
      
                planets[i].y -= (planets[i].y - h) * 2;
                planets[i].vy *= -(1 - LOST);
            } else if (planets[i].y < 0) {
      
      
                planets[i].y += planets[i].y * -2;
                planets[i].vy *= -(1 - LOST);
            }
            fillRound(planets[i].x, planets[i].y, planets[i].mass, COLOR)
            for (var i1 = 0; i1 < count; i1++) {
      
      
                if (i1 != i) {
      
      
                    var r = Math.sqrt(Math.pow((planets[i].x - planets[i1].x), 2) + Math.pow((planets[i].y - planets[i1].y), 2));
                    var f = r != 0 ? G * G * planets[i1].mass / Math.pow(r, 2) : 0;
                    var dx = planets[i1].x - planets[i].x;
                    var dy = planets[i1].y - planets[i].y;
                    if (planets[i].mass > 0) {
      
      
                        planets[i].vy += f / r * dy;
                        planets[i].vx += f / r * dx;
                    }
                    if (i1 > i && r <= maxLineLength) {
      
      
                        drawLine(planets[i].x, planets[i].y, planets[i1].x, planets[i1].y, LINE_COLOR)
                    }
                }
            }
            //
            var r = Math.max(1, Math.sqrt(Math.pow((planets[i].x - mousepoint.x), 2) + Math.pow((planets[i].y - mousepoint.y), 2)));
            if (r > maxLineLength / 8) {
      
      
                var f = r != 0 ? G * G * MOUSE_MASS / Math.pow(r, 2) : 0;
                var dx = mousepoint.x - planets[i].x;
                var dy = mousepoint.y - planets[i].y;
                if (planets[i].mass > 0) {
      
      
                    planets[i].vy += f / r * dy;
                    planets[i].vx += f / r * dx;
                }
                if (r <= maxLineLength) {
      
      
                    drawLine(planets[i].x, planets[i].y, mousepoint.x, mousepoint.y, LINE_COLOR);
                }
            }
            //
            var speedNow = Math.sqrt(Math.pow(planets[i].vx, 2) + Math.pow(planets[i].vy, 2))
            if (speedNow > MAX_SPEED) {
      
      
                planets[i].vx = planets[i].vx * MAX_SPEED / speedNow;
                planets[i].vy = planets[i].vy * MAX_SPEED / speedNow;
            }
            planets[i].x += planets[i].vx;
            planets[i].y += planets[i].vy;
            planets[i].lock--;
        }
    }
    init(PLANET_COUNT);
    setInterval(function () {
      
      
        var w = document.body.clientWidth;
        var h = document.body.clientHeight;
        maxLineLength = Math.max(30, Math.min(w / 10, h / 10));
        canvas.setAttribute('width', w);
        canvas.setAttribute('height', h);
        canvas.style.width = w + 'px';
        canvas.style.height = h + 'px';
        step();
    }, 30)
</script>

</html>

おすすめ

転載: blog.csdn.net/dscn15848078969/article/details/119950455
おすすめ