N体

显示所有步骤

上一节是三个天体在万有引力作用下运行的现象,下面我们看任意多个天体时怎么处理,如何编程实现。

同样也只需要修改第三部分的代码,对天体的处理方式上做了点点修改,我们用列表存储天体, 这样可以根据需要自己添加任意个天体,变化行数也不多(全屏体验):

    var canvasDiv = document.getElementById(parentId);
    if (!canvasDiv || !canvasDiv.appendChild) return;

    var canvas = document.createElement('canvas');
    canvas.setAttribute('id', canvasId);
    canvas.setAttribute('style', "margin: 0px 0px 30px 0px;");
    canvasDiv.appendChild(canvas);

    var imgBg = null;
    var img = document.getElementById("spaceBg");
    img.onload = function(){ imgBg = img; }

    var context = canvas ? canvas.getContext('2d') : null;
    var objList = [];

    var scaleFactor = 10;
    var distUnit = canvas.height / 4;
    var sizeUnit = canvas.height / 400;
    var scaleX = canvas.width / distUnit / scaleFactor;
    var scaleY = canvas.height / distUnit / scaleFactor;
    var transX =  canvas.width / 2, transY =  canvas.height / 2;

    var posX = 0, posY = 0;
    var obj = makeObject('objA', 1.000 * Math.pow(10, 14), 10 * sizeUnit, posX, posY, {x:0.0,y:0}, 'red');
    objList.push(obj);

    obj = makeObject('objB', 100.0 * Math.pow(10, 10),  4 * sizeUnit, posX, posY-sizeUnit*220, {x:2.0,y:0}, 'blue');
    objList.push(obj);

    obj = makeObject('objC', 1.000 * Math.pow(10, 10),  2 * sizeUnit, posX, posY-sizeUnit*120, {x:5.0,y:0}, 'yellow')
    objList.push(obj);

    obj = makeObject('objD', 1.000 * Math.pow(10, 10),  2 * sizeUnit, posX, posY+sizeUnit*190, {x:3.0,y:0}, 'yellow')
    objList.push(obj);

    obj = makeObject('objE', 100.0 * Math.pow(10, 10),  4 * sizeUnit, posX-sizeUnit*250, posY, {x:0,y:4}, 'blue');
    objList.push(obj);

    var limitDraw = 1000/30;
    var lastDrawTime = Date.now() - limitDraw;

    var limitCalc = 10;
    var lastCalcTime = Date.now() - limitCalc;
    var calcTimesPerDraw = 3;

    function update(){
        var now = Date.now();
        var deltaDraw = now - lastDrawTime;
        if (context && deltaDraw >= limitDraw) {
            if (imgBg) context.drawImage(imgBg, 0, 0, imgBg.width, imgBg.height, 0, 0, canvas.width, canvas.height);

            for(var obj of objList){
                if ( isNaN(obj.x) || isNaN(obj.y) || isNaN(obj.v.x) || isNaN(obj.v.y) ){
                    console.error('xxx');
                    continue;
                }
                drawObject(context, obj, scaleX, scaleY, transX, transY);
            }
            lastDrawTime = now;
        }

        var deltaCalc = now - lastCalcTime;
        if (deltaCalc >= limitCalc) {
            lastCalcTime = now;
            for(var tm=0; tm < (calcTimesPerDraw || 10); tm++){
                for(var i = 0; i < objList.length; i++){
                    for(var j = i+1; j < objList.length; j++){
                        calcUpdate2Object(objList[i], objList[j], limitCalc/1000);
                    }
                }
            }
        }
        requestAnimationFrame(update);
    }

    requestAnimationFrame(update);

有了这套系统,我们可以给天体设置不同的坐标,质量,初始速度,然后观察它们运行起来的规律。甚至可以在网上搜索太阳系里星球的数据,来模拟一个小宇宙... 这个过程必有不少蹊跷现象等待去发现。