# 性能优化指南

本文档提供 Whale Town 项目的性能优化策略和最佳实践。

## 🎯 优化目标

### 性能指标
- **帧率**: 保持60FPS稳定运行
- **内存使用**: 控制在合理范围内
- **加载时间**: 场景切换<2秒
- **响应时间**: UI交互<100ms

### 优化原则
1. **测量优先** - 先测量再优化
2. **渐进优化** - 逐步改进性能
3. **平衡取舍** - 在质量和性能间平衡
4. **用户体验** - 优化用户感知性能

## 🔧 渲染优化

### 纹理优化
```gdscript
# 使用合适的纹理格式
# 小图标使用 RGBA8
# 大背景使用 DXT1/DXT5
# UI元素使用 RGBA4444

# 纹理压缩设置
func optimize_texture_import():
    # 在导入设置中启用压缩
    # 设置合适的最大尺寸
    # 启用Mipmaps（3D纹理）
    pass
```

### 批处理优化
```gdscript
# 合并相同材质的对象
# 使用MultiMesh渲染大量相同对象
func create_multimesh_instances():
    var multimesh = MultiMesh.new()
    multimesh.transform_format = MultiMesh.TRANSFORM_2D
    multimesh.instance_count = 100
    
    var mesh_instance = MeshInstance2D.new()
    mesh_instance.multimesh = multimesh
    add_child(mesh_instance)
```

### 视锥剔除
```gdscript
# 只渲染可见区域的对象
func update_visibility():
    var camera = get_viewport().get_camera_2d()
    var screen_rect = get_viewport_rect()
    
    for child in get_children():
        if child is Node2D:
            var visible = screen_rect.intersects(child.get_rect())
            child.visible = visible
```

## 💾 内存优化

### 对象池模式
```gdscript
# ObjectPool.gd
class_name ObjectPool
extends Node

var pools: Dictionary = {}

func get_object(type: String) -> Node:
    if not pools.has(type):
        pools[type] = []
    
    var pool = pools[type]
    if pool.size() > 0:
        return pool.pop_back()
    else:
        return _create_new_object(type)

func return_object(obj: Node, type: String):
    obj.reset()  # 重置对象状态
    pools[type].append(obj)

func _create_new_object(type: String) -> Node:
    match type:
        "Bullet":
            return preload("res://prefabs/Bullet.tscn").instantiate()
        "Enemy":
            return preload("res://prefabs/Enemy.tscn").instantiate()
        _:
            return null
```

### 资源管理
```gdscript
# ResourceManager.gd
class_name ResourceManager
extends Node

var loaded_resources: Dictionary = {}
var resource_usage: Dictionary = {}

func load_resource(path: String) -> Resource:
    if loaded_resources.has(path):
        resource_usage[path] += 1
        return loaded_resources[path]
    
    var resource = load(path)
    loaded_resources[path] = resource
    resource_usage[path] = 1
    return resource

func unload_resource(path: String):
    if resource_usage.has(path):
        resource_usage[path] -= 1
        if resource_usage[path] <= 0:
            loaded_resources.erase(path)
            resource_usage.erase(path)
```

### 内存监控
```gdscript
# MemoryMonitor.gd
extends Node

func _ready():
    # 每秒检查一次内存使用
    var timer = Timer.new()
    timer.wait_time = 1.0
    timer.timeout.connect(_check_memory)
    add_child(timer)
    timer.start()

func _check_memory():
    var memory_usage = OS.get_static_memory_usage_by_type()
    var total_memory = OS.get_static_memory_peak_usage()
    
    print("内存使用: ", memory_usage / 1024 / 1024, "MB")
    print("峰值内存: ", total_memory / 1024 / 1024, "MB")
    
    # 内存使用过高时触发垃圾回收
    if total_memory > 200 * 1024 * 1024:  # 200MB
        print("触发垃圾回收")
        # 清理不必要的资源
        _cleanup_resources()

func _cleanup_resources():
    # 清理缓存
    # 卸载未使用的资源
    # 强制垃圾回收
    pass
```

## ⚡ 脚本优化

### 避免频繁计算
```gdscript
# ❌ 错误示例：每帧计算
func _process(delta):
    var distance = global_position.distance_to(target.global_position)
    if distance < 100:
        attack_target()

# ✅ 正确示例：缓存计算结果
var cached_distance: float = 0.0
var distance_update_timer: float = 0.0

func _process(delta):
    distance_update_timer += delta
    if distance_update_timer >= 0.1:  # 每100ms更新一次
        cached_distance = global_position.distance_to(target.global_position)
        distance_update_timer = 0.0
    
    if cached_distance < 100:
        attack_target()
```

### 优化循环
```gdscript
# ❌ 错误示例：嵌套循环
func find_nearest_enemy():
    var nearest = null
    var min_distance = INF
    
    for enemy in enemies:
        for player in players:
            var distance = enemy.global_position.distance_to(player.global_position)
            if distance < min_distance:
                min_distance = distance
                nearest = enemy

# ✅ 正确示例：优化算法
func find_nearest_enemy():
    var player_pos = player.global_position
    var nearest = null
    var min_distance = INF
    
    for enemy in enemies:
        var distance = enemy.global_position.distance_squared_to(player_pos)
        if distance < min_distance:
            min_distance = distance
            nearest = enemy
```

### 事件优化
```gdscript
# 使用信号代替轮询
# ❌ 错误示例：轮询检查
func _process(delta):
    if player.health <= 0:
        game_over()

# ✅ 正确示例：事件驱动
func _ready():
    player.health_changed.connect(_on_health_changed)

func _on_health_changed(new_health: int):
    if new_health <= 0:
        game_over()
```

## 🎮 游戏逻辑优化

### 状态机优化
```gdscript
# StateMachine.gd
class_name StateMachine
extends Node

var current_state: State
var states: Dictionary = {}

func change_state(state_name: String):
    if current_state:
        current_state.exit()
    
    current_state = states[state_name]
    current_state.enter()

func _process(delta):
    if current_state:
        current_state.update(delta)
```

### AI优化
```gdscript
# EnemyAI.gd
extends Node

var update_interval: float = 0.2  # 每200ms更新一次AI
var update_timer: float = 0.0

func _process(delta):
    update_timer += delta
    if update_timer >= update_interval:
        update_ai()
        update_timer = 0.0

func update_ai():
    # AI逻辑更新
    # 路径寻找
    # 决策制定
    pass
```

### 碰撞检测优化
```gdscript
# 使用空间分区优化碰撞检测
class_name SpatialGrid
extends Node

var grid_size: int = 64
var grid: Dictionary = {}

func add_object(obj: Node2D):
    var grid_pos = Vector2(
        int(obj.global_position.x / grid_size),
        int(obj.global_position.y / grid_size)
    )
    
    if not grid.has(grid_pos):
        grid[grid_pos] = []
    
    grid[grid_pos].append(obj)

func get_nearby_objects(pos: Vector2) -> Array:
    var grid_pos = Vector2(
        int(pos.x / grid_size),
        int(pos.y / grid_size)
    )
    
    var nearby = []
    for x in range(-1, 2):
        for y in range(-1, 2):
            var check_pos = grid_pos + Vector2(x, y)
            if grid.has(check_pos):
                nearby.append_array(grid[check_pos])
    
    return nearby
```

## 🌐 网络优化

### 数据压缩
```gdscript
# NetworkManager.gd
func send_player_data(data: Dictionary):
    # 只发送变化的数据
    var delta_data = get_changed_data(data)
    
    # 压缩数据
    var compressed = compress_data(delta_data)
    
    # 发送数据
    send_to_server(compressed)

func compress_data(data: Dictionary) -> PackedByteArray:
    var json_string = JSON.stringify(data)
    var bytes = json_string.to_utf8_buffer()
    return bytes.compress(FileAccess.COMPRESSION_GZIP)
```

### 批量更新
```gdscript
# 批量发送网络更新
var pending_updates: Array = []
var update_timer: float = 0.0

func _process(delta):
    update_timer += delta
    if update_timer >= 0.05:  # 每50ms发送一次
        if pending_updates.size() > 0:
            send_batch_updates(pending_updates)
            pending_updates.clear()
        update_timer = 0.0

func queue_update(update_data: Dictionary):
    pending_updates.append(update_data)
```

## 📊 性能监控

### FPS监控
```gdscript
# FPSMonitor.gd
extends Control

@onready var fps_label: Label = $FPSLabel
var fps_history: Array = []

func _process(delta):
    var current_fps = Engine.get_frames_per_second()
    fps_history.append(current_fps)
    
    if fps_history.size() > 60:  # 保留60帧历史
        fps_history.pop_front()
    
    var avg_fps = 0
    for fps in fps_history:
        avg_fps += fps
    avg_fps /= fps_history.size()
    
    fps_label.text = "FPS: %d (平均: %d)" % [current_fps, avg_fps]
    
    # FPS过低时警告
    if avg_fps < 30:
        modulate = Color.RED
    elif avg_fps < 50:
        modulate = Color.YELLOW
    else:
        modulate = Color.WHITE
```

### 性能分析器
```gdscript
# Profiler.gd
class_name Profiler
extends Node

var timers: Dictionary = {}

func start_timer(name: String):
    timers[name] = Time.get_time_dict_from_system()

func end_timer(name: String) -> float:
    if not timers.has(name):
        return 0.0
    
    var start_time = timers[name]
    var end_time = Time.get_time_dict_from_system()
    
    var duration = (end_time.hour * 3600 + end_time.minute * 60 + end_time.second) - \
                  (start_time.hour * 3600 + start_time.minute * 60 + start_time.second)
    
    timers.erase(name)
    return duration

# 使用示例
func expensive_function():
    Profiler.start_timer("expensive_function")
    
    # 执行耗时操作
    for i in range(10000):
        pass
    
    var duration = Profiler.end_timer("expensive_function")
    print("函数执行时间: ", duration, "秒")
```

## 🛠️ 调试工具

### 性能调试面板
```gdscript
# DebugPanel.gd
extends Control

@onready var memory_label: Label = $VBox/MemoryLabel
@onready var fps_label: Label = $VBox/FPSLabel
@onready var objects_label: Label = $VBox/ObjectsLabel

func _process(delta):
    # 更新内存使用
    var memory = OS.get_static_memory_usage_by_type()
    memory_label.text = "内存: %.1f MB" % (memory / 1024.0 / 1024.0)
    
    # 更新FPS
    fps_label.text = "FPS: %d" % Engine.get_frames_per_second()
    
    # 更新对象数量
    var object_count = get_tree().get_node_count()
    objects_label.text = "对象数: %d" % object_count
```

### 热点分析
```gdscript
# HotspotAnalyzer.gd
extends Node

var function_calls: Dictionary = {}
var function_times: Dictionary = {}

func profile_function(func_name: String, callable: Callable):
    var start_time = Time.get_time_dict_from_system()
    
    callable.call()
    
    var end_time = Time.get_time_dict_from_system()
    var duration = (end_time.hour * 3600 + end_time.minute * 60 + end_time.second) - \
                  (start_time.hour * 3600 + start_time.minute * 60 + start_time.second)
    
    if not function_calls.has(func_name):
        function_calls[func_name] = 0
        function_times[func_name] = 0.0
    
    function_calls[func_name] += 1
    function_times[func_name] += duration

func print_profile_report():
    print("=== 性能分析报告 ===")
    for func_name in function_calls.keys():
        var calls = function_calls[func_name]
        var total_time = function_times[func_name]
        var avg_time = total_time / calls
        
        print("%s: 调用%d次, 总时间%.3fs, 平均%.3fs" % [func_name, calls, total_time, avg_time])
```

## 📚 最佳实践

### 开发阶段
1. **早期优化** - 在设计阶段考虑性能
2. **渐进开发** - 逐步添加功能并测试性能
3. **定期测试** - 定期进行性能测试
4. **文档记录** - 记录性能优化决策

### 测试阶段
1. **多设备测试** - 在不同性能设备上测试
2. **压力测试** - 测试极限情况下的性能
3. **长时间测试** - 测试内存泄漏和性能衰减
4. **用户测试** - 收集真实用户的性能反馈

### 发布阶段
1. **性能监控** - 监控线上性能指标
2. **快速响应** - 快速修复性能问题
3. **持续优化** - 根据数据持续优化
4. **版本对比** - 对比不同版本的性能表现

## 🔍 常见问题

### Q: 如何识别性能瓶颈？
A: 使用Godot的内置分析器，添加自定义性能监控，分析FPS和内存使用情况。

### Q: 内存使用过高怎么办？
A: 检查资源加载，使用对象池，及时释放不需要的对象，优化纹理大小。

### Q: 如何优化大量对象的渲染？
A: 使用MultiMesh批处理，实现视锥剔除，使用LOD系统，合并相同材质的对象。

### Q: 网络延迟如何优化？
A: 减少网络请求频率，压缩传输数据，使用预测和插值，实现客户端预测。

---

**记住：性能优化是一个持续的过程，需要在开发的各个阶段都保持关注！**