テトリスを作る - 2 テトリミノ
最初の土台ができたので、次にテトリスゲームの主役である**テトリミノ(落下ブロック)の定義と、ゲームの心臓部となる落下処理(ゲームループ)**の実装をします。
ステップ 3: テトリミノ(ブロック)の定義
テトリスには7種類のテトリミノがあります。それぞれの形状と色をデータとしてJavaScriptで定義します。
3-1. テトリミノの形状と色の定義
tetris.jsに以下のコードを追加します。各テトリミノは、中心となる点を基準とした4x4の行列で表現 します。"0"と"1"を入れて"0"はFalse、"1"以上はTrueとなります。
例えば最初の配列は"1"が入っているところが" color: '#00FFFF'"で色が変わります。
表示させるのは1つだけなので、最後にランダムに表示させるように変数宣言しておきます。
let currentPiece = null;
// テトリミノの形状と色を定義する配列
// 1以上の数字はブロックの種類(色)を示す
const TETROMINOS = [
// 0: I型 (Cyan)
{
matrix: [
[0, 0, 0, 0],
[1, 1, 1, 1],
[0, 0, 0, 0],
[0, 0, 0, 0],
],
color: '#00FFFF' // シアン
},
// 1: J型 (Blue)
{
matrix: [
[2, 0, 0],
[2, 2, 2],
[0, 0, 0],
],
color: '#0000FF' // 青
},
// 2: L型 (Orange)
{
matrix: [
[0, 0, 3],
[3, 3, 3],
[0, 0, 0],
],
color: '#FFA500' // オレンジ
},
// 3: O型 (Yellow)
{
matrix: [
[4, 4],
[4, 4],
],
color: '#FFFF00' // 黄色
},
// 4: S型 (Green)
{
matrix: [
[0, 5, 5],
[5, 5, 0],
[0, 0, 0],
],
color: '#00FF00' // 緑
},
// 5: T型 (Purple)
{
matrix: [
[0, 6, 0],
[6, 6, 6],
[0, 0, 0],
],
color: '#800080' // 紫
},
// 6: Z型 (Red)
{
matrix: [
[7, 7, 0],
[0, 7, 7],
[0, 0, 0],
],
color: '#FF0000' // 赤
}
];
// 現在操作中のテトリミノを保持するオブジェクト
let currentPiece = null; 3-2. ランダムなテトリミノを生成する関数
次に、テトリミノをランダムに表示させたいので、currentPiece()関数を作ります。
最初の立ち上げに初期化しゲームの開始。そしてブロックが着地した際に新しいテトリミノをランダムに生成する関数を作ります。
function createPiece() {
// 0からTETROMINOSの数-1までの乱数を生成
const randIndex = Math.floor(Math.random() * TETROMINOS.length);
const pieceData = TETROMINOS[randIndex];
// テトリミノの情報をオブジェクトとして返す
return {
matrix: pieceData.matrix,
color: pieceData.color,
// 開始位置 (ボードの上端中央)
pos: { x: Math.floor(BOARD_WIDTH / 2) - Math.floor(pieceData.matrix[0].length / 2), y: 0 }
};
}最初表示される部分を定義しています。上の真ん中から落ち始めます。
pos: { x: Math.floor(BOARD_WIDTH / 2) - Math.floor(pieceData.matrix[0].length / 2), y: 0 }ステップ 4: ゲームループと落下処理の実装
テトリミノが時間と共に自動で落下するためのゲームループを実装します。
4-1. 現在のテトリミノを描画する関数
drawBoard関数と同様に、currentPieceをキャンバスに描画する関数を作成します。
例えばpiece.matrixには
[ [ 0, 5, 5 ],
[ 5, 5, 0 ],
[ 0, 0, 0 ] ]
function drawPiece(piece) {
// テトリミノのブロックを描画
piece.matrix.forEach((row, y) => {
row.forEach((value, x) => {
if (value !== 0) {
// ボード上の座標に変換
const drawX = (piece.pos.x + x) * BLOCK_SIZE;
const drawY = (piece.pos.y + y) * BLOCK_SIZE;
ctx.fillStyle = piece.color;
ctx.fillRect(drawX, drawY, BLOCK_SIZE, BLOCK_SIZE);
// ブロックの境界線を描画
ctx.strokeStyle = '#000';
ctx.strokeRect(drawX, drawY, BLOCK_SIZE, BLOCK_SIZE);
}
});
});
}(value !== 0)の場合ということは、1から7までの数字が入っているところで四角が色付きで描画されます。
4-2. メインのゲームループ
フレームごとに画面を更新し、一定時間ごとにテトリミノを落下させます。
function gameLoop() {
// 画面のクリア
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (currentPiece) {
currentPiece.pos.y++;
}
// 固定されたブロックと落下中のブロックを描画
if (currentPiece) {
drawPiece(currentPiece);
}
drawBoard();
}あとは以下で繰り返し処理を入れてゲームを動かします。
// --- ゲーム開始 ---
setInterval(gameLoop,1000)
currentPiece = createPiece(); // 最初のテトリミノを生成動作確認のポイント
お手軽にJSBinに貼り付けて確かめることができます。
ランダムなテトリミノが画面上部に生成される。
そのテトリミノが1秒ごとに1マスずつ落下していく。
これで、テトリスとしての基本的な「動き」が実現しました。
