javascript - 使用动态坐标在 Canvas 上定位

标签 javascript html animation canvas intervals

我正在使用 HTML5 Canvas 制作交互式太阳系 Canvas 。我希望能够在页面加载时将行星定位在 Canvas 上的特定坐标处。现在我把它们都排在一条水平线上,所以我知道它们各自的距离有多远。正如您在小图中看到的那样。

enter image description here

但是这是我的问题,因为 x 和 y 坐标根据使它们旋转的函数不断变化,我不知道如何在 Canvas 上准确定位这些行星,以便它们彼此分散,并且不像它们那样位于图像上,同时仍然将它们定位,以便它们在旋转时不会彼此直接接触。我认为这里涉及到一些数学知识。

另外:我意识到不同的动画间隔可能是解决此问题的方法,但我遇到了麻烦。当我为每个行星创建新的动画功能时,行星绘图并不像一个动画所带来的那么流畅。我意识到这本身就是一个独立的问题!

以下是大部分相关代码:

function initCanvas(){
var ctx = document.getElementById('my_canvas').getContext('2d');
var dynamicSunW = 25;
var dynamicSunH = 0;
var dynamicSunX = (ctx.canvas.width * .5) - (Math.PI* 1 * .5);  //dynamicSun is always at dead center of canvas
var dynamicSunY = (ctx.canvas.height * .5) - (dynamicSunH * .5);
var angleOfSun = 0;


var posMercuryX = (ctx.canvas.width * .5) - (Math.PI* 1 * .5) - 50;  
var posMercuryY = (ctx.canvas.height * .5) - (dynamicSunH * .5) + 20;
var gravityMercury = {x: posMercuryX, y: posMercuryY };
var posVenusX = (ctx.canvas.width * .5) - (Math.PI* 1 * .5) - 50;
var posVenusY = (ctx.canvas.height * .5) - (dynamicSunH * .5) + 46;
var gravityVenus = {x: posVenusX, y: posVenusY };
var posEarthX = (ctx.canvas.width * .5) - (Math.PI* 1 * .5) - 50;
var posEarthY = (ctx.canvas.height * .5) - (dynamicSunH * .5) + 80;
var gravityEarth = {x: posEarthX, y: posEarthY};
var posMarsX = (ctx.canvas.width * .5) - (Math.PI* 1 * .5) - 50;
var posMarsY = (ctx.canvas.height * .5) - (dynamicSunH * .5) + 116;
var gravityMars = {x: posMarsX, y: posMarsY };
var posJupiterX = (ctx.canvas.width * .5) - (Math.PI* 1 * .5) - 50;
var posJupiterY = (ctx.canvas.height * .5) - (dynamicSunH * .5) + 157;
var gravityJupiter = {x: posJupiterX, y: posJupiterY };
var posSaturnX = (ctx.canvas.width * .5) - (Math.PI* 1 * .5) - 50;
var posSaturnY = (ctx.canvas.height * .5) - (dynamicSunH * .5) + 208;
var gravitySaturn = {x: posSaturnX, y: posSaturnY };
var posUranusX = (ctx.canvas.width * .5) - (Math.PI* 1 * .5) - 50;
var posUranusY = (ctx.canvas.height * .5) - (dynamicSunH * .5) + 250;
var gravityUranus = {x: posUranusX, y: posUranusY };
var posNeptuneX = (ctx.canvas.width * .5) - (Math.PI* 1 * .5) - 50;
var posNeptuneY = (ctx.canvas.height * .5) - (dynamicSunH * .5) + 283.9;
var gravityNeptune = {x: posNeptuneX, y: posNeptuneY };




    function rotate_point(pointX, pointY, originX, originY, ang) {
            ang =  Math.PI / 180.0;
            return {
                x: Math.cos(ang) * (pointX-originX) - Math.sin(ang) * (pointY-originY) + originX,
                y: Math.sin(ang) * (pointX-originX) + Math.cos(ang) * (pointY-originY) + originY
            };
        }

        var Solarsystem = {
            Neptune: {
                render: function(){
                    ctx.beginPath();
                    gravityNeptune = rotate_point(gravityNeptune.x, gravityNeptune.y, dynamicSunX, dynamicSunY, angleOfSun)
                    ctx.arc(gravityNeptune.x,gravityNeptune.y ,10, 0, 2*Math.PI, true);
                    ctx.fillStyle = "darkblue"; 
                    ctx.closePath();
                    ctx.fill();

                }
            }
            , Uranus: {
                render: function(){
                    ctx.beginPath();
                    gravityUranus = rotate_point(gravityUranus.x, gravityUranus.y, dynamicSunX, dynamicSunY, angleOfSun)
                    ctx.arc(gravityUranus.x,gravityUranus.y ,6, 0, 2*Math.PI, true);
                    ctx.fillStyle = "rgb(64,224,208)"; 
                    ctx.closePath();
                    ctx.fill();
                }
            }
            , Saturn: {
                render: function(){
                    ctx.beginPath();
                    gravitySaturn = rotate_point(gravitySaturn.x, gravitySaturn.y, dynamicSunX, dynamicSunY, angleOfSun)
                    ctx.arc(gravitySaturn.x,gravitySaturn.y ,15, 0, 2*Math.PI, true);
                    ctx.fillStyle = "rgb(186,85,211)"; 
                    ctx.closePath();
                    ctx.fill();

                }
            }
            , Jupiter: {
                render: function(){
                    ctx.beginPath();
                    gravityJupiter = rotate_point(gravityJupiter.x, gravityJupiter.y, dynamicSunX, dynamicSunY, angleOfSun)
                    ctx.arc(gravityJupiter.x,gravityJupiter.y ,18, 0, 2*Math.PI, true);
                    ctx.fillStyle = "rgb(255,255,153)"; 
                    ctx.closePath();
                    ctx.fill();


                    }
            }
            , Mars: {
                render: function(){
                    ctx.beginPath();
                    gravityMars = rotate_point(gravityMars.x, gravityMars.y, dynamicSunX, dynamicSunY, angleOfSun)
                    ctx.arc(gravityMars.x,gravityMars.y ,7, 0, 2*Math.PI, true);
                    ctx.fillStyle = "rgb(255,99,71)"; 
                    ctx.closePath();
                    ctx.fill();

                }
            }
            , Earth: {
                render: function(){
                    ctx.beginPath();
                    gravityEarth = rotate_point(gravityEarth.x, gravityEarth.y, dynamicSunX, dynamicSunY, angleOfSun)
                    ctx.arc(gravityEarth.x,gravityEarth.y ,8, 0, 2*Math.PI);
                    ctx.fillStyle = "rgba(30,144,255,1)"; 
                    ctx.closePath();
                    ctx.fill();

                }
            }
            , Venus: {
                render: function(){
                    ctx.beginPath();
                    gravityVenus = rotate_point(gravityVenus.x, gravityVenus.y, dynamicSunX, dynamicSunY, angleOfSun)
                    ctx.arc(gravityVenus.x,gravityVenus.y ,7, 0, 2*Math.PI);
                    ctx.fillStyle = "rgba(255,165,0,1)"; 
                    ctx.closePath();
                    ctx.fill();
                }
            }
            , Mercury: {
                render: function(){
                ctx.beginPath();
                gravityMercury = rotate_point(gravityMercury.x, gravityMercury.y, dynamicSunX, dynamicSunY, angleOfSun)
                ctx.arc(gravityMercury.x,gravityMercury.y ,5, 0, 2*Math.PI);
                ctx.fillStyle = "rgba(119,136,153,1)";  
                ctx.closePath();
                ctx.fill();
                ctx.stroke();
                }
            }
            , Sun: {
            render: function(){
            ctx.fillStyle = "rgba(255,255,51,1)";  
            ctx.save(); //store ctx so it can  be later reused 
            ctx.shadowColor = 'yellow';
            ctx.shadowBlur = 70;
            ctx.shadowOffsetX = 0;
            ctx.shadowOffsetY = 0;  
            ctx.beginPath();
            ctx.arc(dynamicSunX, dynamicSunY, dynamicSunW, dynamicSunH, Math.PI*2, true);
            ctx.closePath();
            ctx.fill();
            ctx.restore(); //ctx at time of save
                }
            }
        }




    var bg = new Image();
    bg.src = "spacedef.png";
            function Background(){
            this.x = 0, this.y = 0, this.w = bg.width, this.h = bg.height;
            this.render = function(){
                ctx.drawImage(bg, this.x--, 0);
                if(this.x <= -499){
                    this.x = 0;
                }
            }
        } 

        var background = new Background(); 

        function animate(){
            background.render();
            Solarsystem.Neptune.render();
            Solarsystem.Uranus.render();
            Solarsystem.Saturn.render();
            Solarsystem.Jupiter.render();
            Solarsystem.Mars.render();
            Solarsystem.Earth.render();
            Solarsystem.Venus.render();
            Solarsystem.Mercury.render();
            Solarsystem.Sun.render(); 
        }
         var animateInterval = setInterval(animate, 1000/60);  

    }

最佳答案

也许可以让所有行星绕太阳旋转,而不是使用彼此相对的旋转点。每个行星都有自己距太阳的半径,因此您的数学可以简化为以下内容(对于圆形轨道):

var neptune.x=sun.x+neptune.radius*Math.cos(radianAngle);
var neptune.y=sun.y+neptune.radius*Math.sin(radianAngle);

当然,行星轨道实际上是椭圆形而不是圆形。您可以像这样计算椭圆上的点:

// Calc points on Ellipse
function getPointsOnEllipse(cx,cy,a,b){
    var startAngle=-PI/2;
    var lastX=cx-(a*Math.cos(startAngle));
    var lastY=cy+(b*Math.sin(startAngle));
    var points=[];
    // change 1000 to your desired count of waypoints along the ellipse
    for(var i=0;i<1000;i++){
        var angle=startAngle+PI2/1000*i;
        var x=cx-(a*Math.cos(angle));
        var y=cy+(b*Math.sin(angle));
        var dx=x-lastX;
        var dy=y-lastY;
        var length=parseInt(Math.sqrt(dx*dx+dy*dy));
        var eAngle=(Math.atan2(dy,dx)+PI2)%PI2;
        if(length>0){
            points.push({x:x,y:y,angle:eAngle});
            lastX=x;
            lastY=y;
        }
    }
    return(points);
}

关于javascript - 使用动态坐标在 Canvas 上定位,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36431960/

相关文章:

javascript - 我在 <a> 标签中的 onclick 和 href 有问题

javascript - 覆盖无法正常工作的外部 Java 脚本文件的 css 属性

python - 获取 http 响应的链接在 django 中只工作一次

javascript - 使用 JavaScript 在 span 中添加值

swift - 如何为 NSTextField 的 textColor 设置动画?

javascript - Google map API - 自定义原型(prototype)标记图像从今天起不再显示

javascript - 原型(prototype)继承。 obj->C->B->A,但 obj.constructor 是 A。为什么?

javascript - 为什么我无法为 div 设置值?

animation - OpenGL 中骨骼动画背后的逻辑

javascript - SVG 围绕圆圈设置虚线动画