Stories

Detail Return Return

自制版MC - Stories Detail

<!DOCTYPE html>
<html lang="zh-CN">
<head>

<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>大型3D方塊世界</title>
<style>
    * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    
    body {
        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        background: linear-gradient(to bottom, #1a237e, #0d47a1);
        color: white;
        overflow: hidden;
        height: 100vh;
        display: flex;
        flex-direction: column;
    }
    
    #header {
        padding: 15px;
        text-align: center;
        background: rgba(0, 0, 0, 0.5);
        border-bottom: 2px solid rgba(255, 255, 255, 0.1);
    }
    
    h1 {
        font-size: 2.5rem;
        margin-bottom: 5px;
        text-shadow: 0 0 10px rgba(0, 150, 255, 0.7);
    }
    
    .subtitle {
        font-size: 1.1rem;
        opacity: 0.8;
    }
    
    #container {
        display: flex;
        flex: 1;
        overflow: hidden;
    }
    
    #sidebar {
        width: 300px;
        background: rgba(0, 0, 0, 0.6);
        padding: 20px;
        border-right: 1px solid rgba(255, 255, 255, 0.1);
        overflow-y: auto;
    }
    
    #game-container {
        flex: 1;
        position: relative;
    }
    
    #canvas-container {
        width: 100%;
        height: 100%;
    }
    
    #hud {
        position: absolute;
        bottom: 20px;
        left: 0;
        width: 100%;
        display: flex;
        justify-content: center;
        pointer-events: none;
    }
    
    #crosshair {
        width: 20px;
        height: 20px;
        border: 2px solid white;
        border-radius: 50%;
    }
    
    #block-selector {
        position: absolute;
        bottom: 20px;
        left: 50%;
        transform: translateX(-50%);
        display: flex;
        background: rgba(0, 0, 0, 0.7);
        padding: 10px;
        border-radius: 10px;
        gap: 10px;
    }
    
    .block-option {
        width: 40px;
        height: 40px;
        border: 2px solid transparent;
        border-radius: 5px;
        cursor: pointer;
        transition: all 0.2s;
    }
    
    .block-option.active {
        border-color: #4fc3f7;
        box-shadow: 0 0 10px #4fc3f7;
    }#stats {
        position: absolute;
        top: 20px;
        right: 20px;
        background: rgba(0, 0, 0, 0.7);
        padding: 10px 15px;
        border-radius: 5px;
        font-size: 0.9rem;
    }
    
    #instructions {
        position: absolute;
        top: 20px;
        left: 20px;
        background: rgba(0, 0, 0, 0.7);
        padding: 15px;
        border-radius: 5px;
        max-width: 300px;
    }
    
    .section {
        margin-bottom: 25px;
    }
    
    .section-title {
        font-size: 1.2rem;
        margin-bottom: 10px;
        color: #4fc3f7;
        border-bottom: 1px solid rgba(255, 255, 255, 0.2);
        padding-bottom: 5px;
    }
    
    .control-item {
        display: flex;
        justify-content: space-between;
        margin-bottom: 8px;
        padding: 5px 0;
        border-bottom: 1px dotted rgba(255, 255, 255, 0.1);
    }
    
    .control-key {
        background: rgba(255, 255, 255, 0.2);
        padding: 2px 8px;
        border-radius: 4px;
        font-family: monospace;
    }
    
    .block-preview {
        width: 30px;
        height: 30px;
        display: inline-block;
        vertical-align: middle;
        margin-right: 10px;
        border-radius: 4px;
    }
    
    button {
        background: #4fc3f7;
        color: white;
        border: none;
        padding: 10px 15px;
        border-radius: 5px;
        cursor: pointer;
        font-weight: bold;
        margin-top: 10px;
        transition: background 0.3s;
        width: 100%;
    }

button:hover {

        background: #29b6f6;
    }
    
    #world-info {
        background: rgba(0, 0, 0, 0.5);
        padding: 15px;
        border-radius: 5px;
        margin-top: 20px;
    }
    
    .coordinate {
        font-family: monospace;
        background: rgba(0, 0, 0, 0.3);
        padding: 2px 5px;
        border-radius: 3px;
    }
    
    #loading {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba(0, 0, 0, 0.9);
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        z-index: 100;
    }
    
    .progress-bar {
        width: 300px;
        height: 20px;
        background: rgba(255, 255, 255, 0.1);
        border-radius: 10px;
        margin-top: 20px;
        overflow: hidden;
    }
    
    .progress {
        height: 100%;
        background: #4fc3f7;
        width: 0%;
        transition: width 0.3s;
    }
    
    #loading-text {
        margin-top: 10px;
        font-size: 1.2rem;
    }
    
    .hidden {
        display: none !important;
    }
</style>

</head>
<body>

<div id="header">
    <h1>3D方塊世界</h1>
    <div class="subtitle">大型地圖 | 多種方塊 | 自由建造與破壞</div>
</div>

<div id="container">
    <div id="sidebar">
        <div class="section">
            <div class="section-title">遊戲控制</div>
            <div class="control-item">
                <span>移動</span>
                <span class="control-key">W A S D</span>
            </div>
            <div class="control-item">
                <span>跳躍</span>
                <span class="control-key">空格</span>
            </div>
            <div class="control-item">
                <span>飛行/下降</span>
                <span class="control-key">Shift</span>
            </div>
            <div class="control-item">
                <span>放置方塊</span>
                <span class="control-key">左鍵</span>
            </div>
            <div class="control-item">
                <span>破壞方塊</span>
                <span class="control-key">右鍵</span>
            </div>
            <div class="control-item">
                <span>切換方塊</span>
                <span class="control-key">1-6</span>
            </div>
        </div>
        
        <div class="section">
            <div class="section-title">方塊類型</div>
            <div class="control-item">
                <span><div class="block-preview" style="background: #00aa00;"></div>草方塊</span>
                <span class="control-key">1</span>
            </div>
            <div class="control-item">
                <span><div class="block-preview" style="background: #888888;"></div>石頭</span>
                <span class="control-key">2</span>
            </div>
            <div class="control-item">
                <span><div class="block-preview" style="background: #d2691e;"></div>泥土</span>
                <span class="control-key">3</span>
            </div>
            <div class="control-item">
                <span><div class="block-preview" style="background: #0000ff;"></div>藍石</span>
                <span class="control-key">4</span>
            </div>
            <div class="control-item">
                <span><div class="block-preview" style="background: #ff0000;"></div>紅石</span>
                <span class="control-key">5</span>
            </div>
            <div class="control-item">
                <span><div class="block-preview" style="background: #ffff00;"></div>黃石</span>
                <span class="control-key">6</span>
            </div>
        </div>

<div id="world-info">

            <div class="section-title">世界信息</div>
            <div>地圖尺寸: 64x64</div>
            <div>方塊總數: <span id="block-count">0</span></div>
            <div>玩家位置: 
                <span class="coordinate" id="player-pos">0, 0, 0</span>
            </div>
            <div>視角方向: 
                <span class="coordinate" id="player-rot">0°, 0°</span>
            </div>
        </div>
        
        <button id="reset-btn">重置世界</button>
        <button id="save-btn">保存世界</button>
        <button id="load-btn">加載世界</button>
    </div>
    
    <div id="game-container">
        <div id="canvas-container"></div>
        
        <div id="hud">
            <div id="crosshair"></div>
        </div>
        
        <div id="block-selector">
            <div class="block-option active" data-type="grass" style="background: #00aa00;"></div>
            <div class="block-option" data-type="stone" style="background: #888888;"></div>
            <div class="block-option" data-type="dirt" style="background: #d2691e;"></div>
            <div class="block-option" data-type="blue" style="background: #0000ff;"></div>
            <div class="block-option" data-type="red" style="background: #ff0000;"></div>
            <div class="block-option" data-type="yellow" style="background: #ffff00;"></div>
        </div>
        
        <div id="instructions">
            <div class="section-title">遊戲説明</div>
            <p>歡迎來到3D方塊世界!這是一個大型的沙盒遊戲,你可以自由建造和破壞方塊。</p >
            <p>使用鼠標控制視角,鍵盤控制移動。選擇不同的方塊類型來創建你的世界。</p >
        </div>
        
        // 在style標籤中添加以下新樣式
        /* 中央信息面板容器 */
        #center-info { 
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 10px;
            pointer-events: none;
            z-index: 10;
        }
        
        /* 頂部信息欄 - 居中顯示統計信息 */
        #top-stats {
            background: rgba(0, 0, 0, 0.7);
            padding: 10px 15px;
            border-radius: 5px;
            font-size: 0.9rem;
            display: flex;
            gap: 15px;
            min-width: 250px;
            justify-content: center;
        }
        
        /* 中央通知面板 */
        #notification-center {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            z-index: 1000;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 10px;
            pointer-events: none;
        }
        
        /* 中央通知樣式 */
        .center-notification {
            background: rgba(0, 0, 0, 0.8);
            color: white;
            padding: 15px 25px;
            border-radius: 5px;
            max-width: 300px;
            text-align: center;
            transition: opacity 0.3s;
        }
        
        /* 隱藏側邊欄(可選,根據屏幕尺寸) */
        @media (max-width: 1024px) {
            #sidebar {
                display: none;
            }
            
            /* 如果隱藏了側邊欄,顯示一個簡化版的控制面板按鈕 */
            #toggle-controls {
                display: block;
            }
        }
        
        /* 移動端優化 */
        @media (max-width: 768px) {
            #header h1 {
                font-size: 1.8rem;
            }
            
            #block-selector {
                bottom: 10px;
                padding: 8px;
            }
            
            .block-option {
                width: 35px;
                height: 35px;
            }
        }
        
        /* 小屏幕優化 */
        @media (max-width: 480px) {
            #top-stats {
                flex-direction: column;
                gap: 5px;
                padding: 8px 12px;
                font-size: 0.8rem;
            }
        }
        
        // 在body中添加新的HTML元素
        <div id="game-container">
            <div id="canvas-container"></div>
            
            <div id="hud">
                <div id="crosshair"></div>
            </div>
            
            <!-- 中央信息面板 -->
            <div id="center-info">
                <div id="top-stats">
                    <div>FPS: <span id="fps-counter">0</span></div>
                    <div>已放置: <span id="blocks-placed">0</span></div>
                    <div>已破壞: <span id="blocks-broken">0</span></div>
                </div>
            </div>
            
            <div id="block-selector">
                <div class="block-option active" data-type="grass" style="background: #00aa00;"></div>
                <div class="block-option" data-type="stone" style="background: #888888;"></div>
                <div class="block-option" data-type="dirt" style="background: #d2691e;"></div>
                <div class="block-option" data-type="blue" style="background: #0000ff;"></div>
                <div class="block-option" data-type="red" style="background: #ff0000;"></div>
                <div class="block-option" data-type="yellow" style="background: #ffff00;"></div>
            </div>
            
            <!-- 保留世界信息面板但調整位置 -->
            <div id="world-info" style="position: absolute; top: 80px; left: 50%; transform: translateX(-50%); max-width: 250px;">
                <div class="section-title">世界信息</div>
                <div>地圖尺寸: 64x64</div>
                <div>方塊總數: <span id="block-count">0</span></div>
                <div>玩家位置: 
                    <span class="coordinate" id="player-pos">0, 0, 0</span>
                </div>
                <div>視角方向: 
                    <span class="coordinate" id="player-rot">0°, 0°</span>
                </div>
            </div>
            
            <!-- 中央通知容器 -->
            <div id="notification-center"></div>
        </div>
        
        // 修改showNotification函數使其在中央顯示
        showNotification(message) {
            // 創建通知元素
            const notification = document.createElement('div');
            notification.className = 'center-notification';
            notification.textContent = message;
            
            // 添加到中央通知容器
            const notificationCenter = document.getElementById('notification-center');
            notificationCenter.appendChild(notification);
            
            // 3秒後自動消失
            setTimeout(() => {
                notification.style.opacity = '0';
                setTimeout(() => {
                    notificationCenter.removeChild(notification);
                }, 300);
            }, 3000);
        }
        
        // 在setupControls方法中刪除或註釋掉以下代碼(因為我們已經將這些元素移到了新位置)
        // document.getElementById('stats')相關的HTML和CSS可以移除
        // document.getElementById('instructions')相關的HTML和CSS可以移除
    </div>
</div>

<div id="loading">
    <h2>正在生成世界...</h2>
    <div class="progress-bar">
        <div class="progress" id="loading-progress"></div>
    </div>
    <div id="loading-text">初始化中...</div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
    // 遊戲主類
    class BlockWorld {
        constructor() {
            this.scene = null;
            this.camera = null;
            this.renderer = null;
            this.raycaster = null;
            this.mouse = null;
            
            this.blocks = new Map();
            this.blockCount = 0;
            this.blocksPlaced = 0;
            this.blocksBroken = 0;
            
            this.currentBlockType = 'grass';
            this.blockMaterials = {
                grass: new THREE.MeshLambertMaterial({ color: 0x00aa00 }),
                stone: new THREE.MeshLambertMaterial({ color: 0x888888 }),
                dirt: new THREE.MeshLambertMaterial({ color: 0xd2691e }),
                blue: new THREE.MeshLambertMaterial({ color: 0x0000ff }),
                red: new THREE.MeshLambertMaterial({ color: 0xff0000 }),
                yellow: new THREE.MeshLambertMaterial({ color: 0xffff00 })
            };
            
            this.cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
            
            this.keys = {};
            this.moveSpeed = 0.1;
            this.mouseSensitivity = 0.002;
            
            this.pitch = 0;
            this.yaw = 0;
            
            this.mapSize = 64;
            this.worldHeight = 16;
            
            this.clock = new THREE.Clock();
            this.fps = 0;
            
            this.init();
        }
        
        init() {
            this.setupScene();
            this.setupLights();
            this.setupControls();
            this.generateWorld();
            this.animate();
            

// 隱藏加載界面

            setTimeout(() => {
                document.getElementById('loading').classList.add('hidden');
            }, 1000);
        }
        
        setupScene() {
            // 創建場景
            this.scene = new THREE.Scene();
            this.scene.background = new THREE.Color(0x87CEEB); // 天空藍
            
            // 創建相機
            this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
            this.camera.position.set(0, 10, 10);
            
            // 創建渲染器
            this.renderer = new THREE.WebGLRenderer({ antialias: true });
            this.renderer.setSize(window.innerWidth, window.innerHeight);
            this.renderer.shadowMap.enabled = true;
            document.getElementById('canvas-container').appendChild(this.renderer.domElement);
            
            // 射線檢測器
            this.raycaster = new THREE.Raycaster();
            this.mouse = new THREE.Vector2();
            
            // 添加簡單的地面網格
            const gridHelper = new THREE.GridHelper(this.mapSize, this.mapSize, 0x444444, 0x222222);
            gridHelper.position.y = -0.5;
            this.scene.add(gridHelper);
        }
        
        setupLights() {
            // 環境光
            const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
            this.scene.add(ambientLight);
            
            // 方向光(太陽)
            const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
            directionalLight.position.set(50, 50, 25);
            directionalLight.castShadow = true;
            directionalLight.shadow.mapSize.width = 2048;
            directionalLight.shadow.mapSize.height = 2048;
            directionalLight.shadow.camera.near = 0.5;
            directionalLight.shadow.camera.far = 500;
            directionalLight.shadow.camera.left = -100;
            directionalLight.shadow.camera.right = 100;
            directionalLight.shadow.camera.top = 100;
            directionalLight.shadow.camera.bottom = -100;
            this.scene.add(directionalLight);
        }
        
        setupControls() {
            // 鼠標移動事件
            document.addEventListener('mousemove', (event) => {
                if (document.pointerLockElement === this.renderer.domElement) {
                    this.yaw -= event.movementX * this.mouseSensitivity;
                    this.pitch = Math.max(-Math.PI/2, Math.min(Math.PI/2, 
                        this.pitch - event.movementY * this.mouseSensitivity));
                    
                    this.camera.rotation.order = 'YXZ';
                    this.camera.rotation.y = this.yaw;
                    this.camera.rotation.x = this.pitch;
                }
            });
            
            // 鼠標點擊事件
            this.renderer.domElement.addEventListener('click', () => {
                if (document.pointerLockElement !== this.renderer.domElement) {
                    this.renderer.domElement.requestPointerLock();
                }
            });

document.addEventListener('mousedown', (event) => {

                if (document.pointerLockElement !== this.renderer.domElement) return;
                
                this.mouse.x = 0;
                this.mouse.y = 0;
                
                const intersection = this.getBlockIntersection();
                
                if (intersection) {
                    if (event.button === 0) { // 左鍵 - 放置方塊
                        const pos = this.getAdjacentPosition(intersection);
                        this.addBlock(pos.x, pos.y, pos.z, this.currentBlockType);
                        this.blocksPlaced++;
                        document.getElementById('blocks-placed').textContent = this.blocksPlaced;
                    } else if (event.button === 2) { // 右鍵 - 破壞方塊
                        const object = intersection.object;
                        if (this.removeBlock(object.position.x, object.position.y, object.position.z)) {
                            this.blocksBroken++;
                            document.getElementById('blocks-broken').textContent = this.blocksBroken;
                        }
                    }
                }
                
                event.preventDefault();
            });
            
            // 阻止右鍵菜單
            document.addEventListener('contextmenu', (event) => {
                event.preventDefault();
            });
            
            // 鍵盤事件
            document.addEventListener('keydown', (event) => {
                this.keys[event.code] = true;
                
                // 方塊類型切換
                if (event.code >= 'Digit1' && event.code <= 'Digit6') {
                    const types = ['grass', 'stone', 'dirt', 'blue', 'red', 'yellow'];
                    this.currentBlockType = types[parseInt(event.code[5]) - 1];
                    this.updateBlockSelector();
                }
            });
            
            document.addEventListener('keyup', (event) => {
                this.keys[event.code] = false;
            });
            
            // 窗口大小調整
            window.addEventListener('resize', () => {
                this.camera.aspect = window.innerWidth / window.innerHeight;
                this.camera.updateProjectionMatrix();
                this.renderer.setSize(window.innerWidth, window.innerHeight);
            });
            
            // 重置世界按鈕
            document.getElementById('reset-btn').addEventListener('click', () => {
                if (confirm('確定要重置世界嗎?所有方塊將被清除。')) {
                    this.resetWorld();
                }
            });
            
            // 保存/加載按鈕
            document.getElementById('save-btn').addEventListener('click', () => {
                this.saveWorld();
            });
            
            document.getElementById('load-btn').addEventListener('click', () => {
                this.loadWorld();
            });
        }
        
        generateWorld() {
            const progressBar = document.getElementById('loading-progress');
            const loadingText = document.getElementById('loading-text');
            
            // 生成地面
            loadingText.textContent = '生成地面...';
            for (let x = -this.mapSize/2; x < this.mapSize/2; x++) {
                for (let z = -this.mapSize/2; z < this.mapSize/2; z++) {
                    // 簡單的高度圖生成
                    const height = Math.floor(Math.sin(x/10) * Math.cos(z/10) * 3) + 5;

// 生成地面方塊

                    for (let y = 0; y < height; y++) {
                        const type = y === height - 1 ? 'grass' : 
                                    y > height - 4 ? 'dirt' : 'stone';
                        this.addBlock(x, y, z, type);
                    }
                    
                    // 更新進度條
                    const progress = ((x + this.mapSize/2) / this.mapSize) * 100;
                    progressBar.style.width = `${progress}%`;
                }
            }
            
            // 生成一些隨機結構
            loadingText.textContent = '生成隨機結構...';
            for (let i = 0; i < 20; i++) {
                const x = Math.floor(Math.random() * this.mapSize) - this.mapSize/2;
                const z = Math.floor(Math.random() * this.mapSize) - this.mapSize/2;
                const height = this.getHeightAt(x, z) + 1;
                
                // 生成樹或石柱
                if (Math.random() > 0.5) {
                    // 生成樹
                    this.generateTree(x, height, z);
                } else {
                    // 生成石柱
                    this.generateStonePillar(x, height, z);
                }
                
                progressBar.style.width = `${100 + (i/20)*100}%`;
            }
            
            loadingText.textContent = '世界生成完成!';
        }
        
        getHeightAt(x, z) {
            // 簡單的高度查詢
            for (let y = this.worldHeight - 1; y >= 0; y--) {
                if (this.blocks.has(`${x},${y},${z}`)) {
                    return y;
                }
            }
            return -1;
        }
        
        generateTree(x, y, z) {
            // 生成樹幹(3-5格高)
            const trunkHeight = 3 + Math.floor(Math.random() * 3);
            for (let i = 0; i < trunkHeight; i++) {
                this.addBlock(x, y + i, z, 'dirt');
            }
            
            // 生成樹葉
            const leafLevel = y + trunkHeight;
            for (let dx = -2; dx <= 2; dx++) {
                for (let dz = -2; dz <= 2; dz++) {
                    for (let dy = 0; dy < 3; dy++) {
                        // 簡單的球形樹葉
                        if (dx*dx + dz*dz + dy*dy <= 4) {
                            this.addBlock(x + dx, leafLevel + dy, z + dz, 'grass');
                        }
                    }
                }
            }
        }

generateStonePillar(x, y, z) {

            // 生成石柱(5-8格高)
            const height = 5 + Math.floor(Math.random() * 4);
            for (let i = 0; i < height; i++) {
                this.addBlock(x, y + i, z, 'stone');
                
                // 隨機添加一些側邊方塊
                if (Math.random() > 0.7) {
                    const side = Math.floor(Math.random() * 4);
                    const offsets = [[1,0], [-1,0], [0,1], [0,-1]];
                    this.addBlock(x + offsets[side][0], y + i, z + offsets[side][1], 'stone');
                }
            }
        }
        
        addBlock(x, y, z, type) {
            const key = `${x},${y},${z}`;
            
            // 如果該位置已有方塊,先移除
            if (this.blocks.has(key)) {
                this.scene.remove(this.blocks.get(key));
                this.blocks.delete(key);
                this.blockCount--;
            }
            
            const cube = new THREE.Mesh(this.cubeGeometry, this.blockMaterials[type]);
            cube.position.set(x, y, z);
            cube.castShadow = true;
            cube.receiveShadow = true;
            cube.userData = { type: type };
            
            this.scene.add(cube);
            this.blocks.set(key, cube);
            this.blockCount++;
            
            document.getElementById('block-count').textContent = this.blockCount;
            
            return cube;
        }
        
        removeBlock(x, y, z) {
            const key = `${x},${y},${z}`;
            if (this.blocks.has(key)) {
                this.scene.remove(this.blocks.get(key));
                this.blocks.delete(key);
                this.blockCount--;
                document.getElementById('block-count').textContent = this.blockCount;
                return true;
            }
            return false;
        }
        
        getBlockIntersection() {
            this.raycaster.setFromCamera(this.mouse, this.camera);
            const intersections = this.raycaster.intersectObjects(Array.from(this.blocks.values()));
            return intersections.length > 0 ? intersections[0] : null;
        }
        
        getAdjacentPosition(intersection) {
            const normal = intersection.face.normal.clone();
            normal.transformDirection(intersection.object.matrixWorld);
            
            return {
                x: Math.round(intersection.object.position.x + normal.x),
                y: Math.round(intersection.object.position.y + normal.y),
                z: Math.round(intersection.object.position.z + normal.z)
            };
        }
        
        updateBlockSelector() {
            document.querySelectorAll('.block-option').forEach(option => {
                option.classList.remove('active');
                if (option.dataset.type === this.currentBlockType) {
                    option.classList.add('active');
                }
            });
        }
        
        resetWorld() {
            // 移除所有方塊
            this.blocks.forEach(block => {
                this.scene.remove(block);
            });
            this.blocks.clear();
            this.blockCount = 0;
            this.blocksPlaced = 0;
            this.blocksBroken = 0;
            
            document.getElementById('block-count').textContent = '0';
            document.getElementById('blocks-placed').textContent = '0';
            document.getElementById('blocks-broken').textContent = '0';
            
            // 重新生成世界
            this.generateWorld();
        }
        
        // 優化保存功能 - 添加版本控制和更完善的錯誤處理
        saveWorld() {
            try {
                const worldData = {
                    version: '1.0.0', // 添加版本號便於未來更新
                    timestamp: new Date().toISOString(),
                    blocks: [],
                    player: {
                        position: this.camera.position.toArray(),
                        rotation: [this.camera.rotation.x, this.camera.rotation.y, this.camera.rotation.z],
                        currentBlock: this.currentBlockType
                    },
                    stats: {
                        blocksPlaced: this.blocksPlaced,
                        blocksBroken: this.blocksBroken,
                        blockCount: this.blockCount
                    }
                };
                
                this.blocks.forEach((block, key) => {
                    const [x, y, z] = key.split(',').map(Number);
                    worldData.blocks.push({ x, y, z, type: block.userData.type });
                });
                
                // 使用 try-catch 防止 localStorage 滿
                localStorage.setItem('blockWorld', JSON.stringify(worldData));
                
                // 顯示保存成功的提示而不是 alert
                this.showNotification('世界保存成功!');
            } catch (error) {
                console.error('保存失敗:', error);
                this.showNotification('保存失敗,請嘗試減少世界大小或清除瀏覽器數據。');
            }
        }
        
        // 優化加載功能 - 添加版本兼容性檢查
        loadWorld() {
            try {
                const savedData = localStorage.getItem('blockWorld');
                if (!savedData) {
                    this.showNotification('沒有找到保存的世界!');
                    return;
                }
                
                if (!confirm('加載世界將替換當前世界,確定要繼續嗎?')) {
                    return;
                }
                
                // 清除當前世界
                this.blocks.forEach(block => {
                    this.scene.remove(block);
                });
                this.blocks.clear();
                this.blockCount = 0;
                
                const worldData = JSON.parse(savedData);
                
                // 加載方塊
                worldData.blocks.forEach(blockData => {
                    this.addBlock(blockData.x, blockData.y, blockData.z, blockData.type);
                });
                
                // 加載玩家數據
                if (worldData.player) {
                    this.camera.position.fromArray(worldData.player.position);
                    this.camera.rotation.fromArray(worldData.player.rotation);
                    this.yaw = this.camera.rotation.y;
                    this.pitch = this.camera.rotation.x;
                    
                    // 恢復當前選中的方塊類型
                    if (worldData.player.currentBlock) {
                        this.currentBlockType = worldData.player.currentBlock;
                        this.updateBlockSelector();
                    }
                }
                
                // 恢復統計數據
                if (worldData.stats) {
                    this.blocksPlaced = worldData.stats.blocksPlaced || 0;
                    this.blocksBroken = worldData.stats.blocksBroken || 0;
                    document.getElementById('blocks-placed').textContent = this.blocksPlaced;
                    document.getElementById('blocks-broken').textContent = this.blocksBroken;
                }
                
                this.showNotification('世界加載完成!');
            } catch (error) {
                console.error('加載失敗:', error);
                this.showNotification('加載失敗,保存文件可能已損壞。');
            }
        }
        
        // 添加一個更友好的通知函數
        showNotification(message) {
            // 創建通知元素
            const notification = document.createElement('div');
            notification.style.position = 'fixed';
            notification.style.top = '20px';
            notification.style.right = '20px';
            notification.style.background = 'rgba(0, 0, 0, 0.8)';
            notification.style.color = 'white';
            notification.style.padding = '10px 20px';
            notification.style.borderRadius = '5px';
            notification.style.zIndex = '1000';
            notification.style.transition = 'opacity 0.3s';
            notification.textContent = message;
            
            document.body.appendChild(notification);
            
            // 3秒後自動消失
            setTimeout(() => {
                notification.style.opacity = '0';
                setTimeout(() => {
                    document.body.removeChild(notification);
                }, 300);
            }, 3000);
        }
        animate() {
            requestAnimationFrame(() => this.animate());
            
            // 計算FPS
            this.fps = 1 / this.clock.getDelta();
            document.getElementById('fps-counter').textContent = Math.round(this.fps);
            
            // 玩家移動
            this.handleMovement();
            
            // 更新玩家位置顯示
            document.getElementById('player-pos').textContent = 
                `${Math.round(this.camera.position.x)}, ${Math.round(this.camera.position.y)}, ${Math.round(this.camera.position.z)}`;
            
            document.getElementById('player-rot').textContent = 
                `${Math.round(this.camera.rotation.x * 180/Math.PI)}°, ${Math.round(this.camera.rotation.y * 180/Math.PI)}°`;
            
            this.renderer.render(this.scene, this.camera);
        }
        
        handleMovement() {
            if (this.keys['KeyW']) { // 前
                this.camera.position.x -= Math.sin(this.yaw) * this.moveSpeed;
                this.camera.position.z -= Math.cos(this.yaw) * this.moveSpeed;
            }
            if (this.keys['KeyS']) { // 後
                this.camera.position.x += Math.sin(this.yaw) * this.moveSpeed;
                this.camera.position.z += Math.cos(this.yaw) * this.moveSpeed;
            }
            if (this.keys['KeyA']) { // 左
                this.camera.position.x -= Math.cos(this.yaw) * this.moveSpeed;
                this.camera.position.z += Math.sin(this.yaw) * this.moveSpeed;
            }
            if (this.keys['KeyD']) { // 右
                this.camera.position.x += Math.cos(this.yaw) * this.moveSpeed;
                this.camera.position.z -= Math.sin(this.yaw) * this.moveSpeed;
            }
            if (this.keys['Space']) { // 上
                this.camera.position.y += this.moveSpeed;
            }
            if (this.keys['ShiftLeft'] || this.keys['ShiftRight']) { // 下
                this.camera.position.y -= this.moveSpeed;
            }
        }
    }
    
    // 頁面加載完成後初始化遊戲
    window.addEventListener('load', () => {
        new BlockWorld();
    });
</script>

</body>
</html>

user avatar u_16281588 Avatar muzijun_68c14af5563a2 Avatar momeak9 Avatar liutos Avatar hedzr Avatar bianchengdandan Avatar wunima Avatar keen_626105e1ef632 Avatar chongdongdedaxiongmao_kxfei Avatar
Favorites 9 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.