Three.js与AI编程:从零实现3D Mastermind猜颜色游戏
最近在开发小游戏时发现《世界游戏大全51》中的猜颜色游戏特别有意思于是尝试用AI Coding工具复刻这个经典游戏。原来这个游戏叫Mastermind猜谜游戏是一款考验逻辑推理的益智游戏。本文将完整分享如何结合Three.js实现3D视觉效果并利用AI辅助开发的全过程。无论你是前端开发者想学习Three.js 3D开发还是对AI编程工具感兴趣这篇文章都将带你从零开始构建一个可交互的Mastermind游戏。我们将涵盖游戏规则设计、Three.js场景搭建、AI代码生成技巧以及完整的项目实现。1. Mastermind游戏背景与规则解析1.1 什么是Mastermind游戏Mastermind中文常译为猜谜游戏或密码破译是一款经典的两人棋盘游戏由Mordecai Meirowitz在1970年发明。游戏的基本规则是一方扮演编码者设置一个颜色密码另一方作为解码者尝试猜测这个密码。在数字版本中通常由计算机随机生成一个颜色序列玩家通过有限的尝试次数来猜出正确的颜色组合。每次猜测后系统会给出反馈提示告诉玩家有多少个颜色位置完全正确有多少个颜色正确但位置错误。1.2 游戏规则详解标准的Mastermind游戏使用6种颜色和4个位置但我们的实现可以灵活调整难度。核心规则包括颜色集合通常使用6种不同颜色红、蓝、绿、黄、紫、橙密码长度经典版本为4个位置可扩展至5-6位增加难度猜测次数一般限制在8-12次尝试反馈机制黑色标记颜色和位置都正确白色标记颜色正确但位置错误无标记颜色不存在于密码中例如如果密码是红蓝绿黄玩家猜测红绿蓝紫反馈将是2个黑色标记红色位置正确1个白色标记绿色和蓝色颜色正确但位置错误。1.3 为什么选择复刻这个游戏Mastermind游戏具有多个值得复刻的特点规则简单但策略性强适合各年龄段玩家逻辑清晰代码结构相对明确视觉效果丰富适合展示Three.js的3D能力算法部分可以体现AI编程的优势项目规模适中适合作为学习案例2. 技术栈选择与环境准备2.1 核心技术组件基于项目需求我们选择以下技术栈前端框架原生JavaScript HTML5避免框架依赖3D图形库Three.js r155 版本提供强大的WebGL封装AI编程辅助使用Claude Code等AI工具加速开发构建工具Vite或简单HTTP服务器用于开发调试样式设计CSS3实现响应式布局和动画效果2.2 开发环境配置首先确保你的开发环境准备就绪# 检查Node.js版本建议16.0 node --version # 创建项目目录 mkdir mastermind-game cd mastermind-game # 初始化package.json npm init -y # 安装Three.js npm install three2.3 项目结构设计合理的项目结构是成功的第一步mastermind-game/ ├── index.html # 主页面 ├── src/ │ ├── js/ │ │ ├── game.js # 游戏逻辑核心 │ │ ├── renderer.js # Three.js渲染器 │ │ └── ui.js # 用户界面控制 │ ├── css/ │ │ └── style.css # 样式文件 │ └── assets/ # 静态资源 ├── package.json └── README.md2.4 基础HTML结构创建基本的HTML文件框架!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleMastermind 猜颜色游戏/title link relstylesheet hrefsrc/css/style.css /head body div idgame-container header h1Mastermind 猜颜色游戏/h1 div idgame-info span尝试次数: span idattempts0/span/10/span button idreset-btn重新开始/button /div /header main div idgame-board/div div idcolor-palette/div /main div idresult-modal classhidden div classmodal-content h2游戏结果/h2 p idresult-message/p button idplay-again再玩一次/button /div /div /div script typemodule srcsrc/js/game.js/script /body /html3. Three.js 3D场景搭建3.1 Three.js基础概念Three.js是一个基于WebGL的3D图形库主要包含以下几个核心概念场景(Scene)3D对象的容器相当于整个3D世界相机(Camera)观察场景的视角决定能看到什么渲染器(Renderer)将3D场景渲染到2D画布上网格(Mesh)由几何体(Geometry)和材质(Material)组成的可渲染对象光源(Light)照亮场景产生明暗效果3.2 初始化Three.js环境创建基本的Three.js场景// src/js/renderer.js import * as THREE from three; class GameRenderer { constructor(containerId) { this.container document.getElementById(containerId); this.scene new THREE.Scene(); this.camera new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); this.renderer new THREE.WebGLRenderer({ antialias: true }); this.init(); } init() { // 设置渲染器 this.renderer.setSize(window.innerWidth, window.innerHeight); this.renderer.setClearColor(0xf0f0f0); this.renderer.shadowMap.enabled true; this.renderer.shadowMap.type THREE.PCFSoftShadowMap; // 添加到DOM this.container.appendChild(this.renderer.domElement); // 设置相机位置 this.camera.position.set(0, 5, 10); this.camera.lookAt(0, 0, 0); // 添加光源 this.addLights(); // 开始渲染循环 this.animate(); } addLights() { // 环境光 const ambientLight new THREE.AmbientLight(0x404040, 0.6); this.scene.add(ambientLight); // 方向光 const directionalLight new THREE.DirectionalLight(0xffffff, 0.8); directionalLight.position.set(10, 10, 5); directionalLight.castShadow true; this.scene.add(directionalLight); } animate() { requestAnimationFrame(() this.animate()); this.renderer.render(this.scene, this.camera); } // 响应窗口大小变化 onWindowResize() { this.camera.aspect window.innerWidth / window.innerHeight; this.camera.updateProjectionMatrix(); this.renderer.setSize(window.innerWidth, window.innerHeight); } } export default GameRenderer;3.3 创建游戏棋子3D模型为Mastermind游戏创建可交互的彩色棋子// src/js/gamePieces.js import * as THREE from three; class GamePieces { constructor() { this.colors [ 0xff0000, // 红色 0x0000ff, // 蓝色 0x00ff00, // 绿色 0xffff00, // 黄色 0xff00ff, // 紫色 0xffa500 // 橙色 ]; this.materials this.createMaterials(); } createMaterials() { return this.colors.map(color { return new THREE.MeshPhongMaterial({ color: color, shininess: 30, transparent: true, opacity: 0.9 }); }); } createPeg(colorIndex, position) { const geometry new THREE.CylinderGeometry(0.3, 0.3, 0.5, 32); const material this.materials[colorIndex]; const peg new THREE.Mesh(geometry, material); peg.position.set(position.x, position.y, position.z); peg.userData { colorIndex: colorIndex, isSelectable: true }; // 添加交互效果 peg.castShadow true; peg.receiveShadow true; return peg; } createBoardSlot(position) { const geometry new THREE.CylinderGeometry(0.35, 0.35, 0.1, 32); const material new THREE.MeshPhongMaterial({ color: 0x888888, transparent: true, opacity: 0.7 }); const slot new THREE.Mesh(geometry, material); slot.position.set(position.x, position.y, position.z); slot.userData { isEmpty: true }; return slot; } } export default GamePieces;4. 游戏逻辑核心实现4.1 游戏状态管理设计合理的游戏状态机是游戏开发的关键// src/js/game.js import GameRenderer from ./renderer.js; import GamePieces from ./gamePieces.js; class MastermindGame { constructor() { this.state { gameStatus: idle, // idle, playing, win, lose secretCode: [], currentAttempt: 0, maxAttempts: 10, codeLength: 4, currentGuess: [], attemptsHistory: [] }; this.renderer new GameRenderer(game-board); this.pieces new GamePieces(); this.initGame(); } initGame() { this.generateSecretCode(); this.setupEventListeners(); this.createGameBoard(); this.updateUI(); } generateSecretCode() { this.state.secretCode []; for (let i 0; i this.state.codeLength; i) { const randomColor Math.floor(Math.random() * 6); this.state.secretCode.push(randomColor); } console.log(Secret code:, this.state.secretCode); // 调试用 } createGameBoard() { // 创建游戏板网格 const boardGroup new THREE.Group(); // 创建猜测行 for (let row 0; row this.state.maxAttempts; row) { for (let col 0; col this.state.codeLength; col) { const position { x: (col - (this.state.codeLength - 1) / 2) * 1.2, y: (this.state.maxAttempts - 1 - row) * 1.2, z: 0 }; const slot this.pieces.createBoardSlot(position); boardGroup.add(slot); } } this.renderer.scene.add(boardGroup); } }4.2 颜色选择与猜测逻辑实现玩家交互和颜色选择机制// 在MastermindGame类中添加方法 setupColorPalette() { const paletteContainer document.getElementById(color-palette); paletteContainer.innerHTML ; this.pieces.colors.forEach((color, index) { const colorBtn document.createElement(button); colorBtn.className color-btn; colorBtn.style.backgroundColor #${color.toString(16).padStart(6, 0)}; colorBtn.dataset.colorIndex index; colorBtn.addEventListener(click, () { this.selectColor(index); }); paletteContainer.appendChild(colorBtn); }); } selectColor(colorIndex) { if (this.state.gameStatus ! playing) return; if (this.state.currentGuess.length this.state.codeLength) return; this.state.currentGuess.push(colorIndex); this.updateCurrentGuessDisplay(); if (this.state.currentGuess.length this.state.codeLength) { this.evaluateGuess(); } } evaluateGuess() { const guess [...this.state.currentGuess]; const secret [...this.state.secretCode]; let correctPosition 0; let correctColor 0; // 检查位置和颜色都正确的 for (let i 0; i secret.length; i) { if (guess[i] secret[i]) { correctPosition; guess[i] -1; // 标记已匹配 secret[i] -2; } } // 检查颜色正确但位置错误的 for (let i 0; i secret.length; i) { if (secret[i] 0) { const foundIndex guess.indexOf(secret[i]); if (foundIndex -1) { correctColor; guess[foundIndex] -1; } } } this.state.attemptsHistory.push({ attempt: this.state.currentAttempt, guess: [...this.state.currentGuess], feedback: { correctPosition, correctColor } }); this.updateFeedbackDisplay(correctPosition, correctColor); this.checkGameResult(correctPosition); } checkGameResult(correctPosition) { if (correctPosition this.state.codeLength) { this.endGame(win); } else if (this.state.currentAttempt this.state.maxAttempts - 1) { this.endGame(lose); } else { this.state.currentAttempt; this.state.currentGuess []; this.updateUI(); } }5. AI Coding在项目开发中的应用5.1 AI编程工具选择与配置在当前项目中我们主要使用AI编程助手来加速开发过程// AI辅助生成的工具函数示例 /** * 使用AI生成的数组洗牌算法 * param {Array} array 需要洗牌的数组 * returns {Array} 洗牌后的新数组 */ function shuffleArray(array) { const newArray [...array]; for (let i newArray.length - 1; i 0; i--) { const j Math.floor(Math.random() * (i 1)); [newArray[i], newArray[j]] [newArray[j], newArray[i]]; } return newArray; } /** * AI辅助生成的颜色转换工具 * param {number} colorValue Three.js颜色值 * returns {string} CSS颜色字符串 */ function threeColorToCSS(colorValue) { return #${colorValue.toString(16).padStart(6, 0)}; } /** * AI辅助的动画缓动函数 * param {number} t 当前时间 * param {number} b 起始值 * param {number} c变化量 * param {number} d 持续时间 * returns {number} 缓动后的值 */ function easeOutCubic(t, b, c, d) { t / d; t--; return c * (t * t * t 1) b; }5.2 AI代码优化实践利用AI工具进行代码重构和性能优化// AI优化的游戏循环管理 class GameLoopManager { constructor() { this.animations new Map(); this.lastTime 0; this.isRunning false; } addAnimation(id, updateFunction, duration, callback) { this.animations.set(id, { startTime: performance.now(), update: updateFunction, duration: duration, callback: callback, progress: 0 }); if (!this.isRunning) { this.startLoop(); } } startLoop() { this.isRunning true; this.lastTime performance.now(); this.loop(); } loop() { const currentTime performance.now(); const deltaTime currentTime - this.lastTime; this.lastTime currentTime; this.animations.forEach((animation, id) { const elapsed currentTime - animation.startTime; animation.progress Math.min(elapsed / animation.duration, 1); if (animation.update) { animation.update(animation.progress); } if (animation.progress 1) { if (animation.callback) { animation.callback(); } this.animations.delete(id); } }); if (this.animations.size 0) { requestAnimationFrame(() this.loop()); } else { this.isRunning false; } } }6. 用户界面与交互优化6.1 响应式布局设计确保游戏在不同设备上都有良好的体验/* src/css/style.css */ #game-container { max-width: 1200px; margin: 0 auto; padding: 20px; font-family: Arial, sans-serif; } #game-board { width: 100%; height: 60vh; border: 2px solid #ddd; border-radius: 8px; margin-bottom: 20px; } #color-palette { display: flex; justify-content: center; gap: 10px; margin-bottom: 20px; } .color-btn { width: 50px; height: 50px; border: 3px solid #333; border-radius: 50%; cursor: pointer; transition: transform 0.2s, border-color 0.2s; } .color-btn:hover { transform: scale(1.1); border-color: #666; } .color-btn.selected { border-color: #fff; box-shadow: 0 0 10px rgba(255, 255, 255, 0.8); } /* 移动端适配 */ media (max-width: 768px) { #game-board { height: 50vh; } .color-btn { width: 40px; height: 40px; } #game-info { flex-direction: column; gap: 10px; } } /* 动画效果 */ keyframes pegDrop { 0% { transform: translateY(-100px); opacity: 0; } 100% { transform: translateY(0); opacity: 1; } } .peg-animation { animation: pegDrop 0.5s ease-out; } /* 模态框样式 */ #result-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.7); display: flex; justify-content: center; align-items: center; z-index: 1000; } .modal-content { background: white; padding: 30px; border-radius: 10px; text-align: center; max-width: 400px; } .hidden { display: none !important; }6.2 交互动效实现增强用户体验的动画效果// 在GameRenderer类中添加动画方法 animatePegMovement(peg, fromPosition, toPosition, duration 500) { return new Promise((resolve) { const startTime performance.now(); const startPos { ...fromPosition }; const deltaX toPosition.x - fromPosition.x; const deltaY toPosition.y - fromPosition.y; const deltaZ toPosition.z - fromPosition.z; const animate (currentTime) { const elapsed currentTime - startTime; const progress Math.min(elapsed / duration, 1); // 使用缓动函数 const easedProgress this.easeOutCubic(progress, 0, 1, 1); peg.position.x startPos.x deltaX * easedProgress; peg.position.y startPos.y deltaY * easedProgress; peg.position.z startPos.z deltaZ * easedProgress; if (progress 1) { requestAnimationFrame(animate); } else { resolve(); } }; requestAnimationFrame(animate); }); } easeOutCubic(t, b, c, d) { t / d; t--; return c * (t * t * t 1) b; } // 添加棋子选择效果 highlightPeg(peg, isHighlighted) { if (isHighlighted) { peg.material.emissive new THREE.Color(0x444444); peg.scale.set(1.1, 1.1, 1.1); } else { peg.material.emissive new THREE.Color(0x000000); peg.scale.set(1, 1, 1); } }7. 游戏功能扩展与高级特性7.1 难度级别设置实现可配置的游戏难度// 扩展游戏状态管理 const DIFFICULTY_LEVELS { easy: { codeLength: 4, colors: 4, attempts: 12 }, medium: { codeLength: 4, colors: 6, attempts: 10 }, hard: { codeLength: 5, colors: 6, attempts: 8 }, expert: { codeLength: 6, colors: 8, attempts: 10 } }; setDifficulty(level) { const config DIFFICULTY_LEVELS[level]; if (!config) return; this.state.codeLength config.codeLength; this.state.maxAttempts config.attempts; this.pieces.colors this.pieces.colors.slice(0, config.colors); this.resetGame(); } createDifficultySelector() { const selector document.createElement(div); selector.className difficulty-selector; selector.innerHTML label fordifficulty难度: /label select iddifficulty option valueeasy简单4色4位/option option valuemedium selected中等6色4位/option option valuehard困难6色5位/option option valueexpert专家8色6位/option /select ; selector.querySelector(#difficulty).addEventListener(change, (e) { this.setDifficulty(e.target.value); }); document.querySelector(header).appendChild(selector); }7.2 游戏统计与进度保存添加数据持久化功能class GameStatistics { constructor() { this.storageKey mastermind_stats; this.stats this.loadStats(); } loadStats() { try { const stored localStorage.getItem(this.storageKey); return stored ? JSON.parse(stored) : this.getDefaultStats(); } catch (error) { console.warn(Failed to load statistics:, error); return this.getDefaultStats(); } } getDefaultStats() { return { gamesPlayed: 0, gamesWon: 0, currentStreak: 0, maxStreak: 0, attemptDistribution: {}, bestTimes: [] }; } recordGameResult(isWin, attempts, timeSpent) { this.stats.gamesPlayed; if (isWin) { this.stats.gamesWon; this.stats.currentStreak; this.stats.maxStreak Math.max(this.stats.maxStreak, this.stats.currentStreak); // 记录尝试次数分布 this.stats.attemptDistribution[attempts] (this.stats.attemptDistribution[attempts] || 0) 1; // 记录最佳时间 this.recordBestTime(timeSpent); } else { this.stats.currentStreak 0; } this.saveStats(); } recordBestTime(timeSpent) { this.stats.bestTimes.push({ time: timeSpent, date: new Date().toISOString() }); // 只保留前10个最佳时间 this.stats.bestTimes.sort((a, b) a.time - b.time); this.stats.bestTimes this.stats.bestTimes.slice(0, 10); } saveStats() { try { localStorage.setItem(this.storageKey, JSON.stringify(this.stats)); } catch (error) { console.warn(Failed to save statistics:, error); } } getWinPercentage() { return this.stats.gamesPlayed 0 ? (this.stats.gamesWon / this.stats.gamesPlayed * 100).toFixed(1) : 0; } }8. 性能优化与最佳实践8.1 Three.js性能优化技巧确保3D场景的流畅运行// 优化渲染性能 class OptimizedRenderer extends GameRenderer { constructor(containerId) { super(containerId); this.setupPerformanceOptimizations(); } setupPerformanceOptimizations() { // 使用更高效的渲染设置 this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); this.renderer.outputColorSpace THREE.SRGBColorSpace; // 减少重绘区域 this.renderer.info.autoReset false; // 使用实例化网格提高性能 this.setupInstancedMeshes(); } setupInstancedMeshes() { // 为大量重复的棋子使用实例化渲染 const pegGeometry new THREE.CylinderGeometry(0.3, 0.3, 0.5, 16); const materials this.pieces.materials; this.instancedPegs materials.map((material, index) { const instancedMesh new THREE.InstancedMesh(pegGeometry, material, 100); instancedMesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage); this.scene.add(instancedMesh); return instancedMesh; }); } // 使用视锥体剔除 setupFrustumCulling() { this.camera.far 50; this.camera.updateProjectionMatrix(); // 为大型对象设置边界框 this.scene.traverse((object) { if (object.isMesh) { object.geometry.computeBoundingSphere(); object.frustumCulled true; } }); } }8.2 内存管理最佳实践防止内存泄漏和性能下降// 内存管理工具类 class MemoryManager { constructor() { this.disposableObjects new Set(); } trackObject(object) { if (object typeof object.dispose function) { this.disposableObjects.add(object); } // 递归跟踪子对象 if (object.children) { object.children.forEach(child this.trackObject(child)); } } disposeObject(object) { if (!object) return; // 递归处理子对象 if (object.children) { object.children.forEach(child this.disposeObject(child)); } // 调用dispose方法 if (typeof object.dispose function) { object.dispose(); } // 从场景中移除 if (object.parent) { object.parent.remove(object); } this.disposableObjects.delete(object); } cleanup() { this.disposableObjects.forEach(obj this.disposeObject(obj)); this.disposableObjects.clear(); } // 监控内存使用 monitorMemoryUsage() { if (performance.memory) { const used performance.memory.usedJSHeapSize; const limit performance.memory.jsHeapSizeLimit; console.log(Memory usage: ${(used / 1048576).toFixed(2)}MB / ${(limit / 1048576).toFixed(2)}MB); } } }9. 常见问题与解决方案9.1 Three.js常见问题排查问题现象可能原因解决方案场景全黑看不到物体缺少光源或相机位置不当检查光源设置和相机lookAt方向物体显示为黑色材质需要光照或法向量错误使用MeshBasicMaterial测试或重新计算法向量性能卡顿帧率低物体数量过多或重绘频繁使用实例化网格开启frustumCulling物体闪烁(Z-fighting)物体距离太近或深度缓冲问题调整物体间距修改相机near/far参数9.2 游戏逻辑调试技巧// 调试工具函数 class DebugHelper { static enableDebugMode(gameInstance) { window.debugGame gameInstance; // 添加调试控制台 const debugDiv document.createElement(div); debugDiv.style.cssText position: fixed; top: 10px; right: 10px; background: rgba(0,0,0,0.8); color: white; padding: 10px; border-radius: 5px; z-index: 10000; font-family: monospace; font-size: 12px; ; debugDiv.innerHTML button onclickdebugGame.revealCode()显示答案/button button onclickdebugGame.skipToWin()直接获胜/button div iddebug-info/div ; document.body.appendChild(debugDiv); // 定期更新调试信息 setInterval(() { document.getElementById(debug-info).innerHTML 状态: ${gameInstance.state.gameStatus}br 尝试: ${gameInstance.state.currentAttempt}br 当前猜测: ${gameInstance.state.currentGuess.join(, )} ; }, 1000); } static logGameState(state) { console.group(Game State); console.log(Status:, state.gameStatus); console.log(Secret Code:, state.secretCode); console.log(Current Attempt:, state.currentAttempt); console.log(Current Guess:, state.currentGuess); console.groupEnd(); } } // 在游戏初始化时启用调试 // DebugHelper.enableDebugMode(this);10. 项目部署与开源准备10.1 构建优化配置创建生产环境构建配置// vite.config.js (如果使用Vite) import { defineConfig } from vite; export default defineConfig({ base: ./, build: { outDir: dist, assetsDir: assets, rollupOptions: { output: { manualChunks: { three: [three] } } } }, server: { port: 3000, open: true } });10.2 开源项目文档准备创建完整的项目文档# Mastermind 3D Game 基于Three.js实现的3D猜颜色游戏使用AI Coding辅助开发。 ## 特性 - 经典的Mastermind游戏玩法 - 精美的3D视觉效果 - 响应式设计支持移动端 - 多难度级别可选 - 游戏统计和进度保存 - ⚡ 性能优化流畅体验 ## 快速开始 1. 克隆项目 bash git clone https://github.com/yourusername/mastermind-game.git安装依赖npm install启动开发服务器npm run dev打开浏览器访问 http://localhost:3000技术栈Three.js (3D渲染)Vanilla JavaScript (游戏逻辑)HTML5/CSS3 (用户界面)Vite (构建工具)浏览器支持Chrome 90Firefox 88Safari 14Edge 90通过本文的完整实现我们不仅复刻了一个经典的Mastermind游戏还展示了如何结合现代前端技术和AI编程工具来提高开发效率。这个项目涵盖了3D图形编程、游戏逻辑设计、性能优化等多个重要主题为前端开发者提供了一个很好的学习案例。