ブロックパズルは、落ちてくるブロック(テトロミノ)を回転させながら積み上げ、横一列を揃えて消していく、テトリス風の世界的に有名なパズルゲームです。テトロミノの回転データの扱い方、タイマーを使った自動落下、そして揃った行を消す処理など、ゲームプログラミングの重要なテクニックをたくさん学べます。
ブロックパズルのボードは10列x20行のグリッドです。DOMのdiv要素で各セルを生成し、CSSグリッドで並べましょう。セルの2次元配列を作っておくと、高速に色を変更できます。
var COLS = 10; // 横のマス数
var ROWS = 20; // 縦のマス数
var board = []; // ボード配列 [row][col] = '' or 色名
var cells = []; // DOMセルの2次元配列
function createBoard() {
boardEl.innerHTML = '';
cells = [];
for (var y = 0; y < ROWS; y++) {
cells[y] = [];
for (var x = 0; x < COLS; x++) {
var cell = document.createElement('div');
cell.className = 'tetris-cell';
boardEl.appendChild(cell);
cells[y][x] = cell;
}
}
}
function initBoard() {
board = [];
for (var y = 0; y < ROWS; y++) {
board[y] = [];
for (var x = 0; x < COLS; x++) {
board[y][x] = '';
}
}
}
board配列がゲームのデータ、cells配列が描画用のDOM要素です。データと表示を分けることで、ロジックがすっきりします。
ブロックパズルには7種類のテトロミノ(I, O, T, S, Z, J, L)があり、それぞれ4つの回転状態を持ちます。各状態を座標の配列として定義することで、回転処理がとてもシンプルになります。
var TETROMINOS = {
I: {
shapes: [
[[0,0],[1,0],[2,0],[3,0]], // 横向き
[[0,0],[0,1],[0,2],[0,3]], // 縦向き
[[0,0],[1,0],[2,0],[3,0]],
[[0,0],[0,1],[0,2],[0,3]]
],
color: 'I'
},
T: {
shapes: [
[[0,0],[1,0],[2,0],[1,1]],
[[0,0],[0,1],[0,2],[1,1]],
[[1,0],[0,1],[1,1],[2,1]],
[[1,0],[1,1],[1,2],[0,1]]
],
color: 'T'
}
// ... S, Z, J, L, O も同様に定義
};
各テトロミノの4つの回転状態を事前に定義しておくアプローチです。回転時はrotationの値を0〜3の間で循環させるだけで済みます。
ピースを動かしたり回転させたりする前に、移動先が有効な位置かどうかをチェックする必要があります。ボードの範囲外や、既に他のブロックがある場所には移動できません。
function isValidPosition(piece) {
var shape = TETROMINOS[piece.type].shapes[piece.rotation];
for (var i = 0; i < shape.length; i++) {
var newX = piece.x + shape[i][0];
var newY = piece.y + shape[i][1];
if (newX < 0 || newX >= COLS || newY < 0 || newY >= ROWS) {
return false;
}
if (board[newY][newX] !== '') {
return false;
}
}
return true;
}
function rotatePiece() {
var newRotation = (currentPiece.rotation + 1) % 4;
var testPiece = {
type: currentPiece.type,
rotation: newRotation,
x: currentPiece.x,
y: currentPiece.y
};
if (isValidPosition(testPiece)) {
currentPiece.rotation = newRotation;
render();
return;
}
// ウォールキック: 左右にずらして試す
var kicks = [1, -1, 2, -2];
for (var i = 0; i < kicks.length; i++) {
testPiece.x = currentPiece.x + kicks[i];
if (isValidPosition(testPiece)) {
currentPiece.rotation = newRotation;
currentPiece.x = testPiece.x;
render();
return;
}
}
}
回転が壁にぶつかる場合は、左右にずらして試す「ウォールキック」を実装しています。これにより、壁際でも快適に回転操作ができます。
テトロミノは一定間隔で自動的に1マスずつ下に落ちます。setTimeoutを使って落下タイマーを管理し、レベルが上がるにつれて速度を上げましょう。
var INITIAL_SPEED = 800; // 初期落下速度(ms)
var MIN_SPEED = 80; // 最速
var SPEED_DECREASE = 60; // レベルごとの速度減少
function gameStep() {
if (!gameRunning || !currentPiece) return;
var testPiece = {
type: currentPiece.type,
rotation: currentPiece.rotation,
x: currentPiece.x,
y: currentPiece.y + 1
};
if (isValidPosition(testPiece)) {
currentPiece.y++;
render();
gameLoopTimer = setTimeout(gameStep, currentSpeed);
} else {
// 接地 → ロック → 行消去 → 次のピース
lockPiece();
clearLines();
currentPiece = spawnPiece();
if (!currentPiece) { gameOver(); return; }
render();
gameLoopTimer = setTimeout(gameStep, currentSpeed);
}
}
function calcSpeed() {
var speed = INITIAL_SPEED - ((level - 1) * SPEED_DECREASE);
return Math.max(speed, MIN_SPEED);
}
横一列がすべて埋まったら、その行を消して上の行を落とします。一度に消した行数に応じてスコアにボーナスがつきます。
var LINE_SCORES = { 1: 100, 2: 300, 3: 500, 4: 800 };
function clearLines() {
var linesToClear = [];
for (var y = ROWS - 1; y >= 0; y--) {
var full = true;
for (var x = 0; x < COLS; x++) {
if (board[y][x] === '') { full = false; break; }
}
if (full) linesToClear.push(y);
}
if (linesToClear.length > 0) {
// ラインを削除して上に空行を追加
for (var i = linesToClear.length - 1; i >= 0; i--) {
board.splice(linesToClear[i], 1);
}
for (var i = 0; i < linesToClear.length; i++) {
var emptyRow = [];
for (var x = 0; x < COLS; x++) emptyRow.push('');
board.unshift(emptyRow);
}
// スコア加算
var lineScore = LINE_SCORES[linesToClear.length] || 200;
score += lineScore * level;
}
}
board.spliceで揃った行を削除し、board.unshiftで上に空行を追加します。配列の操作だけで行を詰める処理が実現できるのがポイントです。4行同時消しは800点と大きなボーナスがつきます。
このチュートリアルでは、テトロミノの回転データの管理、衝突判定とウォールキック、タイマーによる自動落下、そして行消去の仕組みを学びました。さらに発展させるなら、ホールド機能(ピースの一時保管)、Tスピン判定、ネクストピースの複数表示、スコアランキングなどを追加してみましょう。
A: はい、大丈夫です。このチュートリアルではステップごとにコードを書いていくので、初めての方でも順番に進めれば完成できます。わからないところがあれば、ひなテックの教室で質問もできますよ。
A: 基本部分は約30分〜1時間で作れます。見た目をこだわったり機能を追加すると、さらに楽しく発展させられます。