(C)WorldWideSoftware

<!DOCTYPE html>
<html lang="ja">
 <head>
  <meta charset="utf-8">
  <title>ブロックの落下処理2</title>
 </head>
 <body>
  <canvas id="bg" width="480" height="480"></canvas><br>
  <a href="http://www.wwsft.com">(C)WorldWideSoftware</a><br>
【説明】ブロックを落下させる処理のサンプルです。
緑色の支柱をタップorクリックすると壊れていき、支柱が無くなると上にあるブロックが落下します。

<br>
<strong>
※各ブロックをオブジェクトとして処理する方法もありますが、
このサンプルではBGデータとその描画位置用の2種類の配列を使って実現しています。
このテクニックは、例えば画面全体に置かれた爆弾を一度に爆発させる処理など、色々なギミックに応用できます。
</strong>
<br>
<a href="block01src.html">ソースコードの確認</a>

  <script>
  //描画面(キャンバス)の準備
  var cvs = document.getElementById("bg");
  var ctx = cvs.getContext("2d");

  //クリックとタップの判定
  var tapX = 0, tapY = 0, tapC = 0;
  cvs.addEventListener("touchstart", touchStart);
  cvs.addEventListener("touchend", touchEnd);
  function touchStart(ev) {
   var rect = ev.target.getBoundingClientRect();
   tapX = ev.touches[0].clientX-rect.left;
   tapY = ev.touches[0].clientY-rect.top;
   tapC = 1;
  }
  function touchEnd(ev) {tapC = 0;}

  cvs.addEventListener("mousedown", mouseDown);
  cvs.addEventListener("mouseup", mouseUp);
  function mouseDown(ev) {
   var rect = ev.target.getBoundingClientRect();
   tapX = ev.clientX-rect.left;
   tapY = ev.clientY-rect.top;
   tapC = 1;
  }
  function mouseUp(ev) {tapC = 0;}

  //ブロックを配列で定義する 1,2,3が支柱 4がブロック
  var map = [
   [ 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 4, 0],
   [ 4, 4, 4, 0, 4, 4, 4, 0, 0, 0, 3, 0],
   [ 0, 0, 3, 0, 0, 3, 0, 0, 0, 4, 4, 4],
   [ 0, 0, 3, 0, 0, 3, 0, 0, 0, 0, 3, 0],
   [ 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 3, 0],
   [ 0, 0, 3, 0, 3, 0, 0, 0, 0, 0, 3, 0],
   [ 0, 0, 3, 0, 3, 0, 4, 4, 4, 0, 3, 0],
   [ 0, 4, 4, 4, 4, 0, 0, 3, 0, 0, 3, 0],
   [ 4, 4, 4, 0, 0, 0, 0, 3, 0, 0, 3, 0],
   [ 0, 3, 0, 0, 0, 0, 0, 4, 4, 4, 4, 0],
   [ 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0],
   [ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]
  ];

  //BG各マスの画像の位置をずらして表示するための配列
  var ofs = [
   [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
   [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
   [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
   [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
   [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
   [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
   [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
   [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
   [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
   [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
   [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
   [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  ];

  //画像の読み込み
  var img = [], iOK = [];
  function loadImg(n, fname) {
   iOK[n] = false;
   img[n] = new Image();
   img[n].src = fname;
   img[n].onload = function() { iOK[n] = true; }
  }

  loadImg(1, "pillar3.png");
  loadImg(2, "pillar2.png");
  loadImg(3, "pillar.png");
  loadImg(4, "block_red.png");

  //メイン処理
  var tmr = 0;
  function mainProc() {
   tmr++;
   var n, x, y;

   ctx.fillStyle = "black";
   ctx.fillRect(0, 0, 480, 480);

   //タップの判定
   if(tapC == 1) {
    x = parseInt(tapX/40);
    y = parseInt(tapY/40);
    if(1 <= map[y][x] && map[y][x] <= 3) map[y][x]--;//柱があれば壊していく
   }

   //BG描画
   for(y=0; y<12; y++)
   for(x=0; x<12; x++) {
    n = map[y][x];
    if(n > 0) {
     var ofsY = ofs[y][x];//Y方向の描画位置のオフセット値
     if(iOK[n] == true) ctx.drawImage(img[n], x*40, y*40-ofsY*10);
     if(ofsY > 0) ofs[y][x]--;//オフセット値がセットされている場合、描画のたびに位置を計算
    }
   }

   //ブロックを落下させる処理
   y = 10;
   x = 0;
   do {//マップデータを一番下の行から検索(操作)する

    var bn =  0;//y行にブロックや柱があるかを数える
    var bx = -1;//ブロックや柱がある場合、左端の位置
    var bp =  0;//その下に柱やブロックがあるか

    while(true) {//ブロックや柱があるか調べていく
     if(map[y][x] > 0 && ofs[y][x] == 0) {//ある & 動かし終わっている
      bn++;//数えて
      if(bx == -1) bx = x;//左端の位置を保持
      if(map[y+1][x] > 0) bp = 1;//下に何かあればフラグを立てる
     }
     x++;
     if(x == 12) break;//右端まで調べた
     if(map[y][x] == 0 && bn > 0) break;//ブロックor柱終わり
    }

    if(bn > 0) {//ブロックか柱がある場合
     if(bp == 0) {//下に何も無いなら落とす
      for(n=bx; n<bx+bn; n++) {
       map[y+1][n] = map[y][n];
       ofs[y+1][n] = 4;//Y方向の描画位置のオフセット値
       map[y][n] = 0;
       ofs[y][n] = 0;
      }
     }
    }//残りの部分も検索するのでx,yともに変更しない

    if(bn==0 || x==12) {//落とす必要なしor右端まで検索したら、次の行へ進む
     x=0;
     y--;
    }
   } while(y >= 0);

  }

  setInterval(mainProc, 100);
  </script>
 </body>
</html>

←動作確認に戻る