3D魔方游戏

发布于:2025-07-08 ⋅ 阅读:(18) ⋅ 点赞:(0)

# 3D魔方游戏

这是一个基于Three.js的3D魔方游戏,支持2到6阶魔方的模拟操作。

## 功能特点

- 支持2到6阶魔方

- 真实的3D渲染效果

- 鼠标操作控制

- 随机打乱功能

- 提示功能

- 重置功能

### 安装依赖

```bash

npm install

```

### 启动游戏

```bash

npm start

```

然后在浏览器中访问 `http://localhost:8080` 即可开始游戏。

## 操作说明

- 使用鼠标拖拽可以旋转整个魔方

- 按住Shift键并点击魔方的某一面可以旋转该面

- 使用界面上的下拉菜单可以选择魔方的阶数(2到6阶)

- 点击"随机打乱"按钮可以随机打乱魔方

- 点击"提示"按钮可以获取下一步的提示

- 点击"重置"按钮可以重置魔方到初始状态

## 技术栈

- HTML5

- CSS3

- JavaScript (ES6+)

- Three.js (3D渲染库)

## 浏览器兼容性

支持所有现代浏览器,包括:

- Chrome

- Firefox

- Safari

- Edge

## 许可证

ISC

import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import TWEEN from 'three/examples/jsm/libs/tween.module.js';
import { Cube } from './cube.js';

// 全局变量
let scene, camera, renderer, controls;
let cube;
let currentOrder = 3; // 默认3阶魔方
let isCtrlPressed = false; // 跟踪Ctrl键是否按下
let isDragging = false; // 跟踪是否正在拖拽

// 初始化场景
function init() {
    // 创建场景
    scene = new THREE.Scene();
    scene.background = new THREE.Color(0xf0f0f0);

    // 获取容器
    const container = document.getElementById('cube-container');
    const containerWidth = container.clientWidth;
    const containerHeight = container.clientHeight || window.innerHeight * 0.6;
    
    // 强制设置容器高度
    container.style.height = `${containerHeight}px`;

    // 创建相机
    camera = new THREE.PerspectiveCamera(
        50, // 视角更广
        containerWidth / containerHeight,
        0.1,
        1000
    );
    
    // 根据魔方阶数调整相机位置
    const cameraDistance = 8 + currentOrder * 1.0; // 增加距离
    camera.position.set(cameraDistance, cameraDistance, cameraDistance);
    camera.lookAt(0, 0, 0);

    // 创建渲染器
    renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(containerWidth, containerHeight);
    renderer.setPixelRatio(window.devicePixelRatio);
    container.appendChild(renderer.domElement);

    // 添加轨道控制
    controls = new OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.dampingFactor = 0.1;
    controls.minDistance = cameraDistance * 0.5;
    controls.maxDistance = cameraDistance * 2;
    controls.enableRotate = true;
    controls.rotateSpeed = 1.0;
    // 允许完全旋转
    controls.minPolarAngle = 0;
    controls.maxPolarAngle = Math.PI;
    controls.minAzimuthAngle = -Infinity;
    controls.maxAzimuthAngle = Infinity;
    controls.target.set(0, 0, 0);
    
    // 默认禁用轨道控制
    controls.enabled = false;

    // 添加光源
    const ambientLight = new THREE.AmbientLight(0xffffff, 0.7);
    scene.add(ambientLight);

    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
    directionalLight.position.set(10, 20, 15);
    scene.add(directionalLight);
    
    // 添加第二个方向光源,照亮底部
    const bottomLight = new THREE.DirectionalLight(0xffffff, 0.6);
    bottomLight.position.set(-5, -10, -7);
    scene.add(bottomLight);
    
    // 添加第三个方向光源,照亮侧面
    const sideLight = new THREE.DirectionalLight(0xffffff, 0.6);
    sideLight.position.set(-10, 5, -10);
    scene.add(sideLight);

    // 创建魔方
    createCube(currentOrder);

    // 添加窗口大小调整监听
    window.addEventListener('resize', onWindowResize);

    // 添加交互控制
    setupInteraction();
}

// 窗口大小调整
function onWindowResize() {
    const container = document.getElementById('cube-container');
    const containerWidth = container.clientWidth;
    const containerHeight = container.clientHeight || window.innerHeight * 0.6;
    
    camera.aspect = containerWidth / containerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(containerWidth, containerHeight);
}

// 动画循环
function animate() {
    requestAnimationFrame(animate);
    TWEEN.update(); // 更新动画
    controls.update();
    renderer.render(scene, camera);
}

// 创建魔方
function createCube(order) {
    if (cube) {
        scene.remove(cube.group);
    }
    cube = new Cube(order);
    scene.add(cube.group);
}

// 设置交互控制
function setupInteraction() {
    const raycaster = new THREE.Raycaster();
    const mouse = new THREE.Vector2();
    let selectedFace = null;
    let startPoint = new THREE.Vector2();
    let endPoint = new THREE.Vector2();
    
    // 监听Ctrl键
    window.addEventListener('keydown', function(event) {
        if (event.key === 'Control') {
            isCtrlPressed = true;
            controls.enabled = true;
            renderer.domElement.style.cursor = 'move';
            console.log('Ctrl键按下,启用轨道控制');
        }
    });
    
    window.addEventListener('keyup', function(event) {
        if (event.key === 'Control') {
            isCtrlPressed = false;
            controls.enabled = false;
            renderer.domElement.style.cursor = 'default';
            console.log('Ctrl键释放,禁用轨道控制');
        }
    });
    
    // 添加初始提示
    const infoDiv = document.createElement('div');
    infoDiv.style.position = 'absolute';
    infoDiv.style.bottom = '10px';
    infoDiv.style.left = '10px';
    infoDiv.style.backgroundColor = 'rgba(0,0,0,0.7)';
    infoDiv.style.color = 'white';
    infoDiv.style.padding = '5px 10px';
    infoDiv.style.borderRadius = '5px';
    infoDiv.style.fontSize = '14px';
    infoDiv.innerHTML = '按住Ctrl键可自由旋转整个魔方<br>点击或拖动魔方面可旋转该面';
    document.getElementById('cube-container').appendChild(infoDiv);
    
    // 10秒后隐藏提示
    setTimeout(() => {
        infoDiv.style.opacity = '0';
        infoDiv.style.transition = 'opacity 1s';
        setTimeout(() => {
            infoDiv.remove();
        }, 1000);
    }, 10000);
    
    // 初始自动旋转魔方,让用户看到所有面
    setTimeout(() => {
        // 先旋转到一个角度,让用户看到更多面
        const startRotation = { x: 0, y: 0 };
        const endRotation = { x: Math.PI / 3, y: Math.PI / 4 };
        
        new TWEEN.Tween(startRotation)
            .to(endRotation, 1500)
            .easing(TWEEN.Easing.Quadratic.Out)
            .onUpdate(() => {
                cube.group.rotation.x = startRotation.x;
                cube.group.rotation.y = startRotation.y;
            })
            .onComplete(() => {
                // 旋转完成后,重置魔方位置
                setTimeout(() => {
                    new TWEEN.Tween(cube.group.rotation)
                        .to({ x: 0, y: 0, z: 0 }, 1000)
                        .easing(TWEEN.Easing.Quadratic.Out)
                        .start();
                }, 1000);
            })
            .start();
    }, 500);
    
    // 鼠标按下事件
    renderer.domElement.addEventListener('mousedown', function(event) {
        // 如果按下Ctrl键,启用轨道控制并跳过魔方面旋转
        if (event.ctrlKey || isCtrlPressed) {
            controls.enabled = true;
            return;
        }
        
        // 禁用轨道控制
        controls.enabled = false;
        
        // 如果魔方正在动画中,则不处理
        if (cube && cube.isAnimating) return;
        
        isDragging = false;
        const rect = renderer.domElement.getBoundingClientRect();
        mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
        mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
        
        // 保存起始点
        startPoint.set(event.clientX, event.clientY);
        endPoint.copy(startPoint); // 初始化终点与起点相同
        
        raycaster.setFromCamera(mouse, camera);
        
        try {
            const allCubies = cube.getAllCubies();
            if (!allCubies || allCubies.length === 0) {
                console.warn('没有找到魔方小块');
                return;
            }
            
            // 递归设置为true,以检测子对象
            const intersects = raycaster.intersectObjects(allCubies, true);
            
            if (intersects.length > 0) {
                // 确保我们有正确的对象和面
                let targetObject = intersects[0].object;
                
                // 如果点击的是边缘线段,获取其父对象(实际的方块)
                while (targetObject.parent && !(targetObject instanceof THREE.Mesh)) {
                    targetObject = targetObject.parent;
                }
                
                // 创建一个新的交点对象,确保有正确的目标对象和面信息
                const correctedIntersect = {
                    ...intersects[0],
                    object: targetObject
                };
                
                // 尝试获取面信息
                selectedFace = cube.getFaceFromIntersect(correctedIntersect);
                
                if (selectedFace) {
                    console.log('选中面:', selectedFace);
                    renderer.domElement.style.cursor = 'pointer';
                } else {
                    console.log('未能确定选中的面');
                    
                    // 尝试直接从物体位置确定面
                    const position = targetObject.position.clone();
                    const x = Math.round((position.x + cube.offset) / (cube.cubeSize + cube.gap));
                    const y = Math.round((position.y + cube.offset) / (cube.cubeSize + cube.gap));
                    const z = Math.round((position.z + cube.offset) / (cube.cubeSize + cube.gap));
                    
                    // 确定是哪个面
                    if (x === 0) {
                        selectedFace = { axis: 'x', value: -1, layer: 0 };
                    } else if (x === cube.order - 1) {
                        selectedFace = { axis: 'x', value: 1, layer: cube.order - 1 };
                    } else if (y === 0) {
                        selectedFace = { axis: 'y', value: -1, layer: 0 };
                    } else if (y === cube.order - 1) {
                        selectedFace = { axis: 'y', value: 1, layer: cube.order - 1 };
                    } else if (z === 0) {
                        selectedFace = { axis: 'z', value: -1, layer: 0 };
                    } else if (z === cube.order - 1) {
                        selectedFace = { axis: 'z', value: 1, layer: cube.order - 1 };
                    }
                    
                    if (selectedFace) {
                        console.log('从位置推断的面:', selectedFace);
                        renderer.domElement.style.cursor = 'pointer';
                    }
                }
            } else {
                console.log('未选中任何面');
                selectedFace = null;
            }
        } catch (error) {
            console.error('射线检测错误:', error);
        }
    });

    // 鼠标移动事件
    window.addEventListener('mousemove', function(event) {
        // 如果按下Ctrl键,让轨道控制处理移动
        if (event.ctrlKey || isCtrlPressed) {
            controls.enabled = true;
            return;
        }
        
        // 如果没有选中面,则不处理
        if (!selectedFace) return;
        
        // 更新终点位置
        endPoint.set(event.clientX, event.clientY);
        
        // 计算移动距离
        const moveDistance = Math.sqrt(
            Math.pow(endPoint.x - startPoint.x, 2) + 
            Math.pow(endPoint.y - startPoint.y, 2)
        );
        
        // 如果移动距离超过阈值,标记为拖拽
        if (moveDistance > 8) { // 增加阈值,减少误触
            isDragging = true;
            renderer.domElement.style.cursor = 'grabbing';
            
            // 计算拖拽方向向量
            const dragVector = {
                x: endPoint.x - startPoint.x,
                y: endPoint.y - startPoint.y
            };
            
            // 显示拖拽方向指示
            const direction = determineRotationDirection(selectedFace, dragVector);
            console.log('当前拖拽方向:', direction > 0 ? '顺时针' : '逆时针');
        }
    });

    // 鼠标释放事件
    window.addEventListener('mouseup', function(event) {
        renderer.domElement.style.cursor = 'default';
        
        // 如果按下Ctrl键,让轨道控制处理释放
        if (event.ctrlKey || isCtrlPressed) {
            return;
        }
        
        // 如果没有选中面,则不处理
        if (!selectedFace) return;
        
        // 更新终点位置
        endPoint.set(event.clientX, event.clientY);
        
        // 如果是拖拽操作,根据拖拽方向确定旋转方向
        if (isDragging) {
            // 计算拖拽方向向量
            const dragVector = {
                x: endPoint.x - startPoint.x,
                y: endPoint.y - startPoint.y
            };
            
            // 计算移动距离
            const moveDistance = Math.sqrt(
                Math.pow(dragVector.x, 2) + 
                Math.pow(dragVector.y, 2)
            );
            
            // 只有当移动距离足够大时才执行旋转,防止误触
            if (moveDistance > 15) {
                // 根据拖拽方向和选中的面确定旋转方向
                const direction = determineRotationDirection(selectedFace, dragVector);
                
                console.log('旋转方向:', direction);
                
                // 执行旋转
                if (cube && typeof cube.rotateFace === 'function') {
                    cube.rotateFace({
                        axis: selectedFace.axis,
                        layer: selectedFace.layer,
                        direction: direction
                    });
                } else {
                    console.error('cube.rotateFace 不是一个函数');
                }
            } else {
                console.log('移动距离不足,取消旋转');
            }
        } 
        // 如果是点击操作,使用默认方向旋转
        else {
            console.log('点击操作');
            if (cube && typeof cube.rotateFace === 'function') {
                cube.rotateFace(selectedFace);
            } else {
                console.error('cube.rotateFace 不是一个函数');
            }
        }
        
        selectedFace = null;
        isDragging = false;
    });
    
    // 添加触摸支持
    renderer.domElement.addEventListener('touchstart', function(event) {
        if (cube && cube.isAnimating) return;
        
        event.preventDefault();
        isDragging = false;
        
        const rect = renderer.domElement.getBoundingClientRect();
        const touch = event.touches[0];
        
        mouse.x = ((touch.clientX - rect.left) / rect.width) * 2 - 1;
        mouse.y = -((touch.clientY - rect.top) / rect.height) * 2 + 1;
        
        // 保存起始点
        startPoint.set(touch.clientX, touch.clientY);
        endPoint.copy(startPoint);
        
        raycaster.setFromCamera(mouse, camera);
        
        try {
            const allCubies = cube.getAllCubies();
            if (!allCubies || allCubies.length === 0) return;
            
            const intersects = raycaster.intersectObjects(allCubies, true);
            
            if (intersects.length > 0) {
                // 确保我们有正确的对象和面
                let targetObject = intersects[0].object;
                // 如果点击的是边缘线段,获取其父对象(实际的方块)
                while (targetObject.parent && !(targetObject instanceof THREE.Mesh)) {
                    targetObject = targetObject.parent;
                }
                
                // 创建一个新的交点对象
                const correctedIntersect = {
                    ...intersects[0],
                    object: targetObject
                };
                
                selectedFace = cube.getFaceFromIntersect(correctedIntersect);
                console.log('触摸选中面:', selectedFace);
            }
        } catch (error) {
            console.error('触摸检测错误:', error);
        }
    });
    
    renderer.domElement.addEventListener('touchmove', function(event) {
        if (!selectedFace) return;
        
        event.preventDefault();
        const touch = event.touches[0];
        
        // 更新终点位置
        endPoint.set(touch.clientX, touch.clientY);
        
        // 计算移动距离
        const moveDistance = Math.sqrt(
            Math.pow(endPoint.x - startPoint.x, 2) + 
            Math.pow(endPoint.y - startPoint.y, 2)
        );
        
        // 如果移动距离超过阈值,标记为拖拽
        if (moveDistance > 10) {
            isDragging = true;
        }
    });
    
    renderer.domElement.addEventListener('touchend', function(event) {
        if (!selectedFace) return;
        
        event.preventDefault();
        
        if (isDragging) {
            // 计算拖拽方向向量
            const dragVector = {
                x: endPoint.x - startPoint.x,
                y: endPoint.y - startPoint.y
            };
            
            // 根据拖拽方向和选中的面确定旋转方向
            const direction = determineRotationDirection(selectedFace, dragVector);
            
            // 执行旋转
            if (cube && typeof cube.rotateFace === 'function') {
                cube.rotateFace({
                    axis: selectedFace.axis,
                    layer: selectedFace.layer,
                    direction: direction
                });
            }
        } else {
            if (cube && typeof cube.rotateFace === 'function') {
                cube.rotateFace(selectedFace);
            }
        }
        
        selectedFace = null;
        isDragging = false;
    });
    
    // 阻止右键菜单
    renderer.domElement.addEventListener('contextmenu', function(event) {
        event.preventDefault();
    });
}

// 根据拖拽方向和选中的面确定旋转方向
function determineRotationDirection(face, dragVector) {
    const { axis, value } = face;
    
    // 计算拖拽的主要方向和角度
    const dragAngle = Math.atan2(dragVector.y, dragVector.x) * 180 / Math.PI;
    console.log('拖拽角度:', dragAngle);
    
    // 根据角度确定拖拽的主要方向
    let dragDirection;
    if (dragAngle > -45 && dragAngle <= 45) {
        dragDirection = 'right';
    } else if (dragAngle > 45 && dragAngle <= 135) {
        dragDirection = 'down';
    } else if (dragAngle > 135 || dragAngle <= -135) {
        dragDirection = 'left';
    } else {
        dragDirection = 'up';
    }
    
    console.log('拖拽方向:', dragDirection);
    
    // 根据面的轴和拖拽方向确定旋转方向
    // 1表示顺时针,-1表示逆时针
    let direction = 1;
    
    switch (axis) {
        case 'x': // 左右面
            if (value > 0) { // 右面
                direction = (dragDirection === 'up' || dragDirection === 'right') ? 1 : -1;
            } else { // 左面
                direction = (dragDirection === 'up' || dragDirection === 'left') ? 1 : -1;
            }
            break;
        case 'y': // 上下面
            if (value > 0) { // 上面
                direction = (dragDirection === 'right' || dragDirection === 'down') ? 1 : -1;
            } else { // 下面
                direction = (dragDirection === 'right' || dragDirection === 'up') ? 1 : -1;
            }
            break;
        case 'z': // 前后面
            if (value > 0) { // 前面
                direction = (dragDirection === 'right' || dragDirection === 'up') ? 1 : -1;
            } else { // 后面
                direction = (dragDirection === 'left' || dragDirection === 'up') ? 1 : -1;
            }
            break;
    }
    
    console.log('旋转方向:', direction > 0 ? '顺时针' : '逆时针');
    return direction;
}

// 初始化事件监听
function initEventListeners() {
    // 魔方阶数选择
    document.getElementById('cube-order').addEventListener('change', (event) => {
        currentOrder = parseInt(event.target.value);
        createCube(currentOrder);
        updateLayerButtons(); // 更新层按钮
    });

    // 随机打乱按钮
    document.getElementById('scramble-btn').addEventListener('click', () => {
        cube.scramble();
    });

    // 提示按钮
    document.getElementById('hint-btn').addEventListener('click', () => {
        cube.showHint();
    });

    // 重置按钮
    document.getElementById('reset-btn').addEventListener('click', () => {
        createCube(currentOrder);
        updateLayerButtons(); // 更新层按钮
    });
    
    // 旋转控制按钮
    document.getElementById('rotate-left').addEventListener('click', () => {
        rotateCubeWithAnimation({ axis: 'y', angle: Math.PI / 4 });
    });
    
    document.getElementById('rotate-right').addEventListener('click', () => {
        rotateCubeWithAnimation({ axis: 'y', angle: -Math.PI / 4 });
    });
    
    document.getElementById('rotate-up').addEventListener('click', () => {
        rotateCubeWithAnimation({ axis: 'x', angle: Math.PI / 4 });
    });
    
    document.getElementById('rotate-down').addEventListener('click', () => {
        rotateCubeWithAnimation({ axis: 'x', angle: -Math.PI / 4 });
    });
    
    document.getElementById('rotate-clockwise').addEventListener('click', () => {
        rotateCubeWithAnimation({ axis: 'z', angle: -Math.PI / 4 });
    });
    
    document.getElementById('rotate-counter-clockwise').addEventListener('click', () => {
        rotateCubeWithAnimation({ axis: 'z', angle: Math.PI / 4 });
    });
    
    // 层选择控制
    // 初始化层按钮
    updateLayerButtons();
    
    // 轴选择变化时更新层按钮
    document.getElementById('axis-select').addEventListener('change', updateLayerButtons);
    
    // 层旋转方向按钮
    document.getElementById('rotate-clockwise-layer').addEventListener('click', () => {
        rotateSelectedLayer(1); // 顺时针
    });
    
    document.getElementById('rotate-counter-clockwise-layer').addEventListener('click', () => {
        rotateSelectedLayer(-1); // 逆时针
    });
    
    // 添加键盘控制
    window.addEventListener('keydown', function(event) {
        // 如果魔方正在动画中,则不处理
        if (cube && cube.isAnimating) return;
        
        // 如果按下Ctrl键,启用轨道控制
        if (event.key === 'Control') {
            isCtrlPressed = true;
            controls.enabled = true;
            renderer.domElement.style.cursor = 'move';
            console.log('Ctrl键按下,启用轨道控制');
            return;
        }
        
        // 键盘控制魔方旋转
        switch (event.key) {
            // 旋转整个魔方
            case 'ArrowLeft':
                if (event.shiftKey) {
                    rotateCubeWithAnimation({ axis: 'y', angle: Math.PI / 4 });
                }
                break;
            case 'ArrowRight':
                if (event.shiftKey) {
                    rotateCubeWithAnimation({ axis: 'y', angle: -Math.PI / 4 });
                }
                break;
            case 'ArrowUp':
                if (event.shiftKey) {
                    rotateCubeWithAnimation({ axis: 'x', angle: Math.PI / 4 });
                }
                break;
            case 'ArrowDown':
                if (event.shiftKey) {
                    rotateCubeWithAnimation({ axis: 'x', angle: -Math.PI / 4 });
                }
                break;
                
            // 旋转魔方的面 (按键1-9对应九宫格位置)
            case '1': case '2': case '3': 
            case '4': case '5': case '6': 
            case '7': case '8': case '9':
                const keyNum = parseInt(event.key);
                let layer = 0;
                let axis = 'z';
                let direction = 1;
                
                // 根据按键确定旋转的面和方向
                if (keyNum <= 3) { // 上层
                    layer = cube.order - 1;
                    axis = 'y';
                    direction = keyNum === 1 || keyNum === 3 ? -1 : 1;
                } else if (keyNum <= 6) { // 中层
                    layer = Math.floor(cube.order / 2);
                    axis = 'y';
                    direction = keyNum === 4 || keyNum === 6 ? -1 : 1;
                } else { // 下层
                    layer = 0;
                    axis = 'y';
                    direction = keyNum === 7 || keyNum === 9 ? -1 : 1;
                }
                
                // 执行旋转
                if (event.altKey) { // Alt键按下时旋转X轴
                    axis = 'x';
                } else if (event.ctrlKey) { // Ctrl键按下时旋转Z轴
                    axis = 'z';
                }
                
                cube.rotateFace({
                    axis: axis,
                    layer: layer,
                    direction: direction
                });
                break;
        }
    });
    
    window.addEventListener('keyup', function(event) {
        if (event.key === 'Control') {
            isCtrlPressed = false;
            controls.enabled = false;
            renderer.domElement.style.cursor = 'default';
            console.log('Ctrl键释放,禁用轨道控制');
        }
    });
    
    // 添加操作说明
    const keyboardInfo = document.createElement('div');
    keyboardInfo.className = 'keyboard-info';
    keyboardInfo.innerHTML = `
        <h3>键盘控制说明:</h3>
        <p>- Shift + 方向键: 旋转整个魔方</p>
        <p>- 数字键1-9: 旋转对应位置的面</p>
        <p>- Alt + 数字键: 沿X轴旋转</p>
        <p>- Ctrl + 数字键: 沿Z轴旋转</p>
        <p>- 默认沿Y轴旋转</p>
    `;
    document.querySelector('.instructions').appendChild(keyboardInfo);
}

// 更新层按钮
function updateLayerButtons() {
    if (!cube) return;
    
    const layerButtonsContainer = document.getElementById('layer-buttons');
    layerButtonsContainer.innerHTML = ''; // 清空现有按钮
    
    const axis = document.getElementById('axis-select').value;
    
    // 为每一层创建按钮
    for (let i = 0; i < cube.order; i++) {
        const button = document.createElement('button');
        button.className = 'layer-button';
        button.textContent = i + 1;
        button.dataset.layer = i;
        button.dataset.axis = axis;
        
        // 点击选择层
        button.addEventListener('click', function() {
            // 移除其他按钮的选中状态
            document.querySelectorAll('.layer-button').forEach(btn => {
                btn.classList.remove('selected');
            });
            
            // 添加当前按钮的选中状态
            this.classList.add('selected');
        });
        
        layerButtonsContainer.appendChild(button);
    }
    
    // 默认选中第一个按钮
    if (layerButtonsContainer.firstChild) {
        layerButtonsContainer.firstChild.classList.add('selected');
    }
}

// 旋转选中的层
function rotateSelectedLayer(direction) {
    const selectedButton = document.querySelector('.layer-button.selected');
    if (!selectedButton || !cube) return;
    
    const layer = parseInt(selectedButton.dataset.layer);
    const axis = selectedButton.dataset.axis;
    
    cube.rotateFace({
        axis: axis,
        layer: layer,
        direction: direction
    });
}

// 旋转整个魔方的动画函数
function rotateCubeWithAnimation({ axis, angle }) {
    if (!cube || !cube.group) return;
    
    const startRotation = { value: 0 };
    const endRotation = { value: angle };
    
    new TWEEN.Tween(startRotation)
        .to(endRotation, 300)
        .easing(TWEEN.Easing.Quadratic.Out)
        .onUpdate(() => {
            if (axis === 'x') {
                cube.group.rotation.x += (endRotation.value - startRotation.value) / 10;
            } else if (axis === 'y') {
                cube.group.rotation.y += (endRotation.value - startRotation.value) / 10;
            } else if (axis === 'z') {
                cube.group.rotation.z += (endRotation.value - startRotation.value) / 10;
            }
        })
        .start();
}

// 页面加载完成后初始化
window.addEventListener('DOMContentLoaded', () => {
    init();
    initEventListeners();
    animate();
});


网站公告

今日签到

点亮在社区的每一天
去签到