第37节:移动端优化与触控交互

第37节:移动端优化与触控交互

概述

移动端3D应用开发面临着性能限制、触控交互、电池续航等多重挑战。本节将深入探索移动端优化的核心技术,包括性能分析工具、渲染优化策略、触控交互设计,以及跨平台适配方案,打造流畅的移动端3D体验。

移动端优化系统架构:

flowchard TD A[移动端优化系统] --> B[性能监控] A --> C[渲染优化] A --> D[触控交互] A --> E[资源管理] B --> B1[帧率监控] B --> B2[内存分析] B --> B3[功耗控制] C --> C1[LOD系统] C --> C2[分辨率缩放] C --> C3[批次合并] D --> D1[手势识别] D --> D2[触觉反馈] D --> D3[自适应UI] E --> E1[资源压缩] E --> E2[流式加载] E --> E3[缓存策略] B1 --> F[性能稳定] C1 --> G[流畅渲染] D1 --> H[自然交互] E1 --> I[快速加载]

核心原理深度解析

移动端性能瓶颈分析

移动设备与桌面设备的性能差异:

性能指标 高端手机 中端手机 低端手机 桌面电脑
GPU性能 1.5 TFLOPS 0.5 TFLOPS 0.2 TFLOPS 10+ TFLOPS
内存带宽 50 GB/s 25 GB/s 12 GB/s 500+ GB/s
电池容量 4000 mAh 3000 mAh 2000 mAh 无限制
热限制 严格 中等 宽松 宽松

移动端渲染优化技术对比

优化技术 原理 性能提升 质量影响 实现复杂度
动态分辨率 根据帧率调整分辨率 30-50% 轻微 简单
LOD系统 距离相关细节层次 20-40% 可控 中等
批次合并 减少绘制调用 40-60% 复杂
纹理压缩 使用压缩纹理格式 20-30% 轻微 简单
遮挡剔除 跳过不可见物体 10-50% 复杂

完整代码实现

移动端优化3D应用

vue 复制代码
<template>
  <div class="mobile-optimization-container">
    <!-- 3D场景画布 -->
    <canvas ref="mobileCanvas" class="mobile-canvas"></canvas>
    
    <!-- 移动端控制面板 -->
    <div class="mobile-controls" :class="{ 'controls-collapsed': controlsCollapsed }">
      <div class="controls-header" @click="toggleControls">
        <h3>📱 移动端优化</h3>
        <span class="collapse-icon">{{ controlsCollapsed ? '▶' : '▼' }}</span>
      </div>
      
      <div v-if="!controlsCollapsed" class="controls-content">
        <div class="control-section">
          <h4>🎯 性能设置</h4>
          
          <div class="performance-presets">
            <button 
              v-for="preset in performancePresets" 
              :key="preset.id"
              @click="applyPerformancePreset(preset)"
              class="preset-button"
              :class="{ active: currentPreset?.id === preset.id }"
            >
              {{ preset.name }}
            </button>
          </div>
          
          <div class="control-group">
            <label>目标帧率: {{ targetFPS }} FPS</label>
            <input 
              type="range" 
              v-model="targetFPS" 
              min="30" 
              max="120" 
              step="10"
            >
          </div>
          
          <div class="control-group">
            <label>分辨率缩放: {{ resolutionScale }}%</label>
            <input 
              type="range" 
              v-model="resolutionScale" 
              min="25" 
              max="100" 
              step="5"
            >
          </div>
        </div>

        <div class="control-section">
          <h4>🖐️ 触控设置</h4>
          
          <div class="touch-controls">
            <div class="control-group">
              <label>触控灵敏度: {{ touchSensitivity }}</label>
              <input 
                type="range" 
                v-model="touchSensitivity" 
                min="0.5" 
                max="2" 
                step="0.1"
              >
            </div>
            
            <div class="control-group">
              <label>惯性滚动: {{ inertiaStrength }}</label>
              <input 
                type="range" 
                v-model="inertiaStrength" 
                min="0" 
                max="1" 
                step="0.1"
              >
            </div>
          </div>
          
          <div class="gesture-controls">
            <div class="control-group">
              <label>启用捏合缩放</label>
              <input type="checkbox" v-model="pinchZoomEnabled">
            </div>
            
            <div class="control-group">
              <label>启用旋转</label>
              <input type="checkbox" v-model="rotationEnabled">
            </div>
            
            <div class="control-group">
              <label>启用双击重置</label>
              <input type="checkbox" v-model="doubleTapResetEnabled">
            </div>
          </div>
        </div>

        <div class="control-section">
          <h4>⚡ 渲染优化</h4>
          
          <div class="rendering-optimizations">
            <div class="control-group">
              <label>LOD级别: {{ lodLevel }}</label>
              <input 
                type="range" 
                v-model="lodLevel" 
                min="1" 
                max="4" 
                step="1"
              >
            </div>
            
            <div class="control-group">
              <label>阴影质量: {{ shadowQuality }}</label>
              <input 
                type="range" 
                v-model="shadowQuality" 
                min="0" 
                max="3" 
                step="1"
              >
            </div>
            
            <div class="control-group">
              <label>抗锯齿: {{ antiAliasing }}</label>
              <input 
                type="range" 
                v-model="antiAliasing" 
                min="0" 
                max="2" 
                step="1"
              >
            </div>
          </div>
          
          <div class="optimization-toggles">
            <div class="control-group">
              <label>启用批次合并</label>
              <input type="checkbox" v-model="batchingEnabled">
            </div>
            
            <div class="control-group">
              <label>启用视锥剔除</label>
              <input type="checkbox" v-model="frustumCullingEnabled">
            </div>
            
            <div class="control-group">
              <label>启用纹理压缩</label>
              <input type="checkbox" v-model="textureCompressionEnabled">
            </div>
          </div>
        </div>

        <div class="control-section">
          <h4>🔋 电池优化</h4>
          
          <div class="battery-optimizations">
            <div class="control-group">
              <label>功耗模式: {{ powerMode }}</label>
              <select v-model="powerMode" class="mode-select">
                <option value="performance">性能优先</option>
                <option value="balanced">平衡模式</option>
                <option value="battery">省电模式</option>
              </select>
            </div>
            
            <div class="control-group">
              <label>后台暂停: {{ backgroundPauseDelay }}s</label>
              <input 
                type="range" 
                v-model="backgroundPauseDelay" 
                min="1" 
                max="10" 
                step="1"
              >
            </div>
          </div>
          
          <div class="thermal-controls">
            <div class="control-group">
              <label>温度限制: {{ thermalLimit }}°C</label>
              <input 
                type="range" 
                v-model="thermalLimit" 
                min="40" 
                max="60" 
                step="5"
              >
            </div>
          </div>
        </div>

        <div class="control-section">
          <h4>📊 性能监控</h4>
          <div class="performance-stats">
            <div class="stat-item">
              <span>当前帧率:</span>
              <span :class="getFPSClass(currentFPS)">{{ currentFPS }} FPS</span>
            </div>
            <div class="stat-item">
              <span>帧时间:</span>
              <span>{{ frameTime.toFixed(1) }}ms</span>
            </div>
            <div class="stat-item">
              <span>内存使用:</span>
              <span>{{ formatMemory(memoryUsage) }}</span>
            </div>
            <div class="stat-item">
              <span>绘制调用:</span>
              <span>{{ drawCalls }}</span>
            </div>
            <div class="stat-item">
              <span>三角形数量:</span>
              <span>{{ formatNumber(triangleCount) }}</span>
            </div>
            <div class="stat-item">
              <span>电池状态:</span>
              <span :class="getBatteryClass(batteryLevel)">{{ batteryLevel }}%</span>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 触控控制区域 -->
    <div class="touch-control-area">
      <div class="virtual-joystick" 
           @touchstart="onJoystickStart" 
           @touchmove="onJoystickMove" 
           @touchend="onJoystickEnd">
        <div class="joystick-base">
          <div class="joystick-handle" :style="joystickStyle"></div>
        </div>
      </div>
      
      <div class="action-buttons">
        <button class="action-button jump" @touchstart="onJumpTouch">跳跃</button>
        <button class="action-button interact" @touchstart="onInteractTouch">交互</button>
      </div>
    </div>

    <!-- 手势提示 -->
    <div class="gesture-hints" v-if="showGestureHints">
      <div class="hint-item">
        <span class="hint-icon">🤏</span>
        <span>捏合缩放</span>
      </div>
      <div class="hint-item">
        <span class="hint-icon">👆</span>
        <span>拖拽旋转</span>
      </div>
      <div class="hint-item">
        <span class="hint-icon">👆👆</span>
        <span>双击重置</span>
      </div>
    </div>

    <!-- 性能警告 -->
    <div v-if="showPerformanceWarning" class="performance-warning">
      <div class="warning-content">
        <span class="warning-icon">⚠️</span>
        <span>性能警告: 帧率过低 ({{ currentFPS }} FPS)</span>
        <button @click="applyPerformancePreset(performancePresets[2])" class="optimize-button">
          自动优化
        </button>
      </div>
    </div>

    <!-- 电池警告 -->
    <div v-if="showBatteryWarning" class="battery-warning">
      <div class="warning-content">
        <span class="warning-icon">🔋</span>
        <span>电池电量低 ({{ batteryLevel }}%)</span>
        <button @click="enablePowerSaving" class="power-save-button">
          开启省电模式
        </button>
      </div>
    </div>

    <!-- 加载界面 -->
    <div v-if="isLoading" class="loading-overlay">
      <div class="loading-content">
        <div class="mobile-loader">
          <div class="phone-frame">
            <div class="screen-content">
              <div class="loading-bar"></div>
              <div class="loading-dots">
                <div class="dot"></div>
                <div class="dot"></div>
                <div class="dot"></div>
              </div>
            </div>
          </div>
        </div>
        <h3>优化移动端体验...</h3>
        <div class="loading-progress">
          <div class="progress-bar">
            <div class="progress-fill" :style="loadingProgressStyle"></div>
          </div>
          <span>{{ loadingMessage }}</span>
        </div>
        <div class="optimization-stats">
          <div class="stat">压缩纹理: {{ compressedTextures }}/{{ totalTextures }}</div>
          <div class="stat">优化网格: {{ optimizedMeshes }}/{{ totalMeshes }}</div>
          <div class="stat">加载资源: {{ formatMemory(loadedMemory) }}/{{ formatMemory(totalMemory) }}</div>
        </div>
      </div>
    </div>

    <!-- 调试信息 -->
    <div class="debug-overlay" v-if="showDebugOverlay">
      <div class="debug-info">
        <div>设备: {{ deviceInfo }}</div>
        <div>GPU: {{ gpuInfo }}</div>
        <div>平台: {{ platformInfo }}</div>
        <div>触控点: {{ touchPoints }} 个</div>
        <div>温度: {{ deviceTemperature }}°C</div>
      </div>
    </div>

    <!-- 快捷操作栏 -->
    <div class="quick-actions">
      <button @click="toggleDebug" class="quick-button" :class="{ active: showDebugOverlay }">
        🐛
      </button>
      <button @click="toggleStats" class="quick-button" :class="{ active: showStats }">
        📊
      </button>
      <button @click="screenshot" class="quick-button">
        📸
      </button>
      <button @click="toggleFullscreen" class="quick-button">
        {{ isFullscreen ? '📱' : '🔲' }}
      </button>
    </div>
  </div>
</template>

<script>
import { onMounted, onUnmounted, ref, reactive, computed } from 'vue';
import * as THREE from 'three';

// 移动端性能监控器
class MobilePerformanceMonitor {
  constructor() {
    this.fpsHistory = [];
    this.frameTimeHistory = [];
    this.memoryHistory = [];
    this.maxHistorySize = 60; // 保存60帧数据
    
    this.lowFPSThreshold = 30;
    this.highFrameTimeThreshold = 33; // 对应30FPS
    this.memoryWarningThreshold = 100 * 1024 * 1024; // 100MB
    
    this.startTime = performance.now();
    this.frameCount = 0;
  }

  // 开始监控
  start() {
    this.startTime = performance.now();
    this.frameCount = 0;
  }

  // 更新监控数据
  update() {
    const currentTime = performance.now();
    const frameTime = currentTime - this.lastFrameTime || 0;
    this.lastFrameTime = currentTime;

    // 计算FPS
    this.frameCount++;
    if (currentTime - this.startTime >= 1000) {
      const fps = Math.round((this.frameCount * 1000) / (currentTime - this.startTime));
      this.fpsHistory.push(fps);
      if (this.fpsHistory.length > this.maxHistorySize) {
        this.fpsHistory.shift();
      }
      
      this.frameCount = 0;
      this.startTime = currentTime;
    }

    // 记录帧时间
    this.frameTimeHistory.push(frameTime);
    if (this.frameTimeHistory.length > this.maxHistorySize) {
      this.frameTimeHistory.shift();
    }

    return {
      fps: this.fpsHistory[this.fpsHistory.length - 1] || 0,
      frameTime: frameTime,
      averageFPS: this.getAverageFPS(),
      averageFrameTime: this.getAverageFrameTime()
    };
  }

  // 获取平均FPS
  getAverageFPS() {
    if (this.fpsHistory.length === 0) return 0;
    return Math.round(this.fpsHistory.reduce((a, b) => a + b) / this.fpsHistory.length);
  }

  // 获取平均帧时间
  getAverageFrameTime() {
    if (this.frameTimeHistory.length === 0) return 0;
    return this.frameTimeHistory.reduce((a, b) => a + b) / this.frameTimeHistory.length;
  }

  // 检查性能问题
  checkPerformanceIssues() {
    const currentFPS = this.fpsHistory[this.fpsHistory.length - 1] || 0;
    const averageFrameTime = this.getAverageFrameTime();
    
    const issues = [];
    
    if (currentFPS < this.lowFPSThreshold) {
      issues.push({
        type: 'low_fps',
        severity: currentFPS < 20 ? 'high' : 'medium',
        message: `帧率过低: ${currentFPS} FPS`
      });
    }
    
    if (averageFrameTime > this.highFrameTimeThreshold) {
      issues.push({
        type: 'high_frame_time',
        severity: 'medium',
        message: `帧时间过长: ${averageFrameTime.toFixed(1)}ms`
      });
    }
    
    return issues;
  }

  // 获取性能建议
  getPerformanceSuggestions(issues) {
    const suggestions = [];
    
    if (issues.some(issue => issue.type === 'low_fps')) {
      suggestions.push('降低分辨率缩放');
      suggestions.push('减少阴影质量');
      suggestions.push('启用批次合并');
    }
    
    if (issues.some(issue => issue.type === 'high_frame_time')) {
      suggestions.push('简化场景复杂度');
      suggestions.push('启用LOD系统');
      suggestions.push('减少绘制调用');
    }
    
    return suggestions;
  }
}

// 移动端触控控制器
class MobileTouchController {
  constructor(domElement, camera, renderer) {
    this.domElement = domElement;
    this.camera = camera;
    this.renderer = renderer;
    
    this.touchState = {
      isRotating: false,
      isZooming: false,
      isPanning: false,
      lastTouchX: 0,
      lastTouchY: 0,
      scale: 1,
      touches: []
    };
    
    this.sensitivity = 1.0;
    this.inertia = 0.9;
    this.velocity = new THREE.Vector2();
    
    this.setupEventListeners();
  }

  // 设置事件监听器
  setupEventListeners() {
    this.domElement.addEventListener('touchstart', this.onTouchStart.bind(this), { passive: false });
    this.domElement.addEventListener('touchmove', this.onTouchMove.bind(this), { passive: false });
    this.domElement.addEventListener('touchend', this.onTouchEnd.bind(this), { passive: false });
    this.domElement.addEventListener('touchcancel', this.onTouchEnd.bind(this), { passive: false });
  }

  // 触摸开始
  onTouchStart(event) {
    event.preventDefault();
    
    this.touchState.touches = Array.from(event.touches);
    
    if (event.touches.length === 1) {
      // 单指触摸 - 旋转
      this.touchState.isRotating = true;
      this.touchState.lastTouchX = event.touches[0].clientX;
      this.touchState.lastTouchY = event.touches[0].clientY;
    } else if (event.touches.length === 2) {
      // 双指触摸 - 缩放/平移
      this.touchState.isZooming = true;
      this.touchState.lastTouchDistance = this.getTouchDistance(event.touches);
    }
    
    // 重置速度
    this.velocity.set(0, 0);
  }

  // 触摸移动
  onTouchMove(event) {
    event.preventDefault();
    
    const touches = Array.from(event.touches);
    this.touchState.touches = touches;
    
    if (this.touchState.isRotating && touches.length === 1) {
      this.handleRotation(touches[0]);
    } else if (this.touchState.isZooming && touches.length === 2) {
      this.handleZoom(touches);
    }
    
    // 更新最后触摸位置
    if (touches.length === 1) {
      this.touchState.lastTouchX = touches[0].clientX;
      this.touchState.lastTouchY = touches[0].clientY;
    }
  }

  // 触摸结束
  onTouchEnd(event) {
    event.preventDefault();
    
    const touches = Array.from(event.touches);
    this.touchState.touches = touches;
    
    if (touches.length === 0) {
      // 所有手指抬起
      this.touchState.isRotating = false;
      this.touchState.isZooming = false;
      this.touchState.isPanning = false;
    } else if (touches.length === 1) {
      // 从双指变为单指
      this.touchState.isZooming = false;
      this.touchState.isRotating = true;
      this.touchState.lastTouchX = touches[0].clientX;
      this.touchState.lastTouchY = touches[0].clientY;
    }
  }

  // 处理旋转
  handleRotation(touch) {
    const deltaX = (touch.clientX - this.touchState.lastTouchX) * this.sensitivity * 0.01;
    const deltaY = (touch.clientY - this.touchState.lastTouchY) * this.sensitivity * 0.01;
    
    // 更新相机旋转
    if (this.camera.rotation) {
      this.camera.rotation.y -= deltaX;
      this.camera.rotation.x -= deltaY;
      this.camera.rotation.x = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, this.camera.rotation.x));
    }
    
    // 更新速度
    this.velocity.x = deltaX;
    this.velocity.y = deltaY;
  }

  // 处理缩放
  handleZoom(touches) {
    const currentDistance = this.getTouchDistance(touches);
    const deltaDistance = currentDistance - this.touchState.lastTouchDistance;
    
    // 更新缩放
    const zoomFactor = 1 + deltaDistance * 0.01;
    if (this.camera.zoom !== undefined) {
      this.camera.zoom = Math.max(0.1, Math.min(5, this.camera.zoom * zoomFactor));
      this.camera.updateProjectionMatrix();
    }
    
    this.touchState.lastTouchDistance = currentDistance;
  }

  // 获取触摸点距离
  getTouchDistance(touches) {
    const dx = touches[0].clientX - touches[1].clientX;
    const dy = touches[0].clientY - touches[1].clientY;
    return Math.sqrt(dx * dx + dy * dy);
  }

  // 更新惯性
  update(deltaTime) {
    if (!this.touchState.isRotating && (Math.abs(this.velocity.x) > 0.001 || Math.abs(this.velocity.y) > 0.001)) {
      // 应用惯性
      if (this.camera.rotation) {
        this.camera.rotation.y -= this.velocity.x * deltaTime * 10;
        this.camera.rotation.x -= this.velocity.y * deltaTime * 10;
        this.camera.rotation.x = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, this.camera.rotation.x));
      }
      
      // 衰减速度
      this.velocity.multiplyScalar(this.inertia);
    }
  }

  // 设置灵敏度
  setSensitivity(sensitivity) {
    this.sensitivity = sensitivity;
  }

  // 设置惯性
  setInertia(inertia) {
    this.inertia = inertia;
  }
}

// 移动端渲染优化器
class MobileRenderOptimizer {
  constructor(renderer, scene, camera) {
    this.renderer = renderer;
    this.scene = scene;
    this.camera = camera;
    
    this.optimizationState = {
      resolutionScale: 1.0,
      lodEnabled: true,
      shadowsEnabled: true,
      shadowsQuality: 1,
      batchingEnabled: false,
      textureCompressionEnabled: true
    };
    
    this.setupOptimizations();
  }

  // 设置优化
  setupOptimizations() {
    // 设置移动端友好的渲染参数
    this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    this.renderer.physicallyCorrectLights = false;
    this.renderer.toneMapping = THREE.ACESFilmicToneMapping;
    this.renderer.toneMappingExposure = 1.0;
    
    // 启用基本的优化
    this.enableBasicOptimizations();
  }

  // 启用基础优化
  enableBasicOptimizations() {
    // 使用更高效的阴影映射
    if (this.optimizationState.shadowsEnabled) {
      this.renderer.shadowMap.enabled = true;
      this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    }
    
    // 设置适当的抗锯齿
    this.renderer.antialias = this.optimizationState.resolutionScale >= 0.7;
  }

  // 应用分辨率缩放
  applyResolutionScale(scale) {
    this.optimizationState.resolutionScale = scale;
    
    const width = Math.floor(window.innerWidth * scale);
    const height = Math.floor(window.innerHeight * scale);
    
    this.renderer.setSize(width, height, false);
    
    if (this.camera.isPerspectiveCamera) {
      this.camera.aspect = width / height;
      this.camera.updateProjectionMatrix();
    }
  }

  // 应用LOD优化
  applyLODOptimization(level) {
    this.scene.traverse((object) => {
      if (object.isMesh && object.geometry) {
        // 根据LOD级别简化几何体
        const detailLevel = Math.max(1, Math.floor(level));
        this.optimizeGeometry(object.geometry, detailLevel);
      }
    });
  }

  // 优化几何体
  optimizeGeometry(geometry, level) {
    // 简化实现 - 实际应该使用更复杂的LOD系统
    if (level < 3 && geometry.attributes.position && geometry.attributes.position.count > 500) {
      // 对于复杂网格,可以在这里应用简化
      // 实际实现应该使用 THREE.SimplifyModifier 或类似工具
    }
  }

  // 应用阴影质量设置
  applyShadowQuality(quality) {
    this.optimizationState.shadowsQuality = quality;
    
    this.scene.traverse((object) => {
      if (object.isLight && object.shadow) {
        const resolution = this.getShadowResolution(quality);
        object.shadow.mapSize.set(resolution, resolution);
        object.shadow.needsUpdate = true;
      }
    });
  }

  // 获取阴影分辨率
  getShadowResolution(quality) {
    switch (quality) {
      case 0: return 512;  // 低质量
      case 1: return 1024; // 中等质量
      case 2: return 2048; // 高质量
      case 3: return 4096; // 超高质量
      default: return 1024;
    }
  }

  // 应用批次合并
  applyBatchingOptimization() {
    if (!this.optimizationState.batchingEnabled) return;
    
    // 简化实现 - 实际应该使用 THREE.BufferGeometryUtils.mergeBufferGeometries
    console.log('应用批次合并优化...');
  }

  // 应用纹理压缩
  applyTextureCompression() {
    if (!this.optimizationState.textureCompressionEnabled) return;
    
    this.scene.traverse((object) => {
      if (object.isMesh && object.material) {
        this.compressTexture(object.material);
      }
    });
  }

  // 压缩纹理
  compressTexture(material) {
    // 简化实现 - 实际应该使用压缩纹理格式
    if (material.map) {
      material.map.minFilter = THREE.LinearMipmapLinearFilter;
      material.map.generateMipmaps = true;
    }
  }

  // 获取性能统计
  getPerformanceStats() {
    const info = this.renderer.info;
    return {
      memory: {
        geometries: info.memory.geometries,
        textures: info.memory.textures
      },
      render: {
        calls: info.render.calls,
        triangles: info.render.triangles,
        points: info.render.points,
        lines: info.render.lines
      }
    };
  }

  // 应用性能预设
  applyPerformancePreset(preset) {
    switch (preset) {
      case 'low':
        this.optimizationState.resolutionScale = 0.5;
        this.optimizationState.shadowsEnabled = false;
        this.optimizationState.shadowsQuality = 0;
        this.optimizationState.lodEnabled = true;
        break;
      case 'medium':
        this.optimizationState.resolutionScale = 0.75;
        this.optimizationState.shadowsEnabled = true;
        this.optimizationState.shadowsQuality = 1;
        this.optimizationState.lodEnabled = true;
        break;
      case 'high':
        this.optimizationState.resolutionScale = 1.0;
        this.optimizationState.shadowsEnabled = true;
        this.optimizationState.shadowsQuality = 2;
        this.optimizationState.lodEnabled = false;
        break;
    }
    
    this.applyAllOptimizations();
  }

  // 应用所有优化
  applyAllOptimizations() {
    this.applyResolutionScale(this.optimizationState.resolutionScale);
    this.applyShadowQuality(this.optimizationState.shadowsQuality);
    this.applyBatchingOptimization();
    this.applyTextureCompression();
    
    if (this.optimizationState.lodEnabled) {
      this.applyLODOptimization(2); // 中等LOD级别
    }
  }
}

// 移动端电池管理器
class MobileBatteryManager {
  constructor() {
    this.batteryLevel = 1.0;
    this.isCharging = false;
    this.chargeTime = 0;
    this.dischargeTime = 0;
    
    this.powerSavingMode = false;
    this.thermalThrottling = false;
    
    this.setupBatteryMonitoring();
  }

  // 设置电池监控
  async setupBatteryMonitoring() {
    if ('getBattery' in navigator) {
      try {
        const battery = await navigator.getBattery();
        this.updateBatteryInfo(battery);
        
        battery.addEventListener('levelchange', () => this.updateBatteryInfo(battery));
        battery.addEventListener('chargingchange', () => this.updateBatteryInfo(battery));
        battery.addEventListener('chargingtimechange', () => this.updateBatteryInfo(battery));
        battery.addEventListener('dischargingtimechange', () => this.updateBatteryInfo(battery));
      } catch (error) {
        console.warn('电池API不支持:', error);
        this.simulateBattery();
      }
    } else {
      console.warn('电池API不可用');
      this.simulateBattery();
    }
  }

  // 更新电池信息
  updateBatteryInfo(battery) {
    this.batteryLevel = battery.level;
    this.isCharging = battery.charging;
    this.chargeTime = battery.chargingTime;
    this.dischargeTime = battery.dischargingTime;
  }

  // 模拟电池(用于不支持API的设备)
  simulateBattery() {
    // 模拟电池消耗
    setInterval(() => {
      if (!this.isCharging) {
        this.batteryLevel = Math.max(0, this.batteryLevel - 0.001);
      } else {
        this.batteryLevel = Math.min(1, this.batteryLevel + 0.005);
      }
    }, 1000);
  }

  // 启用省电模式
  enablePowerSaving() {
    this.powerSavingMode = true;
    
    // 应用省电优化
    this.applyPowerSavingOptimizations();
    
    return {
      resolutionScale: 0.5,
      frameRateLimit: 30,
      shadowsEnabled: false,
      reflectionsEnabled: false,
      particleEffects: false
    };
  }

  // 禁用省电模式
  disablePowerSaving() {
    this.powerSavingMode = false;
  }

  // 应用省电优化
  applyPowerSavingOptimizations() {
    // 这些优化应该应用到渲染系统中
    console.log('应用省电优化...');
  }

  // 检查电池状态
  checkBatteryStatus() {
    const status = {
      level: this.batteryLevel,
      isCharging: this.isCharging,
      isLow: this.batteryLevel < 0.2,
      isCritical: this.batteryLevel < 0.1
    };
    
    return status;
  }

  // 获取电池建议
  getBatterySuggestions() {
    const suggestions = [];
    const status = this.checkBatteryStatus();
    
    if (status.isLow && !this.powerSavingMode) {
      suggestions.push('启用省电模式');
    }
    
    if (status.isCritical) {
      suggestions.push('建议连接充电器');
    }
    
    return suggestions;
  }
}

export default {
  name: 'MobileOptimization',
  setup() {
    const mobileCanvas = ref(null);
    const controlsCollapsed = ref(false);
    const targetFPS = ref(60);
    const resolutionScale = ref(75);
    const touchSensitivity = ref(1.0);
    const inertiaStrength = ref(0.8);
    const pinchZoomEnabled = ref(true);
    const rotationEnabled = ref(true);
    const doubleTapResetEnabled = ref(true);
    const lodLevel = ref(2);
    const shadowQuality = ref(1);
    const antiAliasing = ref(1);
    const batchingEnabled = ref(true);
    const frustumCullingEnabled = ref(true);
    const textureCompressionEnabled = ref(true);
    const powerMode = ref('balanced');
    const backgroundPauseDelay = ref(3);
    const thermalLimit = ref(45);
    const currentFPS = ref(0);
    const frameTime = ref(0);
    const memoryUsage = ref(0);
    const drawCalls = ref(0);
    const triangleCount = ref(0);
    const batteryLevel = ref(100);
    const showGestureHints = ref(true);
    const showPerformanceWarning = ref(false);
    const showBatteryWarning = ref(false);
    const isLoading = ref(true);
    const loadingMessage = ref('初始化移动端优化...');
    const compressedTextures = ref(0);
    const totalTextures = ref(50);
    const optimizedMeshes = ref(0);
    const totalMeshes = ref(20);
    const loadedMemory = ref(0);
    const totalMemory = ref(50 * 1024 * 1024);
    const showDebugOverlay = ref(false);
    const showStats = ref(true);
    const isFullscreen = ref(false);
    const joystickPosition = reactive({ x: 0, y: 0 });

    const performancePresets = [
      { id: 'low', name: '低功耗' },
      { id: 'medium', name: '平衡' },
      { id: 'high', name: '高性能' },
      { id: 'auto', name: '自动' }
    ];

    let currentPreset = ref(performancePresets[1]);

    let scene, camera, renderer, touchController, performanceMonitor, renderOptimizer, batteryManager;
    let clock, stats;
    let frameCount = 0;
    let lastFpsUpdate = 0;

    // 设备信息
    const deviceInfo = computed(() => {
      return isMobileDevice() ? '移动设备' : '桌面设备';
    });

    const gpuInfo = computed(() => {
      return renderer ? renderer.capabilities.getMaxAnisotropy() + 'x 各向异性' : '未知';
    });

    const platformInfo = computed(() => {
      const ua = navigator.userAgent;
      if (/android/i.test(ua)) return 'Android';
      if (/iPad|iPhone|iPod/.test(ua)) return 'iOS';
      if (/Windows/.test(ua)) return 'Windows';
      if (/Mac/.test(ua)) return 'macOS';
      if (/Linux/.test(ua)) return 'Linux';
      return '未知';
    });

    const touchPoints = ref(0);
    const deviceTemperature = ref(35);

    // 初始化场景
    const initScene = async () => {
      // 创建场景
      scene = new THREE.Scene();
      scene.background = new THREE.Color(0x87ceeb);

      // 创建相机
      camera = new THREE.PerspectiveCamera(
        75,
        window.innerWidth / window.innerHeight,
        0.1,
        1000
      );
      camera.position.set(0, 5, 10);

      // 创建渲染器
      renderer = new THREE.WebGLRenderer({
        canvas: mobileCanvas.value,
        antialias: true,
        powerPreference: "high-performance"
      });
      
      // 初始化性能监控器
      performanceMonitor = new MobilePerformanceMonitor();
      performanceMonitor.start();

      // 初始化渲染优化器
      renderOptimizer = new MobileRenderOptimizer(renderer, scene, camera);
      
      // 初始化触控控制器
      touchController = new MobileTouchController(renderer.domElement, camera, renderer);
      
      // 初始化电池管理器
      batteryManager = new MobileBatteryManager();

      // 设置初始优化
      applyCurrentOptimizations();

      // 创建测试场景
      loadingMessage.value = '创建优化场景...';
      await createOptimizedScene();

      // 设置事件监听
      setupEventListeners();

      isLoading.value = false;
      
      // 启动渲染循环
      clock = new THREE.Clock();
      animate();
    };

    // 创建优化场景
    const createOptimizedScene = async () => {
      // 添加光照
      const ambientLight = new THREE.AmbientLight(0x404040, 0.6);
      scene.add(ambientLight);

      const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
      directionalLight.position.set(50, 50, 25);
      directionalLight.castShadow = true;
      scene.add(directionalLight);

      // 创建优化地面
      const groundGeometry = new THREE.PlaneGeometry(100, 100);
      const groundMaterial = new THREE.MeshStandardMaterial({ 
        color: 0x3a9d23,
        roughness: 0.8,
        metalness: 0.2
      });
      const ground = new THREE.Mesh(groundGeometry, groundMaterial);
      ground.rotation.x = -Math.PI / 2;
      ground.receiveShadow = true;
      scene.add(ground);

      // 创建优化物体(使用简单的几何体)
      createOptimizedObjects();

      // 模拟加载过程
      await simulateOptimizationProcess();
    };

    // 创建优化物体
    const createOptimizedObjects = () => {
      // 使用简单几何体创建场景物体
      const geometries = [
        new THREE.BoxGeometry(2, 2, 2),
        new THREE.SphereGeometry(1, 16, 16),
        new THREE.ConeGeometry(1, 3, 8),
        new THREE.CylinderGeometry(1, 1, 2, 12)
      ];

      const materials = [
        new THREE.MeshStandardMaterial({ color: 0xff4444 }),
        new THREE.MeshStandardMaterial({ color: 0x44ff44 }),
        new THREE.MeshStandardMaterial({ color: 0x4444ff }),
        new THREE.MeshStandardMaterial({ color: 0xffff44 })
      ];

      for (let i = 0; i < 20; i++) {
        const geometry = geometries[i % geometries.length];
        const material = materials[i % materials.length];
        const mesh = new THREE.Mesh(geometry, material);
        
        mesh.position.set(
          (Math.random() - 0.5) * 40,
          Math.random() * 5,
          (Math.random() - 0.5) * 40
        );
        
        mesh.castShadow = true;
        mesh.receiveShadow = true;
        
        scene.add(mesh);
      }
    };

    // 模拟优化过程
    const simulateOptimizationProcess = async () => {
      const steps = [
        '压缩纹理...',
        '优化网格...',
        '合并批次...',
        '设置LOD...',
        '应用压缩...'
      ];
      
      for (let i = 0; i < steps.length; i++) {
        loadingMessage.value = steps[i];
        compressedTextures.value = Math.floor((i + 1) / steps.length * totalTextures.value);
        optimizedMeshes.value = Math.floor((i + 1) / steps.length * totalMeshes.value);
        loadedMemory.value = Math.floor((i + 1) / steps.length * totalMemory.value);
        await new Promise(resolve => setTimeout(resolve, 500));
      }
    };

    // 设置事件监听
    const setupEventListeners = () => {
      // 窗口大小变化
      window.addEventListener('resize', onWindowResize);
      
      // 电池状态变化
      setInterval(updateBatteryStatus, 5000);
      
      // 设备温度模拟
      setInterval(updateDeviceTemperature, 10000);
      
      // 隐藏手势提示
      setTimeout(() => {
        showGestureHints.value = false;
      }, 5000);
    };

    // 窗口大小变化
    const onWindowResize = () => {
      if (!camera || !renderer) return;
      
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      
      renderOptimizer.applyResolutionScale(resolutionScale.value / 100);
    };

    // 更新电池状态
    const updateBatteryStatus = () => {
      const status = batteryManager.checkBatteryStatus();
      batteryLevel.value = Math.round(status.level * 100);
      
      // 显示电池警告
      showBatteryWarning.value = status.isLow && !batteryManager.powerSavingMode;
    };

    // 更新设备温度
    const updateDeviceTemperature = () => {
      // 模拟设备温度变化
      const baseTemp = 35;
      const loadFactor = currentFPS.value < 30 ? 0.3 : 0.1;
      const randomVariation = (Math.random() - 0.5) * 2;
      
      deviceTemperature.value = Math.max(
        30, 
        Math.min(60, baseTemp + loadFactor * 10 + randomVariation)
      );
      
      // 温度警告
      if (deviceTemperature.value > thermalLimit.value) {
        applyPerformancePreset(performancePresets[0]); // 切换到低功耗模式
      }
    };

    // 应用性能预设
    const applyPerformancePreset = (preset) => {
      currentPreset.value = preset;
      
      switch (preset.id) {
        case 'low':
          resolutionScale.value = 50;
          shadowQuality.value = 0;
          targetFPS.value = 30;
          powerMode.value = 'battery';
          break;
        case 'medium':
          resolutionScale.value = 75;
          shadowQuality.value = 1;
          targetFPS.value = 60;
          powerMode.value = 'balanced';
          break;
        case 'high':
          resolutionScale.value = 100;
          shadowQuality.value = 2;
          targetFPS.value = 120;
          powerMode.value = 'performance';
          break;
        case 'auto':
          // 基于设备性能自动选择
          applyAutoOptimization();
          break;
      }
      
      applyCurrentOptimizations();
    };

    // 应用自动优化
    const applyAutoOptimization = () => {
      // 基于设备性能自动选择设置
      const isLowEndDevice = isMobileDevice() && !isHighEndDevice();
      
      if (isLowEndDevice) {
        applyPerformancePreset(performancePresets[0]);
      } else {
        applyPerformancePreset(performancePresets[1]);
      }
    };

    // 应用当前优化设置
    const applyCurrentOptimizations = () => {
      if (!renderOptimizer) return;
      
      // 应用分辨率缩放
      renderOptimizer.applyResolutionScale(resolutionScale.value / 100);
      
      // 应用阴影质量
      renderOptimizer.applyShadowQuality(shadowQuality.value);
      
      // 应用LOD优化
      renderOptimizer.applyLODOptimization(lodLevel.value);
      
      // 应用触控设置
      if (touchController) {
        touchController.setSensitivity(touchSensitivity.value);
        touchController.setInertia(inertiaStrength.value);
      }
    };

    // 检查设备类型
    const isMobileDevice = () => {
      return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
    };

    // 检查是否高端设备
    const isHighEndDevice = () => {
      // 简化检测 - 实际应该使用更复杂的特征检测
      const hasHighDpi = window.devicePixelRatio >= 2;
      const hasLargeScreen = window.innerWidth >= 400;
      return hasHighDpi && hasLargeScreen;
    };

    // 切换控制面板
    const toggleControls = () => {
      controlsCollapsed.value = !controlsCollapsed.value;
    };

    // 虚拟摇杆控制
    const onJoystickStart = (event) => {
      event.preventDefault();
      // 实际实现应该处理触摸事件
    };

    const onJoystickMove = (event) => {
      event.preventDefault();
      // 实际实现应该处理触摸移动
    };

    const onJoystickEnd = (event) => {
      event.preventDefault();
      joystickPosition.x = 0;
      joystickPosition.y = 0;
    };

    // 动作按钮
    const onJumpTouch = () => {
      console.log('跳跃动作');
      // 实际实现应该触发跳跃动画
    };

    const onInteractTouch = () => {
      console.log('交互动作');
      // 实际实现应该触发交互逻辑
    };

    // 启用省电模式
    const enablePowerSaving = () => {
      batteryManager.enablePowerSaving();
      applyPerformancePreset(performancePresets[0]);
      showBatteryWarning.value = false;
    };

    // 切换调试信息
    const toggleDebug = () => {
      showDebugOverlay.value = !showDebugOverlay.value;
    };

    // 切换统计信息
    const toggleStats = () => {
      showStats.value = !showStats.value;
    };

    // 截图功能
    const screenshot = () => {
      if (!renderer) return;
      
      renderer.domElement.toBlob((blob) => {
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `screenshot-${Date.now()}.png`;
        a.click();
        URL.revokeObjectURL(url);
      });
    };

    // 切换全屏
    const toggleFullscreen = () => {
      if (!document.fullscreenElement) {
        document.documentElement.requestFullscreen().catch(err => {
          console.log(`全屏请求错误: ${err.message}`);
        });
        isFullscreen.value = true;
      } else {
        if (document.exitFullscreen) {
          document.exitFullscreen();
          isFullscreen.value = false;
        }
      }
    };

    // 动画循环
    const animate = () => {
      requestAnimationFrame(animate);
      
      const deltaTime = clock.getDelta();
      
      // 更新性能监控
      const performanceData = performanceMonitor.update();
      currentFPS.value = performanceData.fps;
      frameTime.value = performanceData.frameTime;
      
      // 更新触控控制器
      if (touchController) {
        touchController.update(deltaTime);
      }
      
      // 更新性能统计
      updatePerformanceStats();
      
      // 检查性能问题
      const issues = performanceMonitor.checkPerformanceIssues();
      showPerformanceWarning.value = issues.length > 0;
      
      // 应用动态优化
      applyDynamicOptimizations(issues);
      
      // 渲染场景
      renderer.render(scene, camera);
      
      // 更新FPS计数
      updateFPSCounter(deltaTime);
    };

    // 更新性能统计
    const updatePerformanceStats = () => {
      if (!renderOptimizer) return;
      
      const stats = renderOptimizer.getPerformanceStats();
      memoryUsage.value = stats.memory.geometries * 1024 * 1024 + stats.memory.textures * 512 * 1024;
      drawCalls.value = stats.render.calls;
      triangleCount.value = stats.render.triangles;
    };

    // 应用动态优化
    const applyDynamicOptimizations = (issues) => {
      if (currentPreset.value.id === 'auto') {
        // 自动模式下的动态优化
        if (issues.some(issue => issue.type === 'low_fps')) {
          // 如果帧率低,降低质量
          resolutionScale.value = Math.max(25, resolutionScale.value - 5);
          applyCurrentOptimizations();
        } else if (currentFPS.value > targetFPS.value + 10 && resolutionScale.value < 100) {
          // 如果性能充足,提高质量
          resolutionScale.value = Math.min(100, resolutionScale.value + 5);
          applyCurrentOptimizations();
        }
      }
    };

    // 更新FPS计数器
    const updateFPSCounter = (deltaTime) => {
      frameCount++;
      lastFpsUpdate += deltaTime;
      
      if (lastFpsUpdate >= 1.0) {
        currentFPS.value = Math.round(frameCount / lastFpsUpdate);
        frameCount = 0;
        lastFpsUpdate = 0;
      }
    };

    // 计算属性
    const joystickStyle = computed(() => ({
      transform: `translate(${joystickPosition.x * 20}px, ${joystickPosition.y * 20}px)`
    }));

    const loadingProgressStyle = computed(() => ({
      width: '100%'
    }));

    // 工具函数
    const getFPSClass = (fps) => {
      if (fps >= 50) return 'good';
      if (fps >= 30) return 'warning';
      return 'bad';
    };

    const getBatteryClass = (level) => {
      if (level >= 50) return 'good';
      if (level >= 20) return 'warning';
      return 'bad';
    };

    const formatMemory = (bytes) => {
      if (bytes >= 1024 * 1024) {
        return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
      } else if (bytes >= 1024) {
        return (bytes / 1024).toFixed(1) + ' KB';
      }
      return bytes + ' B';
    };

    const formatNumber = (num) => {
      if (num >= 1000000) {
        return (num / 1000000).toFixed(1) + 'M';
      } else if (num >= 1000) {
        return (num / 1000).toFixed(1) + 'K';
      }
      return num.toString();
    };

    onMounted(() => {
      initScene();
    });

    onUnmounted(() => {
      if (renderer) {
        renderer.dispose();
      }
      window.removeEventListener('resize', onWindowResize);
    });

    return {
      mobileCanvas,
      controlsCollapsed,
      targetFPS,
      resolutionScale,
      touchSensitivity,
      inertiaStrength,
      pinchZoomEnabled,
      rotationEnabled,
      doubleTapResetEnabled,
      lodLevel,
      shadowQuality,
      antiAliasing,
      batchingEnabled,
      frustumCullingEnabled,
      textureCompressionEnabled,
      powerMode,
      backgroundPauseDelay,
      thermalLimit,
      currentFPS,
      frameTime,
      memoryUsage,
      drawCalls,
      triangleCount,
      batteryLevel,
      showGestureHints,
      showPerformanceWarning,
      showBatteryWarning,
      isLoading,
      loadingMessage,
      compressedTextures,
      totalTextures,
      optimizedMeshes,
      totalMeshes,
      loadedMemory,
      totalMemory,
      showDebugOverlay,
      showStats,
      isFullscreen,
      joystickPosition,
      performancePresets,
      currentPreset,
      deviceInfo,
      gpuInfo,
      platformInfo,
      touchPoints,
      deviceTemperature,
      joystickStyle,
      loadingProgressStyle,
      toggleControls,
      applyPerformancePreset,
      onJoystickStart,
      onJoystickMove,
      onJoystickEnd,
      onJumpTouch,
      onInteractTouch,
      enablePowerSaving,
      toggleDebug,
      toggleStats,
      screenshot,
      toggleFullscreen,
      getFPSClass,
      getBatteryClass,
      formatMemory,
      formatNumber
    };
  }
};
</script>

<style scoped>
.mobile-optimization-container {
  width: 100%;
  height: 100vh;
  position: relative;
  background: #000;
  overflow: hidden;
  touch-action: none;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

.mobile-canvas {
  width: 100%;
  height: 100%;
  display: block;
}

.mobile-controls {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 320px;
  max-width: 90vw;
  background: rgba(0, 0, 0, 0.95);
  border-radius: 12px;
  color: white;
  backdrop-filter: blur(20px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
  transition: all 0.3s ease;
  overflow: hidden;
}

.mobile-controls.controls-collapsed {
  height: 50px;
}

.controls-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 15px;
  cursor: pointer;
  background: rgba(0, 0, 0, 0.8);
}

.controls-header h3 {
  margin: 0;
  color: #00ff88;
  font-size: 16px;
}

.collapse-icon {
  color: #ccc;
  font-size: 14px;
}

.controls-content {
  padding: 15px;
  max-height: 70vh;
  overflow-y: auto;
}

.control-section {
  margin-bottom: 20px;
  padding-bottom: 15px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.control-section:last-child {
  margin-bottom: 0;
  border-bottom: none;
}

.control-section h4 {
  color: #00aaff;
  margin-bottom: 15px;
  font-size: 14px;
}

.performance-presets {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin-bottom: 15px;
}

.preset-button {
  padding: 8px;
  border: 1px solid #444;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.05);
  color: white;
  cursor: pointer;
  font-size: 12px;
  transition: all 0.3s ease;
}

.preset-button:hover {
  border-color: #00ff88;
}

.preset-button.active {
  border-color: #00ff88;
  background: rgba(0, 255, 136, 0.2);
}

.control-group {
  margin-bottom: 15px;
}

.control-group label {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
  color: #ccc;
  font-size: 14px;
}

.control-group input[type="range"] {
  width: 100%;
  height: 6px;
  background: #444;
  border-radius: 3px;
  outline: none;
  opacity: 0.7;
  transition: opacity 0.2s;
}

.control-group input[type="range"]:hover {
  opacity: 1;
}

.control-group input[type="range"]::-webkit-slider-thumb {
  appearance: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #00ff88;
  cursor: pointer;
  box-shadow: 0 0 10px rgba(0, 255, 136, 0.5);
}

.control-group input[type="checkbox"] {
  width: 20px;
  height: 20px;
  accent-color: #00ff88;
}

.mode-select {
  width: 100%;
  padding: 8px;
  border: 1px solid #444;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.1);
  color: white;
  font-size: 14px;
}

.touch-controls,
.rendering-optimizations,
.battery-optimizations {
  margin-bottom: 15px;
}

.gesture-controls,
.optimization-toggles,
.thermal-controls {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}

.performance-stats {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.stat-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 6px 0;
  font-size: 12px;
}

.stat-item span:first-child {
  color: #ccc;
}

.stat-item span:last-child.good {
  color: #00ff88;
}

.stat-item span:last-child.warning {
  color: #ffaa00;
}

.stat-item span:last-child.bad {
  color: #ff4444;
}

.touch-control-area {
  position: absolute;
  bottom: 20px;
  left: 20px;
  right: 20px;
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  pointer-events: none;
}

.virtual-joystick {
  width: 120px;
  height: 120px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 50%;
  backdrop-filter: blur(10px);
  border: 2px solid rgba(255, 255, 255, 0.3);
  pointer-events: auto;
  touch-action: none;
}

.joystick-base {
  width: 100%;
  height: 100%;
  position: relative;
}

.joystick-handle {
  width: 50px;
  height: 50px;
  background: rgba(0, 255, 136, 0.8);
  border-radius: 50%;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  transition: transform 0.1s ease;
  box-shadow: 0 0 20px rgba(0, 255, 136, 0.5);
}

.action-buttons {
  display: flex;
  flex-direction: column;
  gap: 15px;
  pointer-events: auto;
}

.action-button {
  padding: 15px 20px;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
  color: white;
  font-size: 14px;
  backdrop-filter: blur(10px);
  border: 2px solid rgba(255, 255, 255, 0.3);
  cursor: pointer;
  transition: all 0.3s ease;
  touch-action: manipulation;
}

.action-button:active {
  background: rgba(0, 255, 136, 0.3);
  transform: scale(0.95);
}

.action-button.jump {
  background: rgba(255, 170, 0, 0.8);
}

.action-button.interact {
  background: rgba(0, 170, 255, 0.8);
}

.gesture-hints {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: rgba(0, 0, 0, 0.8);
  padding: 15px;
  border-radius: 10px;
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.2);
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.hint-item {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  color: #ccc;
}

.hint-icon {
  font-size: 18px;
}

.performance-warning,
.battery-warning {
  position: absolute;
  top: 70px;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(255, 68, 68, 0.9);
  padding: 10px 15px;
  border-radius: 8px;
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.2);
  z-index: 1000;
}

.warning-content {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  color: white;
}

.warning-icon {
  font-size: 16px;
}

.optimize-button,
.power-save-button {
  padding: 5px 10px;
  border: none;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.2);
  color: white;
  cursor: pointer;
  font-size: 12px;
  transition: background 0.3s;
}

.optimize-button:hover,
.power-save-button:hover {
  background: rgba(255, 255, 255, 0.3);
}

.loading-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

.loading-content {
  text-align: center;
  color: white;
}

.mobile-loader {
  margin-bottom: 30px;
}

.phone-frame {
  width: 200px;
  height: 400px;
  background: #333;
  border-radius: 20px;
  padding: 20px;
  position: relative;
  margin: 0 auto;
  border: 4px solid #555;
}

.screen-content {
  width: 100%;
  height: 100%;
  background: #1a1a1a;
  border-radius: 10px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 20px;
}

.loading-bar {
  width: 80%;
  height: 4px;
  background: rgba(255, 255, 255, 0.2);
  border-radius: 2px;
  overflow: hidden;
}

.loading-bar::after {
  content: '';
  display: block;
  width: 100%;
  height: 100%;
  background: #00ff88;
  border-radius: 2px;
  animation: loadingBar 2s infinite ease-in-out;
}

.loading-dots {
  display: flex;
  gap: 8px;
}

.dot {
  width: 8px;
  height: 8px;
  background: #00ff88;
  border-radius: 50%;
  animation: loadingDots 1.4s infinite ease-in-out;
}

.dot:nth-child(1) { animation-delay: 0s; }
.dot:nth-child(2) { animation-delay: 0.2s; }
.dot:nth-child(3) { animation-delay: 0.4s; }

.loading-content h3 {
  margin-bottom: 20px;
  color: white;
  font-size: 18px;
}

.loading-progress {
  width: 300px;
  margin: 0 auto 15px;
}

.progress-bar {
  width: 100%;
  height: 6px;
  background: rgba(255, 255, 255, 0.2);
  border-radius: 3px;
  overflow: hidden;
  margin-bottom: 10px;
}

.progress-fill {
  height: 100%;
  background: linear-gradient(90deg, #00ff88, #00aaff);
  border-radius: 3px;
  transition: width 0.3s ease;
}

.optimization-stats {
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-size: 12px;
  color: #ccc;
}

.debug-overlay {
  position: absolute;
  top: 60px;
  left: 10px;
  background: rgba(0, 0, 0, 0.8);
  padding: 10px;
  border-radius: 6px;
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.debug-info {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 11px;
  color: #ccc;
}

.quick-actions {
  position: absolute;
  bottom: 20px;
  right: 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.quick-button {
  width: 50px;
  height: 50px;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
  color: white;
  font-size: 18px;
  backdrop-filter: blur(10px);
  border: 2px solid rgba(255, 255, 255, 0.3);
  cursor: pointer;
  transition: all 0.3s ease;
  display: flex;
  justify-content: center;
  align-items: center;
}

.quick-button:hover {
  background: rgba(255, 255, 255, 0.2);
}

.quick-button.active {
  background: rgba(0, 255, 136, 0.3);
  border-color: #00ff88;
}

@keyframes loadingBar {
  0% { transform: translateX(-100%); }
  50% { transform: translateX(0); }
  100% { transform: translateX(100%); }
}

@keyframes loadingDots {
  0%, 80%, 100% {
    transform: scale(0.8);
    opacity: 0.5;
  }
  40% {
    transform: scale(1.2);
    opacity: 1;
  }
}

/* 移动端响应式设计 */
@media (max-width: 768px) {
  .mobile-controls {
    width: 280px;
    right: 10px;
    top: 10px;
  }
  
  .controls-content {
    padding: 10px;
  }
  
  .performance-presets {
    grid-template-columns: 1fr;
  }
  
  .touch-control-area {
    bottom: 10px;
    left: 10px;
    right: 10px;
  }
  
  .virtual-joystick {
    width: 100px;
    height: 100px;
  }
  
  .joystick-handle {
    width: 40px;
    height: 40px;
  }
  
  .action-button {
    padding: 12px 16px;
    font-size: 12px;
  }
  
  .quick-actions {
    bottom: 10px;
    right: 10px;
  }
  
  .quick-button {
    width: 45px;
    height: 45px;
    font-size: 16px;
  }
}

@media (max-width: 480px) {
  .mobile-controls {
    width: 250px;
  }
  
  .virtual-joystick {
    width: 80px;
    height: 80px;
  }
  
  .joystick-handle {
    width: 35px;
    height: 35px;
  }
  
  .action-button {
    padding: 10px 14px;
    font-size: 11px;
  }
  
  .gesture-hints {
    font-size: 12px;
    padding: 10px;
  }
}

/* 防止文本选择 */
.no-select {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

/* 改善触控反馈 */
@media (hover: none) and (pointer: coarse) {
  .preset-button:active,
  .action-button:active,
  .quick-button:active {
    transform: scale(0.95);
    transition: transform 0.1s ease;
  }
}
</style>

高级移动端优化技术

自适应性能管理系统

javascript 复制代码
// 自适应性能管理器
class AdaptivePerformanceManager {
  constructor() {
    this.performanceTiers = this.detectPerformanceTier();
    this.qualityLevels = {
      low: this.createLowQualityConfig(),
      medium: this.createMediumQualityConfig(),
      high: this.createHighQualityConfig(),
      ultra: this.createUltraQualityConfig()
    };
    
    this.currentConfig = this.qualityLevels[this.performanceTiers];
    this.performanceHistory = [];
    this.adaptationEnabled = true;
  }

  // 检测性能等级
  detectPerformanceTier() {
    const score = this.calculatePerformanceScore();
    
    if (score >= 80) return 'ultra';
    if (score >= 60) return 'high';
    if (score >= 40) return 'medium';
    return 'low';
  }

  // 计算性能分数
  calculatePerformanceScore() {
    let score = 0;
    
    // GPU 性能评估
    const gpuScore = this.evaluateGPUPerformance();
    
    // CPU 性能评估
    const cpuScore = this.evaluateCPUPerformance();
    
    // 内存评估
    const memoryScore = this.evaluateMemory();
    
    // 设备类型加分
    const deviceBonus = this.getDeviceBonus();
    
    score = (gpuScore * 0.5) + (cpuScore * 0.3) + (memoryScore * 0.2) + deviceBonus;
    
    return Math.min(100, Math.max(0, score));
  }

  // 评估GPU性能
  evaluateGPUPerformance() {
    const canvas = document.createElement('canvas');
    const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
    
    if (!gl) return 30;
    
    const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
    if (debugInfo) {
      const renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
      return this.scoreGPUByRenderer(renderer);
    }
    
    // 基于支持的扩展评估
    return this.scoreGPUByExtensions(gl);
  }

  // 根据渲染器评分GPU
  scoreGPUByRenderer(renderer) {
    const highEndGPUs = [
      'adreno', 'mali-g', 'apple gpu', 'nvidia', 'amd radeon'
    ];
    
    const midRangeGPUs = [
      'mali-t', 'powervr', 'intel hd', 'adreno 5'
    ];
    
    const rendererLower = renderer.toLowerCase();
    
    if (highEndGPUs.some(gpu => rendererLower.includes(gpu))) {
      return 80;
    } else if (midRangeGPUs.some(gpu => rendererLower.includes(gpu))) {
      return 60;
    } else {
      return 40;
    }
  }

  // 根据扩展评分GPU
  scoreGPUByExtensions(gl) {
    let score = 30;
    
    // 检查支持的扩展
    const extensions = [
      'EXT_texture_filter_anisotropic',
      'OES_texture_float',
      'WEBGL_compressed_texture_etc',
      'WEBGL_compressed_texture_astc'
    ];
    
    const supportedExtensions = extensions.filter(ext => gl.getExtension(ext));
    score += supportedExtensions.length * 10;
    
    return Math.min(80, score);
  }

  // 评估CPU性能
  evaluateCPUPerformance() {
    // 通过简单基准测试评估CPU性能
    const startTime = performance.now();
    let operations = 0;
    
    // 执行一些数学运算
    for (let i = 0; i < 1000000; i++) {
      operations += Math.sqrt(i) * Math.sin(i);
    }
    
    const endTime = performance.now();
    const duration = endTime - startTime;
    
    // 基于执行时间评分
    if (duration < 50) return 80;
    if (duration < 100) return 60;
    if (duration < 200) return 40;
    return 20;
  }

  // 评估内存
  evaluateMemory() {
    // 检查设备内存(近似值)
    if (navigator.deviceMemory) {
      return navigator.deviceMemory * 20; // 1GB = 20分, 8GB = 100分
    }
    
    // 基于用户代理的启发式评估
    return this.estimateMemoryFromUA();
  }

  // 从用户代理估算内存
  estimateMemoryFromUA() {
    const ua = navigator.userAgent;
    
    if (/iPhone.*OS 1[3-9]/.test(ua)) return 80; // 较新iPhone
    if (/iPad.*OS 1[3-9]/.test(ua)) return 70;   // 较新iPad
    if (/Android 1[0-9]/.test(ua)) return 60;    // 较新Android
    if (/iPhone|iPad/.test(ua)) return 50;       // 其他iOS设备
    if (/Android/.test(ua)) return 40;           // 其他Android设备
    
    return 70; // 桌面设备默认较高分数
  }

  // 获取设备加分
  getDeviceBonus() {
    const ua = navigator.userAgent;
    
    if (/iPhone1[3-9]/.test(ua)) return 10; // iPhone 12及更新
    if (/iPad[8-9]/.test(ua)) return 10;    // 较新iPad
    if (/SM-G99/.test(ua)) return 8;        // 三星旗舰
    
    return 0;
  }

  // 创建低质量配置
  createLowQualityConfig() {
    return {
      resolutionScale: 0.5,
      shadowEnabled: false,
      antialias: false,
      textureQuality: 'low',
      maxLights: 2,
      maxParticles: 50,
      lodBias: 2.0,
      physicsQuality: 'low'
    };
  }

  // 创建中等质量配置
  createMediumQualityConfig() {
    return {
      resolutionScale: 0.75,
      shadowEnabled: true,
      shadowQuality: 'low',
      antialias: false,
      textureQuality: 'medium',
      maxLights: 4,
      maxParticles: 100,
      lodBias: 1.5,
      physicsQuality: 'medium'
    };
  }

  // 创建高质量配置
  createHighQualityConfig() {
    return {
      resolutionScale: 1.0,
      shadowEnabled: true,
      shadowQuality: 'medium',
      antialias: true,
      textureQuality: 'high',
      maxLights: 8,
      maxParticles: 200,
      lodBias: 1.0,
      physicsQuality: 'high'
    };
  }

  // 创建超高质量配置
  createUltraQualityConfig() {
    return {
      resolutionScale: 1.0,
      shadowEnabled: true,
      shadowQuality: 'high',
      antialias: true,
      textureQuality: 'ultra',
      maxLights: 16,
      maxParticles: 500,
      lodBias: 0.5,
      physicsQuality: 'ultra'
    };
  }

  // 动态调整配置
  adaptBasedOnPerformance(currentFPS, targetFPS) {
    if (!this.adaptationEnabled) return;
    
    this.performanceHistory.push(currentFPS);
    if (this.performanceHistory.length > 60) {
      this.performanceHistory.shift();
    }
    
    const averageFPS = this.performanceHistory.reduce((a, b) => a + b) / this.performanceHistory.length;
    
    if (averageFPS < targetFPS * 0.8) {
      // 性能不足,降低质量
      this.downgradeQuality();
    } else if (averageFPS > targetFPS * 1.2 && this.canUpgradeQuality()) {
      // 性能充足,提升质量
      this.upgradeQuality();
    }
  }

  // 降低质量
  downgradeQuality() {
    const tiers = ['ultra', 'high', 'medium', 'low'];
    const currentIndex = tiers.indexOf(this.performanceTiers);
    
    if (currentIndex < tiers.length - 1) {
      this.performanceTiers = tiers[currentIndex + 1];
      this.currentConfig = this.qualityLevels[this.performanceTiers];
      console.log(`性能适配: 降低到 ${this.performanceTiers} 质量`);
    }
  }

  // 提升质量
  upgradeQuality() {
    const tiers = ['ultra', 'high', 'medium', 'low'];
    const currentIndex = tiers.indexOf(this.performanceTiers);
    
    if (currentIndex > 0) {
      this.performanceTiers = tiers[currentIndex - 1];
      this.currentConfig = this.qualityLevels[this.performanceTiers];
      console.log(`性能适配: 提升到 ${this.performanceTiers} 质量`);
    }
  }

  // 检查是否可以提升质量
  canUpgradeQuality() {
    const tiers = ['ultra', 'high', 'medium', 'low'];
    const currentIndex = tiers.indexOf(this.performanceTiers);
    return currentIndex > 0;
  }

  // 获取当前配置
  getCurrentConfig() {
    return this.currentConfig;
  }

  // 启用/禁用自适应
  setAdaptationEnabled(enabled) {
    this.adaptationEnabled = enabled;
  }
}

注意事项与最佳实践

  1. 性能优化策略

    • 优先考虑60FPS的流畅体验
    • 使用适当的纹理压缩格式(ASTC、ETC2)
    • 实现动态分辨率缩放
    • 监控内存使用和温度
  2. 触控交互设计

    • 提供足够的触控目标(最小44px)
    • 实现手势反馈和视觉提示
    • 支持多指触控和复杂手势
    • 优化触摸响应时间
  3. 电池续航优化

    • 在后台时暂停渲染
    • 降低非活动标签页的更新频率
    • 使用requestAnimationFrame进行节流
    • 监控电池状态并调整画质
  4. 跨平台兼容性

    • 测试不同设备和浏览器
    • 提供优雅的性能降级
    • 支持多种屏幕比例和分辨率
    • 处理方向变化和键盘弹出

下一节预告

第38节:WebGL 2.0与Three.js新特性

将深入探索WebGL 2.0的核心功能,包括:计算着色器、变换反馈、多重渲染目标、实例化渲染,以及Three.js对这些新特性的支持实现。

相关推荐
愚公搬代码1 天前
【愚公系列】《MCP协议与AI Agent开发》011-MCP协议标准与规范体系(交互协议与状态码体系)
人工智能·交互
q***06471 天前
开源模型应用落地-FastAPI-助力模型交互-进阶篇-中间件(四)
开源·交互·fastapi
q***82913 天前
如何使用C#与SQL Server数据库进行交互
数据库·c#·交互
q***18063 天前
如何使用C#与SQL Server数据库进行交互
数据库·c#·交互
程序猿_极客3 天前
JavaScript 的 Web APIs 入门到实战全总结(day7):从数据处理到交互落地的全链路实战(附实战案例代码)
开发语言·前端·javascript·交互·web apis 入门到实战
q***2513 天前
开源模型应用落地-FastAPI-助力模型交互-进阶篇-中间件(四)
开源·交互·fastapi
梓贤Vigo4 天前
【Axure高保真原型】密码组输入框
交互·产品经理·axure·原型
招风的黑耳5 天前
500+带交互的元件库:Axure原型设计的活字典
交互·axure·原型
AI 研究所5 天前
1024开发者节:开源发布,引领生态繁荣
人工智能·语言模型·开源·大模型·交互·agent