俄罗斯方块,是无数人童年的回忆。七种不同形状的方块从天而降,玩家通过左右移动、旋转它们,把它们拼成完整的横行,一旦填满就会自动消除。这种看似简单的玩法,却让人一玩就是几个小时,甚至成为全球最经典的电子游戏之一。
但如果你要自己写一款俄罗斯方块,麻烦可就来了。
方块的随机生成 、旋转逻辑 、碰撞检测 、消除行算法 ,每一个都是代码大坑,更别提 UI 和响应式布局了。可现在,有了 Trae IDE,这些曾经的难题,居然一句话就能解决。
💡 我想要的,其实很简单
我的需求只有几个核心点:
- 七种经典形状的方块:正方形、长条、T 形、L 形......必须一个不落。
- 方块可以左右移动、旋转:用箭头键就能操作,手感要顺滑。
- 消除行的机制:当方块拼满一行时,整行消除,上方方块自动下落。
- 简单的 UI:不用复杂装饰,干净、直观,能看到方块、分数、下一个预览就够了。
过去我可能要花好几天写完,但这次我只在 Trae 里敲了一句:
"生成俄罗斯方块游戏,玩家控制下落的方块拼接,消除行。"

✨ Trae 如何"读懂"并实现
只等了几秒,Trae 就吐出了一份完整的俄罗斯方块代码,核心功能全都齐了:
✅ 方块系统 :七种形状、随机出现,还自动预览下一个方块。
✅ 移动与旋转 :上下左右控制逻辑自动写好,方块贴边、堆叠都能处理。
✅ 行消除 :只要拼满一行,动画闪烁一下就清掉,还自动计算得分。
✅ 简洁 UI:屏幕上是干净的网格,右边显示分数和预览窗口,视觉清晰又不乱。

Trae 写的代码结构也很干净,逻辑清晰,连变量命名都很顺手,几乎可以直接丢进项目跑。
🧩 玩起来,熟悉的"经典味道"
第一次运行 Trae 生成的俄罗斯方块,熟悉的感觉瞬间回来了:
🎮 左右箭头 → 控制方块移动
🔄 上箭头 → 旋转方块
⬇ 下箭头 → 加速下落
每次消除一行,屏幕闪一下,分数跳一下,音效可以随手加,经典街机感立刻拉满。
🛠 想扩展?一句话就行
Trae 的强大不止于"生成",更在于追加功能毫无压力,比如:
- 加入下一个方块预览("加一个方块预览框")
- 增加难度提升机制("每消 10 行,下落速度加快")
- 给方块上个皮肤("让方块变成彩色渐变")
- 增加排行榜和计时模式("记录玩家最高分和游戏时间")
一句自然语言指令,Trae 就能直接补齐功能代码,完美融合现有逻辑。
🎮 这是开发俄罗斯方块的新方式
以前写俄罗斯方块,逻辑又多又绕:
- 要写"方块旋转矩阵"
- 要做"碰撞检测"
- 要搞定"行消除"
全都得自己撸代码、调 bug。
而现在,有了 Trae,开发过程完全变了:
👉 不再是写代码的苦工 ,而是告诉工具我要什么,它帮我写好。
✅ 结语
如果你也想写一个俄罗斯方块,不必再从零开始。打开 Trae,输入:
"生成俄罗斯方块游戏,玩家控制下落的方块拼接,消除行。"
几秒钟,一个完整的俄罗斯方块就出现在你的屏幕上,旋转、移动、消除行、计分,全都好用,还能随时扩展功能。
这不只是"写游戏更快",而是从今天起,开发本身也变得像玩游戏一样有趣。
ini
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>俄罗斯方块</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f0f0f0;
}
.game-container {
display: flex;
gap: 20px;
}
.game-board {
border: 2px solid #333;
background-color: #111;
width: 300px;
height: 600px;
position: relative;
overflow: hidden;
}
.next-piece {
border: 2px solid #333;
background-color: #111;
width: 150px;
height: 150px;
position: relative;
}
.info-panel {
display: flex;
flex-direction: column;
gap: 20px;
}
.score-panel {
border: 2px solid #333;
background-color: #111;
color: white;
padding: 10px;
width: 150px;
}
.controls {
border: 2px solid #333;
background-color: #111;
color: white;
padding: 10px;
width: 150px;
}
.block {
position: absolute;
width: 30px;
height: 30px;
box-sizing: border-box;
border: 1px solid rgba(255, 255, 255, 0.2);
}
.I { background-color: cyan; }
.O { background-color: yellow; }
.T { background-color: purple; }
.S { background-color: green; }
.Z { background-color: red; }
.J { background-color: blue; }
.L { background-color: orange; }
.game-over {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.8);
color: white;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 24px;
display: none;
}
button {
background-color: #4CAF50;
border: none;
color: white;
padding: 10px 20px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 10px 2px;
cursor: pointer;
border-radius: 5px;
}
</style>
</head>
<body>
<div class="game-container">
<div class="game-board" id="game-board">
<div class="game-over" id="game-over">
<div>游戏结束</div>
<button id="restart-btn">重新开始</button>
</div>
</div>
<div class="info-panel">
<div class="next-piece" id="next-piece"></div>
<div class="score-panel">
<h3>分数</h3>
<div id="score">0</div>
<h3>等级</h3>
<div id="level">1</div>
<h3>行数</h3>
<div id="lines">0</div>
</div>
<div class="controls">
<h3>操作说明</h3>
<p>← → : 左右移动</p>
<p>↑ : 旋转</p>
<p>↓ : 加速下落</p>
<p>空格 : 直接落下</p>
<p>P : 暂停/继续</p>
</div>
<button id="start-btn">开始游戏</button>
</div>
</div>
<script>
// 游戏常量
const COLS = 10;
const ROWS = 20;
const BLOCK_SIZE = 30;
const EMPTY = 0;
// 方块形状定义
const SHAPES = {
I: [
[0, 0, 0, 0],
[1, 1, 1, 1],
[0, 0, 0, 0],
[0, 0, 0, 0]
],
O: [
[1, 1],
[1, 1]
],
T: [
[0, 1, 0],
[1, 1, 1],
[0, 0, 0]
],
S: [
[0, 1, 1],
[1, 1, 0],
[0, 0, 0]
],
Z: [
[1, 1, 0],
[0, 1, 1],
[0, 0, 0]
],
J: [
[1, 0, 0],
[1, 1, 1],
[0, 0, 0]
],
L: [
[0, 0, 1],
[1, 1, 1],
[0, 0, 0]
]
};
// 游戏状态
let board = [];
let currentPiece = null;
let nextPiece = null;
let score = 0;
let level = 1;
let lines = 0;
let gameInterval = null;
let isPaused = false;
let isGameOver = false;
// DOM 元素
const gameBoard = document.getElementById('game-board');
const nextPieceDisplay = document.getElementById('next-piece');
const scoreDisplay = document.getElementById('score');
const levelDisplay = document.getElementById('level');
const linesDisplay = document.getElementById('lines');
const startBtn = document.getElementById('start-btn');
const restartBtn = document.getElementById('restart-btn');
const gameOverDisplay = document.getElementById('game-over');
// 初始化游戏板
function initBoard() {
board = Array.from({ length: ROWS }, () => Array(COLS).fill(EMPTY));
}
// 随机生成方块
function getRandomPiece() {
const shapes = Object.keys(SHAPES);
const randomShape = shapes[Math.floor(Math.random() * shapes.length)];
return {
shape: randomShape,
matrix: SHAPES[randomShape],
x: Math.floor((COLS - SHAPES[randomShape][0].length) / 2),
y: 0
};
}
// 绘制游戏板
function drawBoard() {
// 清空游戏板
while (gameBoard.firstChild) {
if (gameBoard.lastChild === gameOverDisplay) {
break;
}
gameBoard.removeChild(gameBoard.lastChild);
}
// 绘制已固定的方块
for (let y = 0; y < ROWS; y++) {
for (let x = 0; x < COLS; x++) {
if (board[y][x] !== EMPTY) {
const block = document.createElement('div');
block.className = `block ${board[y][x]}`;
block.style.left = `${x * BLOCK_SIZE}px`;
block.style.top = `${y * BLOCK_SIZE}px`;
gameBoard.appendChild(block);
}
}
}
// 绘制当前方块
if (currentPiece) {
const { matrix, x, y, shape } = currentPiece;
for (let row = 0; row < matrix.length; row++) {
for (let col = 0; col < matrix[row].length; col++) {
if (matrix[row][col]) {
const block = document.createElement('div');
block.className = `block ${shape}`;
block.style.left = `${(x + col) * BLOCK_SIZE}px`;
block.style.top = `${(y + row) * BLOCK_SIZE}px`;
gameBoard.appendChild(block);
}
}
}
}
}
// 绘制下一个方块
function drawNextPiece() {
// 清空下一个方块显示区域
while (nextPieceDisplay.firstChild) {
nextPieceDisplay.removeChild(nextPieceDisplay.lastChild);
}
if (nextPiece) {
const { matrix, shape } = nextPiece;
const offsetX = (150 - matrix[0].length * BLOCK_SIZE) / 2;
const offsetY = (150 - matrix.length * BLOCK_SIZE) / 2;
for (let row = 0; row < matrix.length; row++) {
for (let col = 0; col < matrix[row].length; col++) {
if (matrix[row][col]) {
const block = document.createElement('div');
block.className = `block ${shape}`;
block.style.left = `${offsetX + col * BLOCK_SIZE}px`;
block.style.top = `${offsetY + row * BLOCK_SIZE}px`;
nextPieceDisplay.appendChild(block);
}
}
}
}
}
// 检查碰撞
function isCollision(matrix, x, y) {
for (let row = 0; row < matrix.length; row++) {
for (let col = 0; col < matrix[row].length; col++) {
if (matrix[row][col] !== 0) {
const newX = x + col;
const newY = y + row;
// 检查边界
if (newX < 0 || newX >= COLS || newY >= ROWS) {
return true;
}
// 检查已有方块
if (newY >= 0 && board[newY][newX] !== EMPTY) {
return true;
}
}
}
}
return false;
}
// 旋转矩阵
function rotateMatrix(matrix) {
const N = matrix.length;
const result = Array.from({ length: N }, () => Array(N).fill(0));
for (let row = 0; row < N; row++) {
for (let col = 0; col < N; col++) {
result[col][N - 1 - row] = matrix[row][col];
}
}
return result;
}
// 移动方块
function movePiece(dx, dy) {
if (!currentPiece || isPaused || isGameOver) return false;
const newX = currentPiece.x + dx;
const newY = currentPiece.y + dy;
if (!isCollision(currentPiece.matrix, newX, newY)) {
currentPiece.x = newX;
currentPiece.y = newY;
drawBoard();
return true;
}
// 如果是向下移动且发生碰撞,则固定方块
if (dy > 0) {
lockPiece();
return false;
}
return false;
}
// 旋转方块
function rotatePiece() {
if (!currentPiece || isPaused || isGameOver) return;
const rotated = rotateMatrix(currentPiece.matrix);
if (!isCollision(rotated, currentPiece.x, currentPiece.y)) {
currentPiece.matrix = rotated;
drawBoard();
} else {
// 尝试墙踢(Wall Kick)
// 向左尝试
if (!isCollision(rotated, currentPiece.x - 1, currentPiece.y)) {
currentPiece.matrix = rotated;
currentPiece.x -= 1;
drawBoard();
}
// 向右尝试
else if (!isCollision(rotated, currentPiece.x + 1, currentPiece.y)) {
currentPiece.matrix = rotated;
currentPiece.x += 1;
drawBoard();
}
// 向上尝试(I型方块特殊处理)
else if (currentPiece.shape === 'I' && !isCollision(rotated, currentPiece.x, currentPiece.y - 1)) {
currentPiece.matrix = rotated;
currentPiece.y -= 1;
drawBoard();
}
}
}
// 固定方块到游戏板
function lockPiece() {
const { matrix, x, y, shape } = currentPiece;
for (let row = 0; row < matrix.length; row++) {
for (let col = 0; col < matrix[row].length; col++) {
if (matrix[row][col]) {
const boardY = y + row;
const boardX = x + col;
// 游戏结束检查
if (boardY < 0) {
gameOver();
return;
}
board[boardY][boardX] = shape;
}
}
}
// 检查并清除完整的行
clearLines();
// 生成新方块
currentPiece = nextPiece;
nextPiece = getRandomPiece();
drawNextPiece();
// 检查新方块是否可以放置
if (isCollision(currentPiece.matrix, currentPiece.x, currentPiece.y)) {
gameOver();
}
drawBoard();
}
// 清除完整的行
function clearLines() {
let linesCleared = 0;
for (let y = ROWS - 1; y >= 0; y--) {
if (board[y].every(cell => cell !== EMPTY)) {
// 移除该行
board.splice(y, 1);
// 在顶部添加新行
board.unshift(Array(COLS).fill(EMPTY));
linesCleared++;
y++; // 重新检查当前行(现在是新行)
}
}
if (linesCleared > 0) {
// 更新分数
const linePoints = [0, 40, 100, 300, 1200]; // 0, 1, 2, 3, 4 行的分数
score += linePoints[linesCleared] * level;
lines += linesCleared;
level = Math.floor(lines / 10) + 1;
// 更新显示
scoreDisplay.textContent = score;
levelDisplay.textContent = level;
linesDisplay.textContent = lines;
// 调整游戏速度
updateGameSpeed();
}
}
// 更新游戏速度
function updateGameSpeed() {
if (gameInterval) {
clearInterval(gameInterval);
}
const speed = Math.max(100, 1000 - (level - 1) * 100); // 最快100ms一次
gameInterval = setInterval(gameLoop, speed);
}
// 硬降(直接落下)
function hardDrop() {
if (!currentPiece || isPaused || isGameOver) return;
while (movePiece(0, 1)) {
// 继续下落直到不能移动
}
}
// 游戏主循环
function gameLoop() {
if (isPaused || isGameOver) return;
movePiece(0, 1);
}
// 游戏结束
function gameOver() {
isGameOver = true;
clearInterval(gameInterval);
gameOverDisplay.style.display = 'flex';
}
// 开始新游戏
function startGame() {
// 重置游戏状态
initBoard();
score = 0;
level = 1;
lines = 0;
isPaused = false;
isGameOver = false;
// 更新显示
scoreDisplay.textContent = score;
levelDisplay.textContent = level;
linesDisplay.textContent = lines;
gameOverDisplay.style.display = 'none';
// 生成初始方块
currentPiece = getRandomPiece();
nextPiece = getRandomPiece();
// 绘制游戏
drawBoard();
drawNextPiece();
// 设置游戏循环
if (gameInterval) {
clearInterval(gameInterval);
}
gameInterval = setInterval(gameLoop, 1000);
}
// 暂停/继续游戏
function togglePause() {
if (isGameOver) return;
isPaused = !isPaused;
if (isPaused) {
clearInterval(gameInterval);
} else {
updateGameSpeed();
}
}
// 键盘控制
document.addEventListener('keydown', (e) => {
switch (e.key) {
case 'ArrowLeft':
movePiece(-1, 0);
break;
case 'ArrowRight':
movePiece(1, 0);
break;
case 'ArrowDown':
movePiece(0, 1);
break;
case 'ArrowUp':
rotatePiece();
break;
case ' ':
hardDrop();
break;
case 'p':
case 'P':
togglePause();
break;
}
});
// 按钮事件
startBtn.addEventListener('click', startGame);
restartBtn.addEventListener('click', startGame);
// 初始化游戏板
initBoard();
drawBoard();
</script>
</body>
</html>