2015年8月15日土曜日

canvasで2Dアニメーション

html5のcanvasアニメーションを調べながら書いたコード。
とりあえず画像の表示と移動、回転を試したかっただけ。
手持ちの素材を適当に使ったらかなりくるった出来上がりになってしまったが気にしてはいけない。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
</head>

<body>
<canvas id="cnvs" width="640" height="480"></canvas>
<input id="play-or-pause" type="button" value="loading">
<script>
/*
  background: 背景のURL
  flyingObjects: 移動物のURLの配列
  num: 移動物の数
  fps: フレームレート
  xmax:1フレーム当たりの移動物のx軸方向の最大移動量(px)
  ymax:1フレーム当たりの移動物のy軸方向の最大移動量(px)
  tmax:1フレーム当たりの移動物の最大回転角(deg) 
*/
(function(background, flyingObjects, num, fps, xmax, ymax, tmax) {

  var canvas = document.getElementById("cnvs");
  var ctx = canvas.getContext("2d");
  var button = document.getElementById("play-or-pause");

  const PI2 = Math.PI * 2;

  var loader = (function() {
    var count = 0;
    return function() {
      if (++count > num) {
        button.value = "play";
        draw();  
      }
    }
  })();

  var bg = new Image();
  bg.src = background;
  bg.onload = loader;

  var fo = new Array(num);
  for (var i = 0; i < num; i++) {
    fo[i] = new Image();
    fo[i].params = {
      speedx: Math.random() * 2 * xmax - xmax,
      speedy: Math.random() * 2 * ymax - ymax,
      dstx: Math.random() * canvas.width,
      dsty: Math.random() * canvas.height,
      theta: ((Math.random() * 2 * tmax - tmax) * Math.PI / 180),
      angle: 0,
    };
    fo[i].src = flyingObjects[Math.random() * flyingObjects.length | 0];
    fo[i].onload = loader;
  }

  function draw() {
    ctx.drawImage(bg, 0, 0, canvas.width, canvas.height);
    for (var i = 0; i < num; i++) {
      var f = fo[i];
      var p = f.params;
      var cx = f.naturalWidth / 2;
      var cy = f.naturalHeight / 2;

      ctx.save();
      ctx.translate(p.dstx + cx, p.dsty + cy);
      ctx.rotate(p.angle);
      ctx.drawImage(f, -cx, -cy);
      ctx.restore();

      p.dstx += p.speedx;
      p.dsty += p.speedy;
      p.angle += p.theta;

      if (p.dstx > canvas.width) {
        p.dstx = -f.naturalWidth;
      }
      if (p.dstx < -f.naturalWidth) {
        p.dstx = canvas.width - 1;
      }
      if (p.dsty > canvas.height) {
        p.dsty = -f.naturalHeight;
      }
      if (p.dsty < -f.naturalHeight) {
        p.dsty = canvas.height - 1;
      }
      if (p.angle < -PI2) {
        p.angle += PI2;
      }
      if (p.angle > PI2) {
        p.angle -= PI2;
      }
    }
  };

  button.onclick = (function() {
    var intervalId = null;
    var interval = 1000 / fps | 0;
    return function() {
      if (button.value === "pause") {
        clearInterval(intervalId);
        button.value = "play";
      } else if (button.value === "play") {
        intervalId = setInterval(draw, interval);
        button.value = "pause";
      }
    };
  })();

})("images/soccer.jpg",
   ["images/saturn.png",
    "images/pig.png",
    "images/heart.png",
    "images/japan.gif"],
    50, 50, 3, 5, 30);
</script>
</body>
</html>




ボタンを押せば再生/一時停止します。

0 件のコメント:

コメントを投稿