〇、前言
前文已经介绍了关于 AI Coding 的相关概念,详见:I Coding 中的概念 Vibe Coding 和 Spec Coding 简介。
那么本文将通过 Trae 工具,简单实践一下,通过 AI 来实现一个简单的“贪吃蛇”游戏。
最终生成一个 HTML 文件,直接在浏览器中打开即可查看效果。
一、Trae 简介
Trae(发音 /treɪ/)是字节跳动于 2025 年 1 月正式推出的 AI 原生集成开发环境(AI IDE),是国内首款 AI 原生 IDE。
与传统的“IDE+AI 插件”组合不同,Trae 从底层架构上就将 AI 能力深度集成,实现了真正意义上的“AI主导开发”。
它同时涵盖了 Vibe Coding 和 Spec Coding,并根据其核心功能模式(SOLO/Builder)有所侧重,是目前“Agentic Coding(智能体编程)”的典型代表。
| 优势 | 说明 |
|---|---|
| ✅ AI原生架构 | 深度集成AI,比AI插件更流畅准确 |
| ✅ 免费使用 | 基础功能完全免费 |
| ✅ 中文友好 | 原生中文界面,适合国内开发者 |
| ✅ 多模型选择 | 支持主流大语言模型 |
| ✅ 全流程AI开发 | SOLO模式实现AI主导开发 |
| ✅ 基于VS Code | 熟悉的操作体验,迁移成本低 |
Trae以“自主智能体(Agent)”为核心定位,提供三种工作模式:
| 特性 | Chat 模式 | Builder 模式 | Solo 模式 |
|---|---|---|---|
| 角色比喻 | 结对编程搭档 (Copilot) | 项目构建专家 (Architect) | 独立全栈工程师 (Agent) |
| 主导权 | 人主导,AI 辅助 | 人机协作,AI 执行构建 | AI 主导,人审核/指挥 |
| 操作粒度 | 代码片段、单文件 | 功能模块、完整项目骨架 | 完整应用生命周期 (需求->部署) |
| 自动化程度 | 低 (需手动应用代码) | 中 (自动创建文件/运行) | 高 (自动规划/编码/测试/修复) |
| 上下文感知 | 当前文件或选中代码 | 项目整体结构 | 全局深度上下文 + 历史迭代记忆 |
| 典型场景 | 查错、解释代码、写函数 | 快速启动新项目、写 Demo | 复杂功能迭代、全案开发、遗留系统重构 |
| 交互频率 | 高频互动 (一问一答) | 中频互动 (需求->结果) | 低频互动 (目标->计划->验收) |
如何选择?
- 如果你正在修一个具体的 Bug,或者不理解某段代码,请用 Chat 模式。
- 如果你想快速做一个新功能的 Demo,或者从头搭建一个项目的初始结构,请用 Builder 模式。
- 如果你有一个复杂的业务需求(例如“把这个旧项目重构为微服务架构”或“给现有系统增加完整的支付流程”),并且希望 AI 能自己处理中间的繁琐步骤,请毫不犹豫地使用 Solo 模式。
计费模式:
| 套餐 | 月费 | 代码补全额度 | SOLO模式 | 适用人群 |
|---|---|---|---|---|
| Free | $0 | 5000次/月 | ❌ | 轻度用户、尝鲜体验 |
| Lite | $3 | 无限次 | ❌ | 日常开发 |
| Pro | $10 | 无限次 | ✅ | 重度AI依赖 |
| Pro+ | $30 | 无限次 | ✅ | 企业级用户 |
| Ultra | $100 | 无限次 | ✅(新模型抢先体验) | 大型团队 |
下载 SOLO 版(适合想试试 Trae 的 AI 能力):https://www.trae.cn/solo。
下载标准版:https://www.trae.cn/ide/download。

二、通过 Trae 来简单实现个纯前端的游戏“贪吃蛇”
2.1 使用 Trae 如何实现贪吃蛇游戏?
为了通过 Trae Solo(或类似的 AI 编程助手)生成一个高质量、可运行的贪吃蛇游戏,提示词(Prompt)需要具体、结构化,并明确技术栈、功能细节和交互方式。
如下一个详细的示例描述:
| # 角色设定 |
| 你是一位精通前端开发和游戏设计的资深工程师。请使用 HTML5 + CSS3 + 原生 JavaScript 创建一个完整、单文件的贪吃蛇游戏。 |
| # 核心需求 |
| 请生成一个名为 `snake_game.html` 的单文件代码,包含所有必要的 HTML 结构、CSS 样式和 JS 逻辑。 |
| # 详细功能规格 |
| ## 1. 游戏界面 (UI/UX) |
| - 画布风格:使用 Canvas 绘制,背景色为深灰色 (#222),网格线隐约可见或无网格线。 |
| - 蛇的设计:蛇头颜色 distinct (如亮绿色),蛇身颜色稍浅,呈圆角矩形。 |
| - 食物设计:红色圆形或方形,随机出现在非蛇身位置。 |
| - 计分板:在画布上方显示“当前得分”和“最高分”(使用 LocalStorage 持久化存储最高分)。 |
| - 状态提示: |
| - 开始前:显示“按任意方向键开始”或“点击开始按钮”。 |
| - 游戏结束:显示半透明遮罩层,显示“游戏结束”,最终得分,以及“重新开始”按钮。 |
| ## 2. 游戏逻辑 |
| - 移动机制:蛇每秒移动一格(初始速度),随着得分增加,速度逐渐加快(每吃 5 个食物速度提升一级)。 |
| - 控制方式: |
| - 支持键盘方向键 (↑, ↓, ←, →) 或 WASD 控制。 |
| - 防反向逻辑:如果蛇正在向右移动,按下“左”键无效,防止直接掉头自杀。 |
| - 碰撞检测: |
| - 撞墙:游戏结束。 |
| - 撞自己:游戏结束。 |
| - 吃食物:蛇身变长,分数 +10,生成新食物。 |
| - 边界处理:采用“撞墙即死”模式(不要穿墙)。 |
| ## 3. 代码质量要求 |
| - 结构清晰:将逻辑分为 `init()`, `gameLoop()`, `update()`, `draw()`, `handleInput()` 等函数。 |
| - 注释完整:关键逻辑处添加中文注释。 |
| - 无外部依赖:不需要安装 Node.js 或任何库,保存为 `.html` 文件后直接用浏览器打开即可运行。 |
| - 响应式:画布大小适中(例如 400x400 或 600x400),在页面中居中显示。 |
| # 输出格式 |
| 请直接提供完整的代码块,不要省略任何部分。代码结束后,简要说明如何运行以及如何扩展功能(如添加音效或障碍物)。 |
执行的过程:
| SOLO Coder: |
| 我将创建一个完整的贪吃蛇游戏,包含所有必要的HTML结构、CSS样式和JavaScript逻辑。首先创建snake_game.html文件。 |
| snake_game.html +361 -0 |
| 我已经成功创建了贪吃蛇游戏的完整代码,保存在 snake_game.html 文件中。以下是游戏的运行方式和扩展建议: |
| ## 如何运行 |
| 1. 直接在浏览器中打开 snake_game.html 文件即可开始游戏 |
| 2. 按任意方向键或 WASD 键开始游戏 |
| 3. 使用方向键或 WASD 控制蛇的移动方向 |
| 4. 游戏结束后,点击"重新开始"按钮可以再次开始游戏 |
| ## 游戏功能说明 |
| - 蛇头使用亮绿色,蛇身使用稍浅的绿色,呈圆角矩形 |
| - 食物为红色圆形,随机生成在非蛇身位置 |
| - 每吃一个食物得 10 分,最高分通过 LocalStorage 持久化存储 |
| - 每吃 5 个食物,游戏速度提升一级 |
| - 支持键盘方向键和 WASD 控制 |
| - 包含防反向逻辑,防止蛇直接掉头自杀 |
| - 采用"撞墙即死"模式 |
| ## 扩展功能建议 |
| 1. 添加音效 : |
| - 吃食物时的音效 |
| - 游戏结束时的音效 |
| - 背景音乐 |
| 2. 添加障碍物 : |
| - 随机生成障碍物 |
| - 随着游戏进度增加障碍物数量 |
| 3. 增加游戏难度级别 : |
| - 简单、中等、困难模式 |
| - 不同模式下初始速度和加速度不同 |
| 4. 添加视觉效果 : |
| - 蛇移动时的动画效果 |
| - 食物出现时的闪烁效果 |
| - 游戏结束时的爆炸效果 |
| 5. 添加暂停功能 : |
| - 按空格键暂停游戏 |
| - 暂停时显示暂停界面 |
| 6. 实现多人模式 : |
| - 分屏双人游戏 |
| - 网络对战功能 |
| 游戏已经完全按照要求实现,代码结构清晰,注释完整,无需任何外部依赖,直接在浏览器中打开即可运行。 |
| 产物汇总 |
| 1个文件已更改 +361 -0 |
直接用浏览器打开所生成的 HTML 文件,查看效果:


下边贴一下所生成的代码详情(可以直接复制到本地,然后通过浏览器打开查看效果):
snake_game.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 { |
| margin: 0; |
| padding: 0; |
| font-family: Arial, sans-serif; |
| background-color: #111; |
| display: flex; |
| flex-direction: column; |
| align-items: center; |
| justify-content: center; |
| min-height: 100vh; |
| color: #fff; |
| } |
| .game-container { |
| text-align: center; |
| } |
| .score-board { |
| display: flex; |
| justify-content: space-between; |
| width: 400px; |
| margin-bottom: 10px; |
| font-size: 18px; |
| } |
| canvas { |
| background-color: #222; |
| border-radius: 5px; |
| box-shadow: 0 0 20px rgba(0, 255, 0, 0.3); |
| } |
| .game-over-overlay { |
| position: absolute; |
| top: 50%; |
| left: 50%; |
| transform: translate(-50%, -50%); |
| background-color: rgba(0, 0, 0, 0.8); |
| padding: 30px; |
| border-radius: 10px; |
| text-align: center; |
| box-shadow: 0 0 30px rgba(255, 0, 0, 0.5); |
| } |
| .game-over-overlay h2 { |
| margin-top: 0; |
| color: #ff4444; |
| } |
| .game-over-overlay p { |
| font-size: 18px; |
| margin: 10px 0; |
| } |
| .btn { |
| background-color: #4CAF50; |
| color: white; |
| border: none; |
| padding: 10px 20px; |
| font-size: 16px; |
| border-radius: 5px; |
| cursor: pointer; |
| margin-top: 20px; |
| transition: background-color 0.3s; |
| } |
| .btn:hover { |
| background-color: #45a049; |
| } |
| .start-message { |
| position: absolute; |
| top: 50%; |
| left: 50%; |
| transform: translate(-50%, -50%); |
| background-color: rgba(0, 0, 0, 0.7); |
| padding: 20px; |
| border-radius: 10px; |
| text-align: center; |
| } |
| </style> |
| </head> |
| <body> |
| <div class="game-container"> |
| <div class="score-board"> |
| <div>当前得分: <span id="current-score">0</span></div> |
| <div>最高分: <span id="high-score">0</span></div> |
| </div> |
| <canvas id="gameCanvas" width="400" height="400"></canvas> |
| <div class="start-message" id="startMessage"> |
| <h2>贪吃蛇游戏</h2> |
| <p>按任意方向键开始</p> |
| </div> |
| <div class="game-over-overlay" id="gameOverOverlay" style="display: none;"> |
| <h2>游戏结束</h2> |
| <p>最终得分: <span id="final-score">0</span></p> |
| <button class="btn" id="restartBtn">重新开始</button> |
| </div> |
| </div> |
| <script> |
| // 游戏变量 |
| const canvas = document.getElementById('gameCanvas'); |
| const ctx = canvas.getContext('2d'); |
| const currentScoreEl = document.getElementById('current-score'); |
| const highScoreEl = document.getElementById('high-score'); |
| const finalScoreEl = document.getElementById('final-score'); |
| const startMessage = document.getElementById('startMessage'); |
| const gameOverOverlay = document.getElementById('gameOverOverlay'); |
| const restartBtn = document.getElementById('restartBtn'); |
| // 游戏配置 |
| const gridSize = 20; |
| const tileCount = canvas.width / gridSize; |
| // 蛇的初始状态 |
| let snake = [ |
| { x: 10, y: 10 }, |
| { x: 9, y: 10 }, |
| { x: 8, y: 10 } |
| ]; |
| // 蛇的方向 |
| let direction = 'right'; |
| let nextDirection = 'right'; |
| // 食物位置 |
| let food = generateFood(); |
| // 游戏状态 |
| let score = 0; |
| let highScore = localStorage.getItem('snakeHighScore') || 0; |
| let gameSpeed = 10; |
| let gameLoopId; |
| let gameStarted = false; |
| // 初始化游戏 |
| function init() { |
| // 重置游戏状态 |
| snake = [ |
| { x: 10, y: 10 }, |
| { x: 9, y: 10 }, |
| { x: 8, y: 10 } |
| ]; |
| direction = 'right'; |
| nextDirection = 'right'; |
| food = generateFood(); |
| score = 0; |
| gameSpeed = 10; |
| gameStarted = false; |
| // 更新UI |
| currentScoreEl.textContent = score; |
| highScoreEl.textContent = highScore; |
| startMessage.style.display = 'block'; |
| gameOverOverlay.style.display = 'none'; |
| // 清除之前的游戏循环 |
| if (gameLoopId) { |
| clearInterval(gameLoopId); |
| } |
| // 绘制初始状态 |
| draw(); |
| } |
| // 游戏主循环 |
| function gameLoop() { |
| update(); |
| draw(); |
| } |
| // 更新游戏状态 |
| function update() { |
| // 更新方向 |
| direction = nextDirection; |
| // 移动蛇头 |
| const head = { ...snake[0] }; |
| switch (direction) { |
| case 'up': |
| head.y--; |
| break; |
| case 'down': |
| head.y++; |
| break; |
| case 'left': |
| head.x--; |
| break; |
| case 'right': |
| head.x++; |
| break; |
| } |
| // 将新头添加到蛇身 |
| snake.unshift(head); |
| // 检测是否吃到食物 |
| if (head.x === food.x && head.y === food.y) { |
| // 增加分数 |
| score += 10; |
| currentScoreEl.textContent = score; |
| // 检查是否更新最高分 |
| if (score > highScore) { |
| highScore = score; |
| highScoreEl.textContent = highScore; |
| localStorage.setItem('snakeHighScore', highScore); |
| } |
| // 生成新食物 |
| food = generateFood(); |
| // 每吃5个食物提升速度 |
| if (score % 50 === 0) { |
| gameSpeed++; |
| clearInterval(gameLoopId); |
| gameLoopId = setInterval(gameLoop, 1000 / gameSpeed); |
| } |
| } else { |
| // 移除蛇尾 |
| snake.pop(); |
| } |
| // 检测碰撞 |
| if (checkCollision()) { |
| gameOver(); |
| } |
| } |
| // 绘制游戏 |
| function draw() { |
| // 清空画布 |
| ctx.clearRect(0, 0, canvas.width, canvas.height); |
| // 绘制蛇 |
| snake.forEach((segment, index) => { |
| // 蛇头颜色亮绿色,蛇身颜色稍浅 |
| if (index === 0) { |
| ctx.fillStyle = '#4CAF50'; |
| } else { |
| ctx.fillStyle = '#45a049'; |
| } |
| // 绘制圆角矩形 |
| ctx.beginPath(); |
| ctx.roundRect(segment.x * gridSize, segment.y * gridSize, gridSize, gridSize, 5); |
| ctx.fill(); |
| }); |
| // 绘制食物(红色圆形) |
| ctx.fillStyle = '#ff4444'; |
| ctx.beginPath(); |
| ctx.arc(food.x * gridSize + gridSize / 2, food.y * gridSize + gridSize / 2, gridSize / 2, 0, Math.PI * 2); |
| ctx.fill(); |
| } |
| // 处理输入 |
| function handleInput(e) { |
| if (!gameStarted) { |
| gameStarted = true; |
| startMessage.style.display = 'none'; |
| gameLoopId = setInterval(gameLoop, 1000 / gameSpeed); |
| } |
| const key = e.key; |
| switch (key) { |
| case 'ArrowUp': |
| case 'w': |
| case 'W': |
| if (direction !== 'down') { |
| nextDirection = 'up'; |
| } |
| break; |
| case 'ArrowDown': |
| case 's': |
| case 'S': |
| if (direction !== 'up') { |
| nextDirection = 'down'; |
| } |
| break; |
| case 'ArrowLeft': |
| case 'a': |
| case 'A': |
| if (direction !== 'right') { |
| nextDirection = 'left'; |
| } |
| break; |
| case 'ArrowRight': |
| case 'd': |
| case 'D': |
| if (direction !== 'left') { |
| nextDirection = 'right'; |
| } |
| break; |
| } |
| } |
| // 生成食物 |
| function generateFood() { |
| let foodX, foodY; |
| let collision; |
| do { |
| collision = false; |
| foodX = Math.floor(Math.random() * tileCount); |
| foodY = Math.floor(Math.random() * tileCount); |
| // 检查食物是否生成在蛇身上 |
| for (const segment of snake) { |
| if (segment.x === foodX && segment.y === foodY) { |
| collision = true; |
| break; |
| } |
| } |
| } while (collision); |
| return { x: foodX, y: foodY }; |
| } |
| // 检测碰撞 |
| function checkCollision() { |
| const head = snake[0]; |
| // 检测撞墙 |
| if (head.x < 0 || head.x >= tileCount || head.y < 0 || head.y >= tileCount) { |
| return true; |
| } |
| // 检测撞自己 |
| for (let i = 1; i < snake.length; i++) { |
| if (head.x === snake[i].x && head.y === snake[i].y) { |
| return true; |
| } |
| } |
| return false; |
| } |
| // 游戏结束 |
| function gameOver() { |
| clearInterval(gameLoopId); |
| gameOverOverlay.style.display = 'block'; |
| finalScoreEl.textContent = score; |
| } |
| // 事件监听 |
| document.addEventListener('keydown', handleInput); |
| restartBtn.addEventListener('click', init); |
| // 初始化游戏 |
| init(); |
| </script> |
| </body> |
| </html> |
2.2 为什么要详细描述自己的需求?
例如在上一章节中的对于“贪吃蛇”的需求描述,内容很长,包含了大量的需求详细信息,下面分析下为什么。
- 明确技术栈(HTML/CSS/JS)
说明目标技术栈,来避免 AI 生成其他不具备开发环境的代码,例如 Python、C++ 等等。
单文件 HTML 是最容易验证和分享的格式。
- 细化视觉反馈
通过指定颜色、形状和 UI 状态(开始/结束遮罩),避免生成只有黑白方块的简陋版本。
使自己的需求被 AI 充分的理解,避免重复调整,浪费资源和时间。
- 定义边缘情况(Edge Cases)
特别提到“防反向逻辑”(不能直接掉头)和“速度递增”,这是贪吃蛇体验好坏的关键细节。
提到 LocalStorage 保存最高分,增加了游戏的可玩性。
定义了游戏规则和游戏分数记录,使功能稳定和完善。
- 结构化输出
要求代码分函数模块,方便你后续阅读和修改。
如果想要更高级的功能,可以在提示词的“详细功能规格”中追加,例如,添加障碍物、特殊道具、移动端支持、音效等等。
本文来自博客园,作者: