操作方法
- ← → : 左右移動
- ↓ : 加速落下
- ↑ : 回転
- ライン消すとスコア+100/ライン
- 積み上がってゲームオーバーになったらアラート出る
Score: 0
GAME OVER
<テトリス>使用コード
テトリスを作るにあたり使用したコードです。
ご自由にコピペしてお使いください。
私は人間ですので誤りがあるかもしれません。その際にはご自分でご調整ください。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Simple Tetris - Elon Style</title>
<style>
body {
margin: 0;
height: 100vh;
background: #000;
display: flex;
justify-content: center;
align-items: center;
font-family: Arial, sans-serif;
}
#game {
position: relative;
}
canvas {
border: 4px solid #333;
background: #111;
box-shadow: 0 0 30px rgba(0, 255, 255, 0.3);
}
#info {
position: absolute;
top: 10px;
left: 10px;
color: #0ff;
font-size: 18px;
text-shadow: 0 0 10px #0ff;
}
#next {
position: absolute;
top: 60px;
right: -140px;
width: 120px;
height: 120px;
background: #222;
border: 2px solid #444;
}
#game-over {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #f00;
font-size: 48px;
font-weight: bold;
text-shadow: 0 0 20px #f00;
display: none;
}
</style>
</head>
<body>
<div id="game">
<canvas id="tetris" width="240" height="480"></canvas>
<div id="info">Score: <span id="score">0</span></div>
<canvas id="next" width="120" height="120"></canvas>
<div id="game-over">GAME OVER</div>
</div>
<script>
const BOARD_WIDTH = 10;
const BOARD_HEIGHT = 20;
const BLOCK_SIZE = 24;
const canvas = document.getElementById('tetris');
const ctx = canvas.getContext('2d');
const nextCanvas = document.getElementById('next');
const nextCtx = nextCanvas.getContext('2d');
const scoreElement = document.getElementById('score');
const gameOverElement = document.getElementById('game-over');
const PIECES = [
[[1,1,1,1]], // I
[[1,1],[1,1]], // O
[[0,1,0],[1,1,1]], // T
[[0,1,1],[1,1,0]], // S
[[1,1,0],[0,1,1]], // Z
[[1,0,0],[1,1,1]], // J
[[0,0,1],[1,1,1]] // L
];
const COLORS = ['#00f0f0','#ffff00','#a000f0','#00f000','#f00000','#0000f0','#f0a000'];
let board = Array(BOARD_HEIGHT).fill().map(() => Array(BOARD_WIDTH).fill(0));
let score = 0;
let dropCounter = 0;
let dropInterval = 1000;
let lastTime = 0;
let gameRunning = true;
let piece = createPiece();
let nextPiece = createPiece();
function createPiece() {
const type = Math.floor(Math.random() * PIECES.length);
return {
shape: PIECES[type],
color: type,
x: Math.floor(BOARD_WIDTH / 2) - Math.floor(PIECES[type][0].length / 2),
y: 0
};
}
function drawBlock(ctx, x, y, color) {
ctx.fillStyle = COLORS[color];
ctx.fillRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
ctx.strokeStyle = '#000';
ctx.strokeRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
nextCtx.clearRect(0, 0, nextCanvas.width, nextCanvas.height);
// 固定されたブロック描画
board.forEach((row, y) => {
row.forEach((value, x) => {
if (value) drawBlock(ctx, x, y, value - 1);
});
});
// 現在のピース描画
piece.shape.forEach((row, y) => {
row.forEach((value, x) => {
if (value) drawBlock(ctx, piece.x + x, piece.y + y, piece.color);
});
});
// NEXT描画
nextPiece.shape.forEach((row, y) => {
row.forEach((value, x) => {
if (value) drawBlock(nextCtx, x + 1, y + 1, nextPiece.color);
});
});
}
function collide() {
return piece.shape.some((row, y) =>
row.some((value, x) =>
value && (board[piece.y + y] && board[piece.y + y][piece.x + x]) !== 0
)
);
}
function merge() {
piece.shape.forEach((row, y) => {
row.forEach((value, x) => {
if (value) {
board[piece.y + y][piece.x + x] = piece.color + 1;
}
});
});
}
function clearLines() {
let lines = 0;
outer: for (let y = BOARD_HEIGHT - 1; y >= 0; y--) {
for (let x = 0; x < BOARD_WIDTH; x++) {
if (!board[y][x]) continue outer;
}
board.splice(y, 1);
board.unshift(Array(BOARD_WIDTH).fill(0));
lines++;
y++;
}
if (lines > 0) {
score += [0, 100, 300, 500, 800][lines];
scoreElement.textContent = score;
}
}
function drop() {
piece.y++;
if (collide()) {
piece.y--;
merge();
clearLines();
piece = nextPiece;
nextPiece = createPiece();
if (collide()) {
gameRunning = false;
gameOverElement.style.display = 'block';
}
}
dropCounter = 0;
}
function move(dir) {
piece.x += dir;
if (collide()) piece.x -= dir;
}
function rotate() {
const original = piece.shape;
piece.shape = piece.shape[0].map((_, i) =>
piece.shape.map(row => row[i]).reverse()
);
if (collide()) piece.shape = original;
}
document.addEventListener('keydown', e => {
if (!gameRunning) return;
if (e.key === 'ArrowLeft') move(-1);
if (e.key === 'ArrowRight') move(1);
if (e.key === 'ArrowDown') drop();
if (e.key === 'ArrowUp') rotate();
if (e.key === ' ') { // ハードドロップ
while (!collide()) piece.y++;
piece.y--;
drop();
}
});
function update(time = 0) {
if (!gameRunning) return;
const delta = time - lastTime;
lastTime = time;
dropCounter += delta;
if (dropCounter > dropInterval) drop();
draw();
requestAnimationFrame(update);
}
draw();
update();
</script>
</body>
</html>