プログラミングとイラストレーション » 惑星間の引力と軌道|HTML5
プログラミングとイラストレーション > HTML5 > 惑星間の引力と軌道|HTML5

惑星間の引力と軌道|HTML5

惑星間の引力と軌道|HTML5

惑星間の引力と軌道|HTML5(HTML5, JavaScript, CSS3) : デモ

惑星間の引力と軌道|HTML5(HTML5, JavaScript, CSS3) : ZIPファイル(3kb)

1.HTML

<!DOCTYPE html>
<html lang="jp">
    <head>
        <meta charset="UTF-8" />
        <title>惑星間の軌道</title>
        <link href="css/base.css" rel="stylesheet" type="text/css">
        <script src="js/base.js"></script>
    </head>
    <body>
        <div id="contents">
            <canvas id="canvas" width="275" height="275"></canvas>
        </div>
    </body>
</html>

2.CSS

@charset "utf-8";
  
body
{
    margin: 0;
    padding: 0;
    background-color: #fff;
}
  
#contents
{
    position: absolute;
    top: 0;
    left: 0;
    width: 275px;
    height: 275px;
    border: 1px solid #000;
    overflow:hidden;
}
  
#canvas
{
    position: absolute;
    top: 0;
    left: 0;
    width: 275px;
    height: 275px;
}

3.JavaScript

base.js

window.addEventListener("load", init, false);
  
function init()
{
    var offsetX = 0,
    offsetY = 0,
    ctx,
    particles = [],
    numParticles = 2,
    theCanvas,
    theContents;
     
    theContents = document.getElementById("contents");
    offsetX = (theContents.currentStyle || document.defaultView.getComputedStyle(theContents,'')).width;
    offsetX = Number(offsetX.replace('px', ''));
  
    offsetY = (theContents.currentStyle || document.defaultView.getComputedStyle(theContents,'')).height;
    offsetY = Number(offsetY.replace('px', ''));
     
    ctx = document.getElementById('canvas').getContext("2d");
     
    var Sun = new Object();
    Sun.red = 256;
    Sun.green = 0;
    Sun.blue = 0;
    Sun.x = offsetX / 2;
    Sun.y = offsetY / 2;
    Sun.vx = 0;
    Sun.vy = 0;
    Sun.radius = 50;
    Sun.mass = 1000;
    particles[0] = Sun;
     
    var Planet = new Object();
    Planet.red = 0;
    Planet.green = 0;
    Planet.blue = 256;
    Planet.x = offsetX / 2 + 100;
    Planet.y = offsetY / 2;
    Planet.vx = 0;
    Planet.vy = 3.1;
    Planet.radius = 5;
    Planet.mass = 1;
    particles[1] = Planet;
     
    setBallAnimation();
     
    function setBallAnimation()
    {
        animation();
        requestAnimationFrame(setBallAnimation);
    }
     
    function animation()
    {
        ctx.clearRect(0, 0, 300, 300);
         
        for(var i = 0; i < numParticles; i++)
        {
            ctx.strokeStyle ="rgb(" + particles[i].red + "," + particles[i].green + "," + particles[i].blue + ")";
            ctx.lineWidth = 1;
            ctx.beginPath();
            ctx.arc(particles[i].x, particles[i].y, particles[i].radius, 0, Math.PI * 2, true);
            ctx.fillStyle = "rgb(" + particles[i].red + "," + particles[i].green + "," + particles[i].blue + ")";
            ctx.fill();
            ctx.stroke();
        }
         
        for(var i = 0; i < numParticles; i++)
        {
            var particle = particles[i];
            particle.x += particle.vx;
            particle.y += particle.vy;
        }
         
        for(var i = 0; i < numParticles - 1; i++)
        {
            var partA = particles[i];
            for(var j = i + 1; j < numParticles; j++)
            {
                var partB = particles[j];
                checkCollision(partA, partB);
                gravitate(partA, partB);
            }
        }
    }
     
    function gravitate(partA, partB)
    {
        var dx = partB.x - partA.x;
        var dy = partB.y - partA.y;
        var distSQ = dx * dx + dy * dy;
        var dist = Math.sqrt(distSQ);
        var force = partA.mass * partB.mass / distSQ;
        var ax = force * dx / dist;
        var ay = force * dy / dist;
        partA.vx += ax / partA.mass;
        partA.vy += ay / partA.mass;
        partB.vx -= ax / partB.mass;
        partB.vy -= ay / partB.mass;
    }
     
    function checkCollision(ball0, ball1)
    {
        var dx = ball1.x - ball0.x;
        var dy = ball1.y - ball0.y;
        var dist = Math.sqrt(dx*dx + dy*dy);
        if(dist < ball0.radius + ball1.radius)
        {
            // 角度とサイン、コサインの計算
            var angle = Math.atan2(dy, dx);
            var sin = Math.sin(angle);
            var cos = Math.cos(angle);
             
            // ball0の位置の回転
            var pos0 = {x:0, y:0};
             
            // ball1の位置の回転
            var pos1 = rotate(dx, dy, sin, cos, true);
             
            // ball0の速度の回転
            var vel0 = rotate(ball0.vx, ball0.vy, sin, cos, true);
             
            // ball1の速度の回転
            var vel1 = rotate(ball1.vx, ball1.vy, sin, cos, true);
             
            // 衝突反応
            var vxTotal = vel0.x - vel1.x;
            vel0.x = ((ball0.mass - ball1.mass) * vel0.x + 2 * ball1.mass * vel1.x) / (ball0.mass + ball1.mass);
            vel1.x = vxTotal + vel0.x;
 
            // 位置の更新
            var absV = Math.abs(vel0.x) + Math.abs(vel1.x);
            var overlap = (ball0.radius + ball1.radius) - Math.abs(pos0.x - pos1.x);
            pos0.x += vel0.x / absV * overlap;
            pos1.x += vel1.x / absV * overlap;
             
            // 位置の回転
            var pos0F = rotate(pos0.x, pos0.y, sin, cos, false);
                                       
            var pos1F = rotate(pos1.x, pos1.y, sin, cos, false);
 
            // 実際の画面位置への調整
            ball1.x = ball0.x + pos1F.x;
            ball1.y = ball0.y + pos1F.y;
            ball0.x = ball0.x + pos0F.x;
            ball0.y = ball0.y + pos0F.y;
             
            // 速度の回転
            var vel0F = rotate(vel0.x, vel0.y, sin, cos, false);
            var vel1F = rotate(vel1.x, vel1.y, sin, cos, false);
            ball0.vx = vel0F.x;
            ball0.vy = vel0F.y;
            ball1.vx = vel1F.x;
            ball1.vy = vel1F.y;
        }
    }
     
    function rotate(x, y, sin, cos, reverse)
    {
        var result = {x:0, y:0};
        if(reverse)
        {
            result.x = x * cos + y * sin;
            result.y = y * cos - x * sin;
        }
        else
        {
            result.x = x * cos - y * sin;
            result.y = y * cos + x * sin;
        }
        return result;
    }
}
 
// 各ブラウザ対応
window.requestAnimationFrame = (function()
{
    return window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    function(callback)
    {
        window.setTimeout(callback, 1000/60);
    };
}());

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

コメントフィード

トラックバック URL : http://www.htmlcode.jp/%e6%83%91%e6%98%9f%e9%96%93%e3%81%ae%e5%bc%95%e5%8a%9b%e3%81%a8%e8%bb%8c%e9%81%93%ef%bd%9chtml5/trackback/