太陽と地球と月と宇宙船

Bloggerのデザインを換えました

このBloggerのデザインに関しては、 いじくり回しても切りがない上に、思うように変更できないので妥協して放置していたのですが、 さすがに自分でも見難いなという思いが山積してしまったため、手直ししました。

いかがなものでしょうか。

こっちが本題に見せかけるためのネタ

流石にしれっとデザイン変更だけするのも気が引けたもので、 アニメーションでもやろうと、Javascriptで行列を使ってみました。

「太陽の周りを回る地球の周りを回る月を追う宇宙船」

  • 赤 : 太陽
  • 青 : 地球
  • 黄 : 月
  • 黒 : 宇宙船

処理的には2次元 + 同次座標で3x3行列を使用して、2Dで処理しています。

宇宙船が他の天体に衝突しないようにするとかの処理を追加してみると面白いかもしれません。

(function(global) {
  'use strict';
  main();
})(new Function('return this;')())

function main() {
  var self = this;

  var width = 320;
  var height = 240;
  var font_size = 24;

  var center = [width / 2, height / 2];
  var theta = 0;
  var pos_spaceship = [0.0, 0.0, 1.0];

  canvas = document.createElement('canvas');
  {
    canvas.width = width;
    canvas.height = height;
    var script = document.getElementById('script_main');
    script.parentNode.insertBefore(canvas, script);
  }

  {  // event handler
    var es = [
      [canvas,  'click',        onClick],
      // [canvas,  'dblclick',     onDblclick],
      // [canvas,  'mouseover',    onMouseover],
      // [canvas,  'mouseout',     onMouseout],
      [canvas,  'mousedown',    onClick],
      // [canvas,  'mousemove',    onMousemove],
      // [canvas,  'mouseup',      onMouseup],
      // [canvas,  'touchcancel',  onTouch],
      // [canvas,  'touchstart',   onTouch],
      // [canvas,  'touchmove',    onTouch],
      // [canvas,  'touchend',     onTouch],
      // [canvas,  'wheel',        onWheel],

      // [window,  'keydown',      onKeydown],
      // [window,  'contextmenu',  onContextmenu]
    ];
    for (var i in es) {
      (function(j){
        j[0].addEventListener(j[1], function(e){
          j[2].apply(self, [e]);
        }, true);
      })(es[i]);
    };
  }

  function onClick(e) {
    e.preventDefault();
    e.stopPropagation();

    pos_spaceship = [0.0, 0.0, 1.0];

    return false;
  }

  function draw() {
    var ctx = canvas.getContext('2d');
    ctx.font = font_size + "px 'Times New Roman'";
    ctx.clearRect(0, 0, width, height);
    ctx.fillStyle = "rgb(192, 192, 192)";
    ctx.fillRect(0, 0, width, height);
    ctx.fill();

    var matrix_sun = m3_tra(center[0], center[1]);
    {  // sun
      ctx.fillStyle = "rgb(255, 0, 0)";
      ctx.beginPath(); {
        ctx.arc(center[0], center[1], 30, 0, 2.0 * Math.PI, false);
      } ctx.closePath();
      ctx.fill();
    }

    var matrix_earth = m3_mul(m3_mul(matrix_sun, m3_rot(theta)),
                              m3_tra(60.0, 60.0));
    {  // earth
      ctx.fillStyle = "rgb(0, 0, 255)";
      var pos = m3_apply(matrix_earth, [0.0, 0.0, 1.0]);
      ctx.beginPath(); {
        ctx.arc(pos[0], pos[1], 20, 0, 2.0 * Math.PI, false);
      } ctx.closePath();
      ctx.fill();
    }

    var matrix_moon = m3_mul(m3_mul(matrix_earth, m3_rot(theta)),
                             m3_tra(30.0, 30.0));
    {  // moon
      ctx.fillStyle = "rgb(255, 255, 0)";
      var pos = m3_apply(matrix_moon, [0.0, 0.0, 1.0]);
      ctx.beginPath(); {
        ctx.arc(pos[0], pos[1], 10, 0, 2.0 * Math.PI, false);
      } ctx.closePath();
      ctx.fill();
    }

    {  // spaceship
      ctx.fillStyle = "rgb(0, 0, 0)";
      var velocity = v_sub(m3_apply(matrix_moon, [0.0, 0.0, 1.0]),
                           pos_spaceship);
      var len = v_length(velocity);
      if (3.0 < len) { len = 3.0; }
      pos_spaceship = v_add(pos_spaceship,
                            v_mul(v_normalize(velocity), len));
      ctx.beginPath(); {
        ctx.arc(pos_spaceship[0], pos_spaceship[1],
                10, 0, 2.0 * Math.PI, false);
      } ctx.closePath();
      ctx.fill();
    }

    theta += 0.05;
  }

  setInterval(draw, 32);
}

/*
row order matrix
 */
function m3_rot(theta) {
  var c = Math.cos(theta);
  var s = Math.sin(theta);
  return [  c   s,  0,
           -s,  c,  0,
            0,  0,  1, ];
}
function m3_tra(x, y) {
  return [  1,  0,  0,
            0,  1,  0,
            x,  y,  1, ];
}
function m3_mul(lhs, rhs) {
  return [
    lhs[3*0+0]*rhs[3*0+0] + lhs[3*1+0]*rhs[3*0+1] + lhs[3*2+0]*rhs[3*0+2],
    lhs[3*0+1]*rhs[3*0+0] + lhs[3*1+1]*rhs[3*0+1] + lhs[3*2+1]*rhs[3*0+2],
    lhs[3*0+2]*rhs[3*0+0] + lhs[3*1+2]*rhs[3*0+1] + lhs[3*2+2]*rhs[3*0+2],

    lhs[3*0+0]*rhs[3*1+0] + lhs[3*1+0]*rhs[3*1+1] + lhs[3*2+0]*rhs[3*1+2],
    lhs[3*0+1]*rhs[3*1+0] + lhs[3*1+1]*rhs[3*1+1] + lhs[3*2+1]*rhs[3*1+2],
    lhs[3*0+2]*rhs[3*1+0] + lhs[3*1+2]*rhs[3*1+1] + lhs[3*2+2]*rhs[3*1+2],

    lhs[3*0+0]*rhs[3*2+0] + lhs[3*1+0]*rhs[3*2+1] + lhs[3*2+0]*rhs[3*2+2],
    lhs[3*0+1]*rhs[3*2+0] + lhs[3*1+1]*rhs[3*2+1] + lhs[3*2+1]*rhs[3*2+2],
    lhs[3*0+2]*rhs[3*2+0] + lhs[3*1+2]*rhs[3*2+1] + lhs[3*2+2]*rhs[3*2+2],
  ];
}
function m3_invert(lhs) {  // homogenious
  return [  lhs[3*1+1],  lhs[3*1+0],  lhs[3*0+2],
            lhs[3*0+1],  lhs[3*0+0],  lhs[3*1+2],
           -lhs[3*2+0], -lhs[3*2+1],  lhs[3*2+2], ];
}
function m3_apply(lhs, rhs) {
  return [ lhs[3*0+0]*rhs[0] + lhs[3*1+0]*rhs[1] + lhs[3*2+0]*rhs[2],
           lhs[3*0+1]*rhs[0] + lhs[3*1+1]*rhs[1] + lhs[3*2+1]*rhs[2],
           lhs[3*0+2]*rhs[0] + lhs[3*1+2]*rhs[1] + lhs[3*2+2]*rhs[2], ];
}
function v_add(lhs, rhs) {
  return [lhs[0] + rhs[0], lhs[1] + rhs[1], lhs[2] + rhs[2]];
}
function v_sub(lhs, rhs) {
  return [lhs[0] - rhs[0], lhs[1] - rhs[1], lhs[2] - rhs[2]];
}
function v_mul(lhs, rhs) {
  return [lhs[0] * rhs, lhs[1] * rhs, lhs[2] * rhs];
}
function v_div(lhs, rhs) {
  return [lhs[0] / rhs, lhs[1] / rhs, lhs[2] / rhs];
}
function v_inner(lhs, rhs) {
  return lhs[0] * rhs[0] + lhs[1] * rhs[1] + lhs[2] * rhs[2];
}
function v_length(lhs) {
  return Math.sqrt(v_inner(lhs, lhs));
}
function v_normalize(lhs) {
  return v_div(lhs, v_length(lhs));
}