コアダンプの数だけ強くなれるよ

見習いエンジニアの備忘log

HTML5/Javascriptで糸通し風アプリを作る

今回はHTML5のcanvasを使って、ガラケー時代の名作ゲームである糸通しっぽい動きをする曲線を作ってみた。 即席で作ったのでソースコードは改良が必要。スマホでは恐らく正常に動かない。

www.appdime.jp

完成品


ソースコード全体

<html lang="ja">
<head>
<meta charset="utf-8">
<script>
(function() {
  var canvas;
  var ctx;
  var drawTimerID;
  var raiseTimerID;
  var dropTimerID;
  var dot = [];
  var velocity = 0; // 糸の上昇or下降の速さ
  
  var FIELD = {
    'FPS'     : 60,  // 画面更新の速さ
    'CPS'     : 1,   // 糸の操作周期
    'GRAVITY' :120,  // 重力加速度
    'PUSHUP'  :120,  // クリック中の抗力
    'X_DOT'   : 2,   // 点の横幅(px)
    'Y_DOT'   : 2,   // 点の縦幅(px)
    'INVALID' : -1,  // 無効値
  };
  
  // 初期化処理(キャンバス作成,イベントハンドラ登録)
  function initialize () {
    // キャンバスを初期化
    if (canvas == null) {
      canvas = document.getElementById('field');
    }
    
    if (canvas.getContext) {
      ctx = canvas.getContext('2d');
      ctx.fillStyle = "rgb(0,0,0)";
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      
      ctx.font = "18px 'MS ゴシック'";
      ctx.fillStyle = "white";
      ctx.fillText("画面をクリックでスタート", 40, 150);
    } else {
      return;
    }
    
    // 軌跡を初期化
    dot[0] = canvas.height/4;
    for(var i = 1; i < canvas.width / 2; i++) {
      dot[i] = FIELD.INVALID;
    }
    
    // 糸の速さを初期化
    velocity = 0;
    
    // クリックでゲーム開始
    canvas.addEventListener('click', startGame, false);
  }
  
  function startGame() {
    ctx.fillStyle = "rgb(0,0,0)";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    
    canvas.removeEventListener('click', startGame, false);
    canvas.addEventListener('mousedown', raiseLine, false);
    canvas.addEventListener('mouseup', dropLine, false);
    
    dropTimerID = setInterval(function() { velocity += FIELD.GRAVITY * 1/FIELD.FPS; }, FIELD.CPS);
    drawTimerID = setInterval(drawDot, 1000/FIELD.FPS);
  }
  
  
  function raiseLine(e) {
    if (e.button == 0) {
      clearInterval(dropTimerID);
      raiseTimerID = setInterval(function() { velocity -= FIELD.PUSHUP * 1/FIELD.FPS; }, FIELD.CPS);
    }
  };
  
  function dropLine(e) {
    if (e.button == 0) {
      clearInterval(raiseTimerID);
      dropTimerID = setInterval(function() { velocity += FIELD.GRAVITY * 1/FIELD.FPS; }, FIELD.CPS);
    }
  };
  
  
  function drawDot() {
    
    // 軌跡の更新
    for (var i = 0; i < (canvas.width / 2 - 1); i++) {
      dot[canvas.width / 2 - 1 - i] = dot[canvas.width / 2 - 1 - (i + 1)]
    }
    
    dot[0] = velocity * (1/FIELD.FPS) + dot[1];
    
    // 軌跡の描画
    ctx.fillStyle = "rgb(0,0,0)";
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    for (var i = 0; i < canvas.width/2; i++) {
      if (dot[i] != FIELD.INVALID) {
        ctx.fillStyle = "rgb(255,255,255)";
        ctx.fillRect(canvas.width/2 - i, dot[i], FIELD.X_DOT, FIELD.Y_DOT);
      }
    }
    
    if (dot[0] >= canvas.height || dot[0] < 0) {
      resetGame();
    }
    
  }
  
  function resetGame() {
    clearInterval(drawTimerID);
    clearInterval(dropTimerID);
    clearInterval(raiseTimerID);
    canvas.removeEventListener('mousedown', raiseLine, false);
    canvas.removeEventListener('mouseup', dropLine, false);
    initialize();
  }
  
  window.addEventListener('load', initialize, false);
})();
</script>
</head>
<body>
<canvas id="field" width="300" height="300">
</body>
<html>


流石に障害物が何もないと味気ないので改良して再度アップしたい。


(追記:下記で改良してみた) www.segmentation-fault.xyz