Skip to content

Instantly share code, notes, and snippets.

@kujirahand
Last active August 7, 2025 14:25
Show Gist options
  • Save kujirahand/9e53e990cd7eae443f60690c67ed6986 to your computer and use it in GitHub Desktop.
Save kujirahand/9e53e990cd7eae443f60690c67ed6986 to your computer and use it in GitHub Desktop.
落ちものゲーム
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>落ちものゲーム</title>
<style>
canvas { background: #eee; display: block; margin: 20px auto; }
</style>
</head>
<body>
<canvas id="gameCanvas" width="300" height="450"></canvas>
<script>
const cols = 10;
const rows = 15;
const cellSize = 30;
const colors = ["red", "green", "blue", "yellow", "purple"];
let grid = [];
// グリッド初期化
for (let y = 0; y < rows; y++) {
grid[y] = Array(cols).fill(0);
}
// 障害物を3つランダム配置
for (let i = 0; i < 3; i++) {
let x, y;
do {
x = Math.floor(Math.random() * cols);
y = Math.floor(Math.random() * (rows - 5)) + 5;
} while (grid[y][x] !== 0);
grid[y][x] = Math.floor(Math.random() * colors.length) + 1;
}
// ブロック情報
const baseShape = [ {x:0, y:0}, {x:0, y:1}, {x:1, y:1}, {x:2, y:1} ];
let piece;
let interval;
// 新しいブロック生成
function spawnPiece() {
piece = {
coords: baseShape.map(c => ({ x: c.x, y: c.y })),
x: Math.floor((cols - 3) / 2),
y: 0,
color: Math.floor(Math.random() * colors.length) + 1
};
// スポーン時に衝突したらゲームオーバー
if (collides(piece.x, piece.y, piece.coords)) {
clearInterval(interval);
alert("ゲームオーバー");
}
}
// 衝突判定
function collides(px, py, coords) {
return coords.some(c => {
const x = px + c.x;
const y = py + c.y;
return x < 0 || x >= cols || y < 0 || y >= rows || grid[y][x] !== 0;
});
}
// 回転処理
function rotate(coords) {
const newCoords = coords.map(c => ({ x: c.y, y: -c.x }));
const minX = Math.min(...newCoords.map(c => c.x));
const minY = Math.min(...newCoords.map(c => c.y));
return newCoords.map(c => ({ x: c.x - minX, y: c.y - minY }));
}
// キー操作
document.addEventListener("keydown", e => {
if (e.key === "ArrowLeft" && !collides(piece.x - 1, piece.y, piece.coords)) {
piece.x--;
} else if (e.key === "ArrowRight" && !collides(piece.x + 1, piece.y, piece.coords)) {
piece.x++;
} else if (e.key === "ArrowUp") {
const rc = rotate(piece.coords);
if (!collides(piece.x, piece.y, rc)) piece.coords = rc;
}
});
// ブロックを固定&消去&次生成
function placePiece() {
piece.coords.forEach(c => {
grid[piece.y + c.y][piece.x + c.x] = piece.color;
});
clearLines();
spawnPiece();
}
// 同じ色が5個並んでいたら消去
function clearLines() {
const offsets = [1,2,3,4];
let toClear = [];
// 横
for (let y = 0; y < rows; y++) {
for (let x = 0; x <= cols - 5; x++) {
const v = grid[y][x];
if (v !== 0 && offsets.every(o => grid[y][x + o] === v)) {
for (let o = 0; o < 5; o++) toClear.push({ x: x + o, y: y });
}
}
}
// 縦
for (let x = 0; x < cols; x++) {
for (let y = 0; y <= rows - 5; y++) {
const v = grid[y][x];
if (v !== 0 && offsets.every(o => grid[y + o][x] === v)) {
for (let o = 0; o < 5; o++) toClear.push({ x: x, y: y + o });
}
}
}
// 消去
toClear.forEach(p => { grid[p.y][p.x] = 0; });
if (toClear.length > 0) {
// 落下処理
for (let x = 0; x < cols; x++) {
const col = [];
for (let y = rows - 1; y >= 0; y--) {
if (grid[y][x] !== 0) col.push(grid[y][x]);
}
for (let y = rows - 1; y >= 0; y--) {
grid[y][x] = col[rows - 1 - y] || 0;
}
}
}
}
// 描画
function draw() {
const ctx = document.getElementById("gameCanvas").getContext("2d");
ctx.clearRect(0, 0, cols * cellSize, rows * cellSize);
// グリッド
for (let y = 0; y < rows; y++) {
for (let x = 0; x < cols; x++) {
if (grid[y][x]) {
ctx.fillStyle = colors[grid[y][x] - 1];
ctx.fillRect(x * cellSize, y * cellSize, cellSize, cellSize);
ctx.strokeRect(x * cellSize, y * cellSize, cellSize, cellSize);
}
}
}
// 現在のブロック
piece.coords.forEach(c => {
ctx.fillStyle = colors[piece.color - 1];
ctx.fillRect((piece.x + c.x) * cellSize, (piece.y + c.y) * cellSize, cellSize, cellSize);
ctx.strokeRect((piece.x + c.x) * cellSize, (piece.y + c.y) * cellSize, cellSize, cellSize);
});
}
// ゲーム開始
spawnPiece();
draw();
interval = setInterval(() => {
if (!collides(piece.x, piece.y + 1, piece.coords)) {
piece.y++;
} else {
placePiece();
}
draw();
}, 300);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment