基于Canvas和和原生JS实现俄罗斯方块小游戏

发布于:2025-03-10 ⋅ 阅读:(15) ⋅ 点赞:(0)

这里是一个完整的H5俄罗斯方块游戏,使用了 HTML + CSS + JavaScript (原生) 实现,支持基本的俄罗斯方块玩法,如:
✅ 方块自动下落
✅ 方向键控制移动、旋转、加速下落
✅ 方块堆叠、消行
✅ 计分系统
在这里插入图片描述

canvas 上绘制游戏,并使用 requestAnimationFrame 进行流畅的动画渲染。下面是完整的代码:


const canvas = document.getElementById("tetris");
const ctx = canvas.getContext("2d");
const ROWS = 20;
const COLS = 10;
const 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]], // S
  [[0, 1, 1], [1, 1, 0]], // Z
  [[1, 0, 0], [1, 1, 1]], // J
  [[0, 0, 1], [1, 1, 1]], // L
];

// 颜色数组
const COLORS = ["cyan", "yellow", "purple", "green", "red", "blue", "orange"];

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

// 生成新方块
function newPiece() {
  const index = Math.floor(Math.random() * SHAPES.length);
  currentPiece = {
    shape: SHAPES[index],
    color: COLORS[index],
    row: 0,
    col: Math.floor(COLS / 2) - 1,
  };
}
newPiece();

// 画一个方块
function drawBlock(x, y, color) {
  ctx.fillStyle = color;
  ctx.fillRect(x * SIZE, y * SIZE, SIZE, SIZE);
  ctx.strokeStyle = "black";
  ctx.strokeRect(x * SIZE, y * SIZE, SIZE, SIZE);
}

// 画游戏面板
function drawBoard() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  for (let r = 0; r < ROWS; r++) {
    for (let c = 0; c < COLS; c++) {
      if (board[r][c]) {
        drawBlock(c, r, board[r][c]);
      }
    }
  }
  drawPiece();
}

// 画当前下落的方块
function drawPiece() {
  currentPiece.shape.forEach((row, r) => {
    row.forEach((cell, c) => {
      if (cell) {
        drawBlock(currentPiece.col + c, currentPiece.row + r, currentPiece.color);
      }
    });
  });
}

// 碰撞检测
function isValidMove(offsetRow, offsetCol, shape) {
  return shape.every((row, r) =>
    row.every((cell, c) => {
      if (!cell) return true;
      let newRow = currentPiece.row + r + offsetRow;
      let newCol = currentPiece.col + c + offsetCol;
      return (
        newRow >= 0 &&
        newRow < ROWS &&
        newCol >= 0 &&
        newCol < COLS &&
        !board[newRow][newCol]
      );
    })
  );
}

// 移动方块
function movePiece(offsetRow, offsetCol) {
  if (isValidMove(offsetRow, offsetCol, currentPiece.shape)) {
    currentPiece.row += offsetRow;
    currentPiece.col += offsetCol;
  }
}

// 旋转方块
function rotatePiece() {
  const rotated = currentPiece.shape[0].map((_, c) =>
    currentPiece.shape.map(row => row[c]).reverse()
  );
  if (isValidMove(0, 0, rotated)) {
    currentPiece.shape = rotated;
  }
}

// 触底逻辑
function placePiece() {
  currentPiece.shape.forEach((row, r) => {
    row.forEach((cell, c) => {
      if (cell) {
        board[currentPiece.row + r][currentPiece.col + c] = currentPiece.color;
      }
    });
  });
  clearRows();
  newPiece();
  if (!isValidMove(0, 0, currentPiece.shape)) {
    gameOver = true;
  }
}

// 消行逻辑
function clearRows() {
  board = board.filter(row => row.some(cell => !cell));
  while (board.length < ROWS) {
    board.unshift(Array(COLS).fill(0));
    score += 10;
  }
}

// 游戏循环
function update() {
  if (!gameOver) {
    if (isValidMove(1, 0, currentPiece.shape)) {
      movePiece(1, 0);
    } else {
      placePiece();
    }
    drawBoard();
    document.getElementById("score").innerText = score;
    setTimeout(update, 500);
  } else {
    alert("游戏结束!");
  }
}
update();

// 监听键盘事件
document.addEventListener("keydown", (event) => {
  if (gameOver) return;
  if (event.key === "ArrowLeft") movePiece(0, -1);
  if (event.key === "ArrowRight") movePiece(0, 1);
  if (event.key === "ArrowDown") movePiece(1, 0);
  if (event.key === "ArrowUp") rotatePiece();
  drawBoard();
});


说明:

  • 使用 canvas 进行绘制
  • 方块随机生成并自动下落
  • 方向键:
    • 左/右键 移动
    • 下键 加速下落
    • 上键 旋转
  • 触底后自动消行并累加得分
  • 游戏结束提示 alert("游戏结束!")

你可以直接将这段代码放入 index.html 页面,并配合 <canvas> 运行。