javascriptcanvasorbital-mechanics

Create a "tail" for an object that is orbiting


Edit

Here is a JSFiddle with the code for the "tail" function commenting out.Solar System JSFiddle

I have this object I am working on that has an object orbiting a center mass. That works perfectly. small red planet orbiting sun

I am now trying to add a trailing line or "tail" that follows behind the planet. My tail object looks like this:

function Tail(maxLength){
  this.points = [];
  this.maxLength = maxLength;
  this.addPoint = function(point){
    for(var i = Math.min(maxLength, this.points.length); i < maxLength; i++){
        this.points[i] = this.points[i - 1];
    }

    this.points[0] = point;
 }
 this.draw = function(ctx){
    for(var i = 1; Math.min(maxLength, this.points.length); i++){
        if(i < maxLength - 20){
            ctx.globalAlpha = 1;
        } else {
            ctx.globalAlpha = (this.maxLength - i) / 20;
        }

        ctx.beginPath();
        ctx.moveTo(this.points[i - 1].x, this.points[i - 1].y);
        ctx.lineTo(this.points[i].x, this.points[i].y);
        ctx.stroke();
    }

    ctx.globalAlpha = 1;
  }
}

The addPoint function takes an object that looks like '{x: currentX, y: currentY} currentX and currentY are the x and y point of the object when ever it gets called.

I am lost on how I need to add the point to the points array and then draw based on those coordinates.


Solution

  • I modified your version to working condition

    var canvas, width, height, ctx;
    var bodies = [];
    
    function init(){
        canvas = document.getElementById("space-time");
        width = window.innerWidth;
        height = window.innerHeight;
        canvas.width = width;
        canvas.height = height;
        ctx = canvas.getContext('2d');
    
        createBodies();
    
        setInterval(function(){
            updateSystem();
            updateBodies(0.01);
            ctx.clearRect(0, 0, width, height);
            drawBodies();
        }, 10);
    }
    
    function createBodies(){
        bodies.push(new Body((this.width / 2) - 250, (this.height / 2) - 300, 200, 0, 1, 10, "#14c71d", true));
        bodies.push(new Body((this.width / 2) + 100, (this.height / 2) + 100, 350, 0, 1, 5, "#de2d16", true));
        bodies.push(new Body(this.width / 2, this.height / 2, 0, 0, 1000000, 30, "#FF8501", false)); //sun
    }
    
    function drawBodies(){
        for(var i = 0; i < bodies.length; i++){
            bodies[i].draw(ctx);
        }
    }
    
    function updateBodies(dt){
        for(var i = 0; i < bodies.length; i++){
            bodies[i].update(dt);
        }
    }
    
    function updateSystem(){
        var G = 10;
        for(var i = 0; i < bodies.length; i++){
            for(var j = 0; j < bodies.length; j++){
                if(i === j) continue;
                var b1 = bodies[i];
                var b2 = bodies[j];
    
                var dist = Math.sqrt((b1.x - b2.x) * (b1.x - b2.x) + (b1.y - b2.y) * (b1.y - b2.y));
                var force = G * (b1.m * b2.m) / dist / dist;
                var nx = (b2.x - b1.x) / dist;
                var ny = (b2.y - b1.y) / dist;
    
                b1.ax += nx * force / b1.m;
                b1.ay += ny * force / b1.m;
    
                b2.ax -= nx * force / b2.m;
                b2.ay -= ny * force / b2.m;
            }
        }
    }
    
    function Body(x, y, v, angle, mass, radius, color, hasTail){
        this.x = x;
        this.y = y;
        this.vx = v * Math.cos(angle);
        this.vy = v * Math.sin(angle);
        this.m = mass;
        this.radius = radius;
        this.color = color;
        this.ax = 0;
        this.ay = 0;
    
        if (hasTail) {
            this.tail = new Tail(50);
        }
        
        this.update = function(dt){
            this.vx += this.ax * dt;
            this.vy += this.ay * dt;
            this.x += this.vx * dt;
            this.y += this.vy * dt;
            this.ax = 0;
            this.ay = 0;
    
            if(this.tail){
                this.tail.addPoint({x: this.x, y: this.y});
            }
        }
    
        this.draw = function(ctx){
            ctx.strokeStyle = this.color;
            ctx.fillStyle = this.color;
            ctx.shadowColor = this.color;
            ctx.shadowBlur = 5;
            if(this.tail){
                this.tail.draw(ctx);
            }
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.radius, 0, 6.28);
            ctx.fill();
        }
    }
    
    function Tail(maxLength){
        this.points = [];
        this.maxLength = maxLength;
        this.addPoint = point => {
            this.points = [point].concat(this.points).slice(0, this.maxLength);
        }
        this.draw = function(ctx){
            for(var i = 1; i < this.points.length; i++){
                ctx.beginPath();
                if(i < maxLength - 20){
                    ctx.globalAlpha = 1;
                } else {
                    ctx.globalAlpha = (this.maxLength - i) / 20;
                }
                ctx.moveTo(this.points[i - 1].x, this.points[i - 1].y);
                ctx.lineTo(this.points[i].x, this.points[i].y);
                ctx.stroke();
            }
            ctx.globalAlpha = 1;
        }
    }
    #space-time {
        background-color: #1a1a1c;
    }
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Solar System AJ</title>
    </head>
    <body onload="init();">
        <canvas id="space-time"></canvas>
    </body>
    </html>