如何在HTML5中计算行星绕太阳到地球的光轴

问题描述 投票:0回答:1

我正在从地球的角度创建一个内部太阳系模型,用于创建占星术出生图参考。我能够为地球 - 太阳轴和地球 - 月球轴绘制一条光轴线,但我无法为我的生命绘制其余内行星的三角函数。 这是一支工作笔。 https://codepen.io/pjdroopypants/pen/wvEKeOm

window.onload = function(){

    var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    cw = canvas.width,
    ch = canvas.height,
    time = 1;

function circle(radius,color,x,y){
    ctx.beginPath();
    ctx.fillStyle = color;
    ctx.arc(x,y,radius,0,2*Math.PI,true);
    ctx.fill();
    ctx.closePath();
}


function line(color,ax,ay,bx,by){

    ctx.beginPath();
    ctx.moveTo(ax*2,ay);
    ctx.lineTo(bx+0.5,by+0.5);
    ctx.strokeStyle = color;
    ctx.stroke();
    ctx.closePath();

}

var sunDegree = Math.floor(Math.random() * 359) + 1; //temporary, will use function from live planetary data
var merDegree = Math.floor(Math.random() * 359) + 1; //temporary, will use function from live planetary data 
var venDegree = Math.floor(Math.random() * 359) + 1; //temporary, will use function from live planetary data 
var marDegree = Math.floor(Math.random() * 359) + 1; //temporary, will use function from live planetary data 
var mooDegree = Math.floor(Math.random() * 359) + 1; //temporary, will use function from live planetary data 
var interval = 570.0930061551268;

function animate(){

    ctx.save();
    ctx.clearRect(0, 0, 1100, 1100);
    ctx.translate(cw/2,ch/2);

    //Earth 
    ctx.rotate(-(time / interval)+ Math.PI);
    circle(15,"blue",0,0);
    ctx.translate(480,0);
    line("blue",-240,0,0,0);
    ctx.translate(-480,0);
    ctx.rotate((time / interval)+ Math.PI);

        //Moon
        var moontime = (time / (interval / 13.36996336996337)+mooDegree);
        ctx.rotate(-moontime);
        ctx.translate(23,0);
        circle(3,"black",0,0);
        ctx.translate(457,0);
        line("#6a6a6a",-230,0,0,0);
        ctx.translate(-480,0);
        ctx.rotate(moontime);

    //Sun
    var suntime = time / interval;
    ctx.rotate(-suntime);
    ctx.translate(120,0);
    circle(15,"yellow",0,0);
    ctx.translate(360,0);
    line("yellow",-182,0,0,0);
    ctx.translate(-360,0);
    ctx.rotate(suntime);

    //Mercury
    var mertime = (time / (interval / 4.150568181818182))+merDegree;
    ctx.rotate(-(time / (interval / 4.150568181818182))+merDegree-suntime);
    ctx.translate(40,0);
    circle(15,"#898989",0,0);

    ctx.translate(-40,0);
    ctx.rotate((time / (interval / 4.150568181818182))+merDegree+suntime);

    //Venus
    ctx.rotate(-(time / (interval / 1.625500667556742))+venDegree-suntime);
    ctx.translate(80,0);
    circle(15,"#b9955b",0,0);
    ctx.translate(-80,0);
    ctx.rotate((time / (interval / 1.625500667556742))+venDegree);

    //Mars
    ctx.rotate(-(time / (interval / 0.5316593886462882))+marDegree);
    ctx.translate(160,0);
    circle(15,"#9f5e13",0,0);
    ctx.translate(-160,0);
    ctx.rotate((time / (interval / 0.5316593886462882))+marDegree);

    ctx.restore();
    time++;
    window.requestAnimationFrame(animate);

}

    window.requestAnimationFrame(animate);

}

我试图通过减去太阳的旋转角度来反向旋转每个动画迭代,但这只会使轴线水平而不是回到中心。

javascript html5-canvas
1个回答
0
投票

使用对象封装

你的代码一团糟

您需要封装各个部分,以便您可以单独使用它们。

下面的示例使用工厂模式定义行星,将行星创建为对象。

每个行星都获得轨道角度、速率和与它们围绕的行星的距离。例如水星、金星、地球、火星都绕太阳公转,而月球绕地球公转。

行星是按轨道顺序创建的。 IE 无法在创建它所环绕的行星之前创建行星。

在每个动画帧上,每个行星的位置都是按照其创建时的相同顺序相对于其运行的行星计算的。

在渲染行星之前,我们希望将视图集中在选定的行星(在本例中为地球)上。居中的行星位置用于创建一个全局矩阵,将所有行星移动到正确的位置。

然后在绘制每个行星时,我们将全局矩阵乘以行星矩阵

ctx.setTransform(...globalMat); ctx.transform(this.cos, this.sin, -this.sin, this.cos, this.x, this.y);
并绘制结果

requestAnimationFrame(mainLoop);
const ctx = canvas.getContext("2d");
const TAU = Math.PI * 2;
const centerOnPlanetName = "Earth";  // Planet name to center view on
const globalMatrix = [1,0,0,1,0,0];  // holds position of planet to track
const solSystem = {};                // holds planets by name
const planets = [];                  // holds planets in order of created
const planetCommon = {               // common properties of planets
     x: 0, y: 0, cos: 1, sin: 0,
     update(time) {
         const ang = this.startAng + this.orbitalSpeed * time;
         this.cos = Math.cos(ang);
         this.sin = Math.sin(ang);
         if (this.orbits) {          // Check if orbiting something
             this.x = this.orbits.x + this.cos * this.dist;
             this.y = this.orbits.y + this.sin * this.dist;
         } 
     },
     draw(ctx, globalMat) {
         ctx.setTransform(...globalMat);
         ctx.transform(this.cos, this.sin, -this.sin, this.cos, this.x, this.y);
         ctx.fillStyle = this.color;
         ctx.beginPath();
         ctx.arc(0, 0, this.radius, 0, TAU);
         ctx.fill();
         ctx.beginPath();
         ctx.lineTo(this.radius * 1.5, 0);
         ctx.lineTo(300, 0);
         ctx.stroke();
     }
};
const planet = (name, orbitsName, dist, orbitalSpeed, startAng, radius, color) => {
    planets.push(solSystem[name] = {
        orbits: solSystem[orbitsName], // Set planet new planet orbits
        dist,                          // dist from orbiting body
        orbitalSpeed,                  // in radians per time unit
        startAng,                      // starting angle in radians
        radius,
        color,
        ...planetCommon,
     });
};
planet("Sun", undefined,     0, 0.8, - Math.PI, 20, "yellow");
planet("Mercury", "Sun",    45,   2,         0,  6, "#888");
planet("Venus",   "Sun",    70, 1.2,         0, 15, "#CC8");
planet("Earth",   "Sun",   120, 0.8,         0, 16, "#39B");
planet("Mars",    "Sun",   175, 0.4,         0, 10, "#B43");
planet("Moon",    "Earth",  30,   5,         0,  3, "#444");

function centerOn(cx, cy, planet) {
    globalMatrix[4] = cx - planet.x;
    globalMatrix[5] = cy - planet.y;
}

function mainLoop(time) {
    time /= 1000;
    ctx.setTransform(1, 0, 0, 1, 0, 0);
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    planets.forEach(planet => planet.update(time));
    centerOn(ctx.canvas.width * 0.5, ctx.canvas.height * 0.5, solSystem[centerOnPlanetName]);
    planets.forEach(planet => planet.draw(ctx, globalMatrix));
    requestAnimationFrame(mainLoop);
}
canvas {
 border: 1px solid black;
}
<canvas id="canvas" width="600" height="600"></canvas>

© www.soinside.com 2019 - 2024. All rights reserved.