one-yeheng
Version:
A simple Tetris game
186 lines (170 loc) • 5.25 kB
JavaScript
const canvas = document.getElementById('tetris');
const context = canvas.getContext('2d');
const startButton = document.getElementById('start-button');
const ROWS = 20; // 行数
const COLS = 10; // 列数
const BLOCK_SIZE = 30; // 每个方块的大小
const shapes = [
[[1, 1, 1, 1]], // I
[[1, 1], [1, 1]], // O
[[0, 1, 0], [1, 1, 1]], // T
[[1, 1, 0], [0, 1, 1]], // Z
[[0, 1, 1], [1, 1, 0]], // S
[[1, 0, 0], [1, 1, 1]], // L
[[0, 0, 1], [1, 1, 1]] // J
];
let board = Array.from({ length: ROWS }, () => Array(COLS).fill(0));
let currentPiece = createPiece();
let score = 0;
let gameActive = false; // 游戏是否正在进行
// 创建随机方块
function createPiece() {
const type = shapes[Math.floor(Math.random() * shapes.length)];
return {
shape: type,
x: Math.floor(COLS / 2) - Math.floor(type[0].length / 2),
y: 0
};
}
// 绘制方块
function drawPiece(piece) {
piece.shape.forEach((row, y) => {
row.forEach((value, x) => {
if (value) {
context.fillStyle = 'cyan';
context.fillRect((piece.x + x) * BLOCK_SIZE, (piece.y + y) * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
context.strokeStyle = 'black';
context.strokeRect((piece.x + x) * BLOCK_SIZE, (piece.y + y) * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
}
});
});
}
// 绘制游戏板
function drawBoard() {
board.forEach((row, y) => {
row.forEach((value, x) => {
if (value) {
context.fillStyle = 'blue';
context.fillRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
context.strokeStyle = 'black';
context.strokeRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
}
});
});
}
// 碰撞检测
function collide(board, piece) {
for (let y = 0; y < piece.shape.length; y++) {
for (let x = 0; x < piece.shape[y].length; x++) {
if (
piece.shape[y][x] &&
(board[piece.y + y] && board[piece.y + y][piece.x + x]) !== 0
) {
return true;
}
}
}
return false;
}
// 固定方块
function freeze() {
currentPiece.shape.forEach((row, y) => {
row.forEach((value, x) => {
if (value) {
board[currentPiece.y + y][currentPiece.x + x] = value;
}
});
});
}
// 消除行
function clearLines() {
let linesCleared = 0;
board.forEach((row, y) => {
if (row.every(cell => cell !== 0)) {
board.splice(y, 1);
board.unshift(Array(COLS).fill(0));
linesCleared++;
}
});
if (linesCleared > 0) {
score += linesCleared * 10;
document.getElementById('score').innerText = `得分: ${score}`;
}
}
// 更新游戏状态
function update() {
if (!gameActive) return; // 如果游戏未开始,则不更新游戏状态
currentPiece.y++; // 方块下落
if (collide(board, currentPiece)) {
currentPiece.y--; // 如果碰撞,回退一步
freeze(); // 固定方块
clearLines(); // 消除满行
currentPiece = createPiece(); // 生成新方块
if (collide(board, currentPiece)) {
// 如果新方块也碰撞,游戏结束
alert(`游戏结束!得分: ${score}`);
gameActive = false; // 标记游戏为未进行中
startButton.textContent = '重新开始'; // 修改按钮文字
}
}
}
// 渲染游戏
function render() {
context.clearRect(0, 0, canvas.width, canvas.height);
drawBoard();
drawPiece(currentPiece);
}
// 游戏循环
function gameLoop() {
update();
render();
setTimeout(gameLoop, 500);
}
// 键盘控制
document.addEventListener('keydown', event => {
if (!gameActive) return; // 如果游戏未开始,则不响应键盘事件
if (event.key === 'ArrowLeft') {
currentPiece.x--;
if (collide(board, currentPiece)) {
currentPiece.x++;
}
} else if (event.key === 'ArrowRight') {
currentPiece.x++;
if (collide(board, currentPiece)) {
currentPiece.x--;
}
} else if (event.key === 'ArrowDown') {
currentPiece.y++;
if (collide(board, currentPiece)) {
currentPiece.y--;
}
} else if (event.key === 'ArrowUp') {
const rotated = rotate(currentPiece.shape);
if (!collide(board, { ...currentPiece, shape: rotated })) {
currentPiece.shape = rotated;
}
}
});
// 旋转方块
function rotate(piece) {
const N = piece.length;
const rotated = Array.from({ length: N }, () => Array(N).fill(0));
for (let y = 0; y < N; y++) {
for (let x = 0; x < N; x++) {
rotated[x][N - 1 - y] = piece[y][x];
}
}
return rotated;
}
// 启动游戏
function startGame() {
if (gameActive) return; // 如果游戏已经在进行中,则不再重复启动
gameActive = true; // 标记游戏为进行中
board = Array.from({ length: ROWS }, () => Array(COLS).fill(0)); // 初始化游戏板
currentPiece = createPiece(); // 生成初始方块
score = 0; // 重置得分
document.getElementById('score').innerText = `得分: ${score}`; // 更新得分显示
gameLoop(); // 启动游戏循环
}
// 绑定按钮点击事件
startButton.addEventListener('click', startGame);