(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>
←動作確認に戻る