用trae完全自动化开发一款网页版的俄罗斯方块游戏
阅读原文
建议阅读原文,始终查看最新文档版本,获得最佳阅读体验:《用trae完全自动化开发一款网页版的俄罗斯方块游戏》
deepseek-R1-0528已经上传到Huggingface
参考资料:deepseek-ai/DeepSeek-R1-0528 · Hugging Face
2025年5月28日deepseek对deepseek R1模型进行了小幅度更新,据说编程性能大幅提升,甚至能媲美claude 4,我马上就想要测试一下。想着利用deepseek-R1-0528开发一个俄罗斯方块游戏。
可以看到,模型参数是6850亿,但当前还没有详细的模型描述
通过api询问当前聊天模型是否是最新的deepseek R1-0528版本的
curl --request POST \
-H "Content-Type: application/json" \
--header 'Authorization: Bearer <此处替换为你的deepseek API KEY>' \
--url https://api.deepseek.com/chat/completions \
--data '{"messages":[{"role":"user","content":"请问你是deepseek最新发布的DeepSeek R1-0528大模型吗?2025年5月28日发布的"}],"model":"deepseek-reasoner"}' | jq .
输出表明,通过api调用,仍然还是旧版本的deepseek R1(2025年5月29日14点测试的)
如果直接在网页端询问,给出的回答是最新版本的R1
让trae自动开发游戏
使用自定义大模型
我使用的是自定义的大模型,因为我本来以为通过api调用是可以用上最新版本的deepseek R1的。
提示词
提示词非常简单,就一句话“开发一款网页版的俄罗斯方块游戏”
一开始生成的代码只能利用方向键移动方块,我希望除了这种方式,还能利用WASD键操作方块,更加符合人类的习惯。
生成的代码
代码也不多,只有三个文件
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>网页版俄罗斯方块</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="game-container">
<h1>俄罗斯方块</h1>
<div class="game-info">
<div>分数: <span id="score">0</span></div>
<div>等级: <span id="level">1</span></div>
<div>下一块:</div>
<canvas id="next-piece" width="100" height="100"></canvas>
</div>
<canvas id="game-board" width="300" height="600"></canvas>
<div class="controls">
<button id="start-btn">开始游戏</button>
<button id="pause-btn">暂停</button>
</div>
</div>
<script src="game.js"></script>
</body>
</html>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f0f0f0;
font-family: 'Microsoft YaHei', sans-serif;
}
.game-container {
display: flex;
flex-direction: column;
align-items: center;
}
h1 {
color: #333;
margin-bottom: 20px;
}
#game-board {
border: 2px solid #333;
background-color: #111;
}
.game-info {
margin-bottom: 15px;
text-align: center;
font-size: 18px;
}
.controls {
margin-top: 15px;
}
button {
padding: 10px 20px;
margin: 0 5px;
font-size: 16px;
cursor: pointer;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
}
button:hover {
background-color: #45a049;
}
#next-piece {
display: block;
margin: 10px auto;
background-color: #222;
}
// 游戏常量
const COLS = 10;
const ROWS = 20;
const BLOCK_SIZE = 30;
const COLORS = [
null,
'#FF0D72', // I
'#0DC2FF', // J
'#0DFF72', // L
'#F538FF', // O
'#FF8E0D', // S
'#FFE138', // T
'#3877FF' // Z
];
// 方块形状定义
const SHAPES = [
[],
[[0,0,0,0], [1,1,1,1], [0,0,0,0], [0,0,0,0]], // I
[[0,0,0], [1,0,0], [1,1,1], [0,0,0]], // J
[[0,0,0], [0,0,1], [1,1,1], [0,0,0]], // L
[[0,0,0,0], [0,1,1,0], [0,1,1,0], [0,0,0,0]], // O
[[0,0,0], [0,1,1], [1,1,0], [0,0,0]], // S
[[0,0,0], [0,1,0], [1,1,1], [0,0,0]], // T
[[0,0,0], [1,1,0], [0,1,1], [0,0,0]] // Z
];
// 游戏状态
let board = createBoard();
let score = 0;
let level = 1;
let gameOver = false;
let dropInterval = 1000; // 初始下落速度(毫秒)
let dropStart = Date.now();
let requestId = null;
// DOM元素
const canvas = document.getElementById('game-board');
const nextCanvas = document.getElementById('next-piece');
const ctx = canvas.getContext('2d');
const nextCtx = nextCanvas.getContext('2d');
const scoreElement = document.getElementById('score');
const levelElement = document.getElementById('level');
const startBtn = document.getElementById('start-btn');
const pauseBtn = document.getElementById('pause-btn');
// 初始化游戏板
function createBoard() {
return Array.from(Array(ROWS), () => Array(COLS).fill(0));
}
// 当前方块
let piece = {
pos: {x: 0, y: 0},
matrix: null,
type: null
};
// 下一个方块
let nextPiece = {
matrix: null,
type: null
};
// 绘制单个方块
function drawBlock(ctx, x, y, type) {
ctx.fillStyle = COLORS[type];
ctx.fillRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
ctx.strokeStyle = '#000';
ctx.lineWidth = 1;
ctx.strokeRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
}
// 绘制游戏板
function drawBoard() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 绘制已落下的方块
board.forEach((row, y) => {
row.forEach((value, x) => {
if (value !== 0) {
drawBlock(ctx, x, y, value);
}
});
});
// 绘制当前方块
if (piece.matrix) {
piece.matrix.forEach((row, y) => {
row.forEach((value, x) => {
if (value !== 0) {
drawBlock(ctx, x + piece.pos.x, y + piece.pos.y, piece.type);
}
});
});
}
}
// 绘制下一个方块预览
function drawNextPiece() {
nextCtx.clearRect(0, 0, nextCanvas.width, nextCanvas.height);
if (nextPiece.matrix) {
nextPiece.matrix.forEach((row, y) => {
row.forEach((value, x) => {
if (value !== 0) {
nextCtx.fillStyle = COLORS[nextPiece.type];
nextCtx.fillRect(x * 20, y * 20, 20, 20);
nextCtx.strokeStyle = '#000';
nextCtx.lineWidth = 1;
nextCtx.strokeRect(x * 20, y * 20, 20, 20);
}
});
});
}
}
// 碰撞检测
function collide(board, piece) {
const [m, o] = [piece.matrix, piece.pos];
for (let y = 0; y < m.length; y++) {
for (let x = 0; x < m[y].length; x++) {
if (m[y][x] !== 0 &&
(board[y + o.y] &&
board[y + o.y][x + o.x]) !== 0) {
return true;
}
}
}
return false;
}
// 旋转方块 - 修复非方阵旋转问题
function rotate(matrix) {
const rows = matrix.length;
const cols = matrix[0].length;
const rotated = Array(cols).fill().map(() => Array(rows).fill(0));
for (let y = 0; y < rows; y++) {
for (let x = 0; x < cols; x++) {
rotated[x][rows - 1 - y] = matrix[y][x];
}
}
return rotated;
}
// 合并方块到游戏板
function merge(board, piece) {
piece.matrix.forEach((row, y) => {
row.forEach((value, x) => {
if (value !== 0) {
board[y + piece.pos.y][x + piece.pos.x] = piece.type;
}
});
});
}
// 消除满行
function sweep() {
let linesCleared = 0;
outer: for (let y = ROWS - 1; y > 0; y--) {
for (let x = 0; x < COLS; x++) {
if (board[y][x] === 0) {
continue outer;
}
}
const row = board.splice(y, 1)[0].fill(0);
board.unshift(row);
linesCleared++;
y++; // 重新检查当前行
}
if (linesCleared > 0) {
// 更新分数
score += [40, 100, 300, 1200][linesCleared - 1] * level;
scoreElement.textContent = score;
// 更新等级
level = Math.floor(score / 1000) + 1;
levelElement.textContent = level;
// 加快下落速度
dropInterval = Math.max(100, 1000 - (level - 1) * 100);
}
}
// 创建新方块
function createPiece() {
const type = Math.floor(Math.random() * 7) + 1;
return {
matrix: SHAPES[type],
type: type
};
}
// 重置当前方块
function resetPiece() {
piece.matrix = nextPiece.matrix;
piece.type = nextPiece.type;
piece.pos.y = 0;
piece.pos.x = Math.floor(COLS / 2) - Math.floor(piece.matrix[0].length / 2);
nextPiece = createPiece();
drawNextPiece();
// 检查游戏结束
if (collide(board, piece)) {
gameOver = true;
cancelAnimationFrame(requestId);
alert(`游戏结束!最终得分: ${score}`);
}
}
// 方块下落
function drop() {
piece.pos.y++;
if (collide(board, piece)) {
piece.pos.y--;
merge(board, piece);
resetPiece();
sweep();
}
dropStart = Date.now();
}
// 游戏主循环
function gameLoop() {
if (gameOver) return;
const now = Date.now();
const delta = now - dropStart;
if (delta > dropInterval) {
drop();
}
drawBoard();
requestId = requestAnimationFrame(gameLoop);
}
// 初始化游戏
function init() {
board = createBoard();
score = 0;
level = 1;
gameOver = false;
dropInterval = 1000;
scoreElement.textContent = score;
levelElement.textContent = level;
nextPiece = createPiece();
resetPiece();
drawBoard();
drawNextPiece();
}
// 控制事件监听
document.addEventListener('keydown', event => {
if (gameOver || !requestId) { // 添加暂停状态检查
return;
}
switch (event.keyCode) {
case 37: // 左箭头
case 65: // A键 (新增)
piece.pos.x--;
if (collide(board, piece)) piece.pos.x++;
break;
case 39: // 右箭头
case 68: // D键 (新增)
piece.pos.x++;
if (collide(board, piece)) piece.pos.x--;
break;
case 40: // 下箭头
case 83: // S键 (新增)
drop();
break;
case 38: // 上箭头 (旋转)
case 87: // W键 (新增)
const rotated = rotate(piece.matrix);
const original = piece.matrix;
piece.matrix = rotated;
if (collide(board, piece)) piece.matrix = original;
break;
case 32: // 空格键 (硬降落)
event.preventDefault(); // 阻止空格键触发按钮点击
while (!collide(board, piece)) {
piece.pos.y++;
}
piece.pos.y--;
merge(board, piece);
resetPiece();
sweep();
break;
}
});
// 按钮事件
startBtn.addEventListener('click', () => {
if (gameOver) init();
if (requestId) cancelAnimationFrame(requestId);
gameOver = false;
gameLoop();
});
pauseBtn.addEventListener('click', () => {
if (gameOver) return;
if (requestId) {
cancelAnimationFrame(requestId);
requestId = null;
pauseBtn.textContent = '继续';
} else {
gameLoop();
pauseBtn.textContent = '暂停';
}
});
// 初始化游戏
init();
验证游戏
直接用浏览器打开index.html文件即可开始游戏
其实验证过程中,我发现了一个问题,就是如果单击了“继续”按钮后,再按空格,虽然方块确实会直接落地,但是游戏也暂停了。下面这个视频演示了这个问题
请至钉钉文档查看附件《网页版俄罗斯方块 和另外 12 个页面 - 个人 - Microsoft Edge 2025-05-29 14-55-56.mp4》
后来我让trae再调整代码,问题解决了。
请至钉钉文档查看附件《网页版俄罗斯方块 和另外 12 个页面 - 个人 - Microsoft Edge 2025-05-29 15-19-41.mp4》