テトリス
<!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>
新規登録で充実の読書を
- マイページ
- 読書の状況から作品を自動で分類して簡単に管理できる
- 小説の未読話数がひと目でわかり前回の続きから読める
- フォローしたユーザーの活動を追える
- 通知
- 小説の更新や作者の新作の情報を受け取れる
- 閲覧履歴
- 以前読んだ小説が一覧で見つけやすい
アカウントをお持ちの方はログイン
ビューワー設定
文字サイズ
背景色
フォント
組み方向
機能をオンにすると、画面の下部をタップする度に自動的にスクロールして読み進められます。
応援すると応援コメントも書けます