テトリス

<!DOCTYPE html>

<html lang="ja">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>テトリス</title>

<style>

body { font-family: Arial, sans-serif; text-align: center; }

canvas { border: 1px solid #000; background: #eee; display: block; margin: 0 auto; }

#score { font-size: 20px; margin: 20px; }

</style>

</head>

<body>

<h1>テトリス</h1>

<canvas id="gameCanvas" width="240" height="400"></canvas>

<div id="score">スコア: 0</div>

<button onclick="startGame()">再スタート</button>


<audio id="clearSound" src="https://www.soundjay.com/button/sounds/button-4.mp3"></audio>

<audio id="gameOverSound" src="https://www.soundjay.com/button/sounds/button-8.mp3"></audio>

<audio id="bgMusic" loop src="https://www.soundjay.com/button/sounds/button-1.mp3"></audio>


<script>

const canvas = document.getElementById("gameCanvas");

const ctx = canvas.getContext("2d");

const clearSound = document.getElementById("clearSound");

const gameOverSound = document.getElementById("gameOverSound");

const bgMusic = document.getElementById("bgMusic");


const COLS = 10;

const ROWS = 20;

const BLOCK_SIZE = 20;

const colors = ["#FF0D72", "#0DC2FF", "#0DFF72", "#F5FF0D", "#FF7B0D", "#FF0D35", "#6A0DAD"];


let board = Array.from({ length: ROWS }, () => Array(COLS).fill(0));

let score = 0;

let currentPiece;

let gameInterval;

let gameOver = false;


const pieces = [

[[1, 1, 1, 1]], // I

[[1, 1, 1], [0, 1, 0]], // T

[[1, 1], [1, 1]], // O

[[0, 1, 1], [1, 1, 0]], // S

[[1, 1, 0], [0, 1, 1]], // Z

[[1, 1, 1], [1, 0, 0]], // L

[[1, 1, 1], [0, 0, 1]] // J

];


function startGame() {

board = Array.from({ length: ROWS }, () => Array(COLS).fill(0));

score = 0;

gameOver = false;

document.getElementById("score").innerText = "スコア: " + score;

bgMusic.play();

spawnPiece();

gameInterval = setInterval(update, 500);

}


function spawnPiece() {

const randomIndex = Math.floor(Math.random() * pieces.length);

currentPiece = {

shape: pieces[randomIndex],

x: Math.floor(COLS / 2) - Math.floor(pieces[randomIndex][0].length / 2),

y: 0,

color: colors[randomIndex]

};


if (collision(0, 0)) {

gameOver = true;

gameOverSound.play();

clearInterval(gameInterval);

alert("ゲームオーバー");

}

}


function collision(offsetX, offsetY) {

for (let r = 0; r < currentPiece.shape.length; r++) {

for (let c = 0; c < currentPiece.shape[r].length; c++) {

if (currentPiece.shape[r][c]) {

const newX = currentPiece.x + c + offsetX;

const newY = currentPiece.y + r + offsetY;

if (newX < 0 || newX >= COLS || newY >= ROWS || board[newY]?.[newX]) {

return true;

}

}

}

}

return false;

}


function merge() {

for (let r = 0; r < currentPiece.shape.length; r++) {

for (let c = 0; c < currentPiece.shape[r].length; c++) {

if (currentPiece.shape[r][c]) {

board[currentPiece.y + r][currentPiece.x + c] = currentPiece.color;

}

}

}

}


function clearRows() {

let rowsCleared = 0;

for (let r = ROWS - 1; r >= 0; r--) {

if (board[r].every(cell => cell)) {

board.splice(r, 1);

board.unshift(Array(COLS).fill(0));

rowsCleared++;

}

}

if (rowsCleared > 0) {

clearSound.play();

score += rowsCleared * 10;

document.getElementById("score").innerText = "スコア: " + score;

}

}


function update() {

if (!gameOver) {

if (!collision(0, 1)) {

currentPiece.y++;

} else {

merge();

clearRows();

spawnPiece();

}

draw();

}

}


function draw() {

ctx.clearRect(0, 0, canvas.width, canvas.height);

board.forEach((row, r) => {

row.forEach((cell, c) => {

if (cell) {

ctx.fillStyle = cell;

ctx.fillRect(c * BLOCK_SIZE, r * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);

}

});

});


currentPiece.shape.forEach((row, r) => {

row.forEach((cell, c) => {

if (cell) {

ctx.fillStyle = currentPiece.color;

ctx.fillRect((currentPiece.x + c) * BLOCK_SIZE, (currentPiece.y + r) * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);

}

});

});

}


document.addEventListener("keydown", (event) => {

if (!gameOver) {

if (event.key === "ArrowLeft" && !collision(-1, 0)) {

currentPiece.x--;

} else if (event.key === "ArrowRight" && !collision(1, 0)) {

currentPiece.x++;

} else if (event.key === "ArrowDown" && !collision(0, 1)) {

currentPiece.y++;

} else if (event.key === "ArrowUp") {

rotate();

}

}

});


function rotate() {

const originalShape = currentPiece.shape;

currentPiece.shape = currentPiece.shape[0].map((_, index) => currentPiece.shape.map(row => row[index]).reverse());

if (collision(0, 0)) {

currentPiece.shape = originalShape; // 回転が衝突したら元に戻す

}

}


window.onload = startGame;

</script>

</body>

</html>

  • Xで共有
  • Facebookで共有
  • はてなブックマークでブックマーク

作者を応援しよう!

ハートをクリックで、簡単に応援の気持ちを伝えられます。(ログインが必要です)

応援したユーザー

応援すると応援コメントも書けます

新規登録で充実の読書を

マイページ
読書の状況から作品を自動で分類して簡単に管理できる
小説の未読話数がひと目でわかり前回の続きから読める
フォローしたユーザーの活動を追える
通知
小説の更新や作者の新作の情報を受け取れる
閲覧履歴
以前読んだ小説が一覧で見つけやすい
新規ユーザー登録無料

アカウントをお持ちの方はログイン

カクヨムで可能な読書体験をくわしく知る