《three.js网页可操控魔方》

发布时间:2026/8/12 18:50:07

《three.js网页可操控魔方》
《three.js网页可操控魔方》3D 魔方模拟器 3D 魔方模拟器操作说明鼠标拖拽旋转视角空格打乱魔方R复原魔方U/D/L/R/F/B顺时针转一层Shift 字母逆时针转 打乱 复原步数:0script srchttps://unpkg.com/three0.160.0/build/three.min.js/script script let scene, camera, renderer, cubeGroup; let cubelets []; let moveCount 0; let isAnimating false; let rotationGroup; let faceCubelets []; const COLORS { white: 0xffffff, yellow: 0xffeb3b, red: 0xf44336, orange: 0xff9800, blue: 0x2196f3, green: 0x4caf50, black: 0x222222 }; function init() { try { scene new THREE.Scene(); scene.background new THREE.Color(0x1a1a2e); camera new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(6, 5, 8); camera.lookAt(0, 0, 0); renderer new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(window.devicePixelRatio); document.getElementById(container).appendChild(renderer.domElement); const ambientLight new THREE.AmbientLight(0xffffff, 0.6); scene.add(ambientLight); const directionalLight new THREE.DirectionalLight(0xffffff, 0.8); directionalLight.position.set(10, 20, 10); scene.add(directionalLight); cubeGroup new THREE.Group(); scene.add(cubeGroup); createRubiksCube(); setupControls(); animate(); console.log(魔方初始化成功); } catch (e) { showError(初始化错误: e.message); } } function showError(msg) { document.getElementById(error).textContent msg; document.getElementById(error).style.display block; console.error(msg); } function createCubelet(x, y, z) { const cubeletGroup new THREE.Group(); cubeletGroup.position.set(x, y, z); cubeletGroup.userData { originalPos: {x, y, z} }; const geometry new THREE.BoxGeometry(0.95, 0.95, 0.95); const materials []; // 定义每个面的颜色: right, left, top, bottom, front, back const faceDefs [ { cond: x 1, color: red }, // 右 - 红 { cond: x -1, color: orange }, // 左 - 橙 { cond: y 1, color: white }, // 上 - 白 { cond: y -1, color: yellow }, // 下 - 黄 { cond: z 1, color: blue }, // 前 - 蓝 { cond: z -1, color: green } // 后 - 绿 ]; faceDefs.forEach(face { const material new THREE.MeshStandardMaterial({ color: face.cond ? COLORS[face.color] : COLORS.black, roughness: 0.3, metalness: 0.1 }); materials.push(material); }); const cubelet new THREE.Mesh(geometry, materials); cubeletGroup.add(cubelet); cubelets.push(cubeletGroup); cubeGroup.add(cubeletGroup); return cubeletGroup; } function createRubiksCube() { cubelets.forEach(c cubeGroup.remove(c)); cubelets []; for (let x -1; x 1; x) { for (let y -1; y 1; y) { for (let z -1; z 1; z) { createCubelet(x, y, z); } } } } function setupControls() { let isDragging false; let previousMousePosition { x: 0, y: 0 }; renderer.domElement.addEventListener(mousedown, (e) { if (isAnimating) return; isDragging true; previousMousePosition { x: e.clientX, y: e.clientY }; }); renderer.domElement.addEventListener(mousemove, (e) { if (!isDragging) return; const deltaX e.clientX - previousMousePosition.x; const deltaY e.clientY - previousMousePosition.y; cubeGroup.rotation.y deltaX * 0.01; cubeGroup.rotation.x deltaY * 0.01; previousMousePosition { x: e.clientX, y: e.clientY }; }); renderer.domElement.addEventListener(mouseup, () isDragging false); renderer.domElement.addEventListener(mouseleave, () isDragging false); renderer.domElement.addEventListener(contextmenu, (e) e.preventDefault()); document.addEventListener(keydown, (e) { if (isAnimating) return; const key e.key.toUpperCase(); const faces { U: Y, D: -Y, L: -X, R: X, F: Z, B: -Z }; if (faces[key]) { e.preventDefault(); rotateFace(faces[key], e.shiftKey ? -1 : 1); } else if (e.code Space) { e.preventDefault(); scramble(); } else if (key R !e.ctrlKey) { resetCube(); } }); } function getCubeletsOnFace(face) { return cubelets.filter(c { const pos c.userData.originalPos; switch(face) { case Y: return pos.y 1; case -Y: return pos.y -1; case X: return pos.x 1; case -X: return pos.x -1; case Z: return pos.z 1; case -Z: return pos.z -1; } }); } function rotateFace(face, direction 1, animate true) { if (isAnimating) return; isAnimating true; faceCubelets getCubeletsOnFace(face); rotationGroup new THREE.Group(); scene.add(rotationGroup); faceCubelets.forEach(cubelet { cubeGroup.remove(cubelet); rotationGroup.add(cubelet); }); const axis new THREE.Vector3( face X || face -X ? 1 : 0, face Y || face -Y ? 1 : 0, face Z || face -Z ? 1 : 0 ); if (face.startsWith(-)) axis.negate(); const targetAngle (Math.PI / 2) * direction; if (!animate) { rotationGroup.rotateOnWorldAxis(axis, targetAngle); finishRotation(); return; } const duration 200; const startTime Date.now(); function animateRotation() { const elapsed Date.now() - startTime; const progress Math.min(elapsed / duration, 1); const eased 1 - Math.pow(1 - progress, 3); rotationGroup.rotation.set(0, 0, 0); rotationGroup.rotateOnWorldAxis(axis, targetAngle * eased); if (progress 1) { requestAnimationFrame(animateRotation); } else { finishRotation(); } } animateRotation(); } function finishRotation() { const savedCubelets faceCubelets.slice(); savedCubelets.forEach(cubelet { const worldPos new THREE.Vector3(); cubelet.getWorldPosition(worldPos); const worldQuat new THREE.Quaternion(); cubelet.getWorldQuaternion(worldQuat); rotationGroup.remove(cubelet); cubeGroup.add(cubelet); cubelet.position.copy(worldPos); cubelet.quaternion.copy(worldQuat); cubelet.position.x Math.round(cubelet.position.x * 10) / 10; cubelet.position.y Math.round(cubelet.position.y * 10) / 10; cubelet.position.z Math.round(cubelet.position.z * 10) / 10; cubelet.userData.originalPos { x: cubelet.position.x, y: cubelet.position.y, z: cubelet.position.z }; }); scene.remove(rotationGroup); rotationGroup null; isAnimating false; moveCount; document.getElementById(moves).textContent moveCount; } function scramble() { if (isAnimating) return; const moves [Y, -Y, X, -X, Z, -Z]; const sequence []; for (let i 0; i 20; i) { sequence.push({ face: moves[Math.floor(Math.random() * moves.length)], direction: Math.random() 0.5 ? 1 : -1 }); } let i 0; function doNextMove() { if (i sequence.length) { rotateFace(sequence[i].face, sequence[i].direction, true); i; setTimeout(doNextMove, 250); } } doNextMove(); showStatus(魔方已打乱); } function resetCube() { if (isAnimating) return; createRubiksCube(); moveCount 0; document.getElementById(moves).textContent 0; showStatus(魔方已复原); } function showStatus(text) { const status document.getElementById(status); status.textContent text; status.style.display block; setTimeout(() status.style.display none, 2000); } function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); } window.addEventListener(resize, () { camera.aspect window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); }); window.addEventListener(DOMContentLoaded, init); if (document.readyState ! loading) { init(); } /script

相关新闻

FB广告成本越来越高,普通卖家还有机会吗?

FB广告成本越来越高,普通卖家还有机会吗?

2026/8/12 18:50:07

最近很多做跨境的老板都有一个感觉:Facebook广告越来越难跑了。以前一天几百美金预算,可能还能稳定出单。但是现在呢?CPM越来越高,点击越来越贵,获客成本不断上涨。很多人开始怀疑:“是不是Facebook已经不适…

链表与哈希表:数据结构核心原理与工程实践

链表与哈希表:数据结构核心原理与工程实践

2026/8/12 18:40:07

1. 数据结构入门:为什么链表和哈希表是核心基础 刚入行那会儿,我总以为数据结构就是些抽象概念,直到第一次面试被要求手写链表反转才意识到它的重要性。链表和哈希表作为数据结构中最基础也最实用的两种结构,几乎出现在所有技术岗…

基于YOLOv8+pyqt5的农作物识别检测系统1(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_

基于YOLOv8+pyqt5的农作物识别检测系统1(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_

2026/8/12 18:40:07

基于YOLOv8pyqt5的农作物识别检测系统1(设计源文件万字报告讲解)(支持资料、图片参考_相关定制)_ 内含CWC数据集 包含蓝草、藜、刺菜、玉米、莎草、棉花、茄属植物、番茄、天鹅绒、生菜、萝卜,11类农作物 也可自行替换模型,使用该…

【ORC】ORC 文件如何支持 Schema Evolution(模式演进)?添加/删除列时文件结构如何变化?

【ORC】ORC 文件如何支持 Schema Evolution(模式演进)?添加/删除列时文件结构如何变化?

2026/8/12 21:00:13

ORC 文件如何优雅支持 Schema Evolution?添加/删除列的底层机制全解析 在构建流批一体平台和实时数仓的过程中,Schema Evolution(模式演进) 是一项不可或缺的能力。业务需求瞬息万变,数据模型必须随之灵活调整:今天可能需要为用户行为日志增加一个 device_model 字段,明…

Python AI 服务迁到 Rust:先对齐协议,再切执行路径

Python AI 服务迁到 Rust:先对齐协议,再切执行路径

2026/8/12 21:00:13

Python AI 服务迁到 Rust:先对齐协议,再切执行路径 先把问题落到具体对象 重写服务最先对齐的不是吞吐,而是请求、响应、错误码、取消和超时语义。Rust 版本只有在这些外部行为稳定后,才适合进入流量切换。 变更如何分阶段 先用脱…

易认证(EAuth)集成Github认证

易认证(EAuth)集成Github认证

2026/8/12 21:00:13

介绍 易认证(EAuth)是一款开源的企业级的OIDC认证平台,使用golangreact(ant design pro框架)开发的,提供多种认证方式,包括人脸识别、OpenID Connect(OIDC)、Web身份认证等,支持多因素认证(MFA), 灵活的令牌(Token)生…

AUTOSAR CAN通信DBC文件:从协议定义到工程实践

AUTOSAR CAN通信DBC文件:从协议定义到工程实践

2026/8/12 21:00:13

这次我们来看一个在汽车电子开发中绕不开的技术点:AUTOSAR CAN通信中的DBC文件。对于从事车载网络、ECU开发、测试或诊断的工程师来说,DBC不是一个陌生的概念,但它到底是什么?为什么在AUTOSAR架构下如此重要?它解决了什…

MiniMax M3深度测评:高性价比AI模型如何平衡性能与成本

MiniMax M3深度测评:高性价比AI模型如何平衡性能与成本

2026/8/12 21:00:13

1. 从“能打”到“不贵”:MiniMax M3的定位与市场冲击最近几个月,AI大模型领域的热度似乎从纯粹的“参数竞赛”转向了更务实的“性价比之争”。当大家还在讨论GPT-4o、Claude 3.5 Sonnet这些顶级模型如何惊艳时,一个来自国内团队的声音&#…

VS Code与Claude Code整合提升开发效率指南

VS Code与Claude Code整合提升开发效率指南

2026/8/12 20:50:13

1. 为什么开发者需要VS Code与Claude Code的深度整合在代码编辑器的生态中,VS Code早已成为大多数开发者的首选工具。根据2023年Stack Overflow开发者调查报告,VS Code以74.48%的使用率遥遥领先其他编辑器。而Claude Code作为新兴的AI编程助手&#xff0…

比较好的亚太EMBA,问了6位校友师资差别真的挺大

比较好的亚太EMBA,问了6位校友师资差别真的挺大

2026/8/12 7:11:29

比较好的亚太EMBA核心差异先看什么?对于希望兼顾工作与系统管理能力提升的亚太区高管而言,筛选匹配度高的EMBA项目时,师资配置是决定学习体验与实际收获的核心要素之一。我们结合3-4个公开信息透明、办学历史较长的亚太区主流EMBA项目特点&am…

备考3个月对比6份资料 海外游学的亚洲EMBA面试注意点

备考3个月对比6份资料 海外游学的亚洲EMBA面试注意点

2026/8/11 8:44:43

备考海外游学的亚洲EMBA面试,核心要围绕项目国际化设计逻辑、个人跨文化管理经验匹配度两个维度准备,避免把游学模块等同于普通旅游参访的认知偏差。不少备考者花3个月对比6份资料,却容易忽略面试官对“国际视野落地能力”的考察——比如香港…

比较好的国内EMBA,问了二十位校友聊透人脉价值

比较好的国内EMBA,问了二十位校友聊透人脉价值

2026/8/11 15:57:54

比较好的国内EMBA核心差异体现在哪些方面?比较好的国内EMBA的核心长期价值,很大程度上依托于校友网络的连接质量与资源生态的活跃度,这也是不少高管在择校时优先考量的因素。我们结合3-4个市场关注度较高的项目公开信息,从课程、师…

告别模组冲突!5步掌握《神界:原罪2》模组管理的终极秘诀

告别模组冲突!5步掌握《神界:原罪2》模组管理的终极秘诀

2026/8/12 9:39:37

告别模组冲突!5步掌握《神界:原罪2》模组管理的终极秘诀 【免费下载链接】DivinityModManager A mod manager for Divinity: Original Sin - Definitive Edition. 项目地址: https://gitcode.com/gh_mirrors/di/DivinityModManager 你是否曾经为《…

如何用Charge Limiter延长MacBook电池寿命:终极保护指南

如何用Charge Limiter延长MacBook电池寿命:终极保护指南

2026/8/12 9:39:37

如何用Charge Limiter延长MacBook电池寿命:终极保护指南 【免费下载链接】charge-limiter macOS app to set battery charge limit for Intel MacBooks 项目地址: https://gitcode.com/gh_mirrors/ch/charge-limiter 还在为MacBook电池健康度下降而烦恼吗&am…

推三返一模式5.0版本系统开发

推三返一模式5.0版本系统开发

2026/8/12 9:39:37

推三返一模式5.0版本系统开发要点编辑:araolin(私域邦网络土土哥)模式核心逻辑 推三返一是一种促销或分销机制,用户推荐三人完成特定行为(如购买、注册),推荐人可获得返利或奖励。5.0版本通常在…

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

2026/8/8 5:07:31

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…

导师推荐!2026最新AI论文工具测评与实用推荐

导师推荐!2026最新AI论文工具测评与实用推荐

2026/8/9 13:42:46

2026年真正好用的AI论文工具,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

告别游戏崩溃:XCOM 2模组管理器的智能革命

告别游戏崩溃:XCOM 2模组管理器的智能革命

2026/8/8 2:30:15

告别游戏崩溃:XCOM 2模组管理器的智能革命 【免费下载链接】xcom2-launcher The Alternative Mod Launcher (AML) is a replacement for the default game launchers from XCOM 2 and XCOM Chimera Squad. 项目地址: https://gitcode.com/gh_mirrors/xc/xcom2-lau…