当前位置: 首页 > article >正文

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

这里是一个完整的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> 运行。


http://www.kler.cn/a/578756.html

相关文章:

  • 【贪心算法】简介
  • el-input-number添加自定义内容class-unit
  • 【算法题】小鱼的航程
  • AWS中使用CloudFront分发位于S3中的静态网站
  • SV学习笔记——数组、队列
  • spring boot+vue项目(免费)
  • es-初体验easy-es时报错:找不到mapper
  • Vue 过滤器 filter(s) 的使用
  • win32汇编环境,对话框中使用树形视图示例四
  • Objective-C 中 @synthesize VS @dynamic
  • webtinyserver讲解
  • pytorch retain_grad vs requires_grad
  • 电路研究9.3.1——合宙Air780EP中的AT开发指南:TCP 使用 SSL 示例
  • 关于VScode终端无法识别外部命令
  • mysql安装(演示为mac安装流程)
  • 使用 Python 批量提取 PDF 书签:一款实用工具的实现
  • Hadoop集群搭建(一)安装jdk
  • Nacos高频面试题10个
  • 深度学习与数据挖掘题库:401-500题精讲
  • 技术领域,有许多优秀的博客和网站