""" 动态音乐系统插件 根据游戏状态和环境条件动态生成和控制音乐 """ import math import time import uuid from typing import Dict, List, Optional, Any, Callable from plugins.plugin_manager import BasePlugin from panda3d.core import AudioSound, NodePath class Plugin(BasePlugin): """ 动态音乐系统插件 根据游戏状态和环境条件动态生成和控制音乐 """ def __init__(self, plugin_manager, name): super().__init__(plugin_manager, name) self.config = { "version": "1.0.0", "author": "EG Team", "description": "动态音乐系统,支持根据游戏状态和环境条件实时生成和控制音乐" } # 核心组件 self.music_manager = None self.transition_manager = None self.composition_engine = None self.analysis_engine = None self.effect_processor = None # 音乐状态 self.current_theme = None self.current_intensity = 0.0 self.target_intensity = 0.0 self.intensity_change_rate = 1.0 self.current_layer_volumes = {} # 游戏状态跟踪 self.game_state = {} self.environment_conditions = {} self.player_state = {} # 音乐库 self.themes = {} self.layers = {} self.transitions = {} self.sound_effects = {} # GUI元素 self.gui_elements = [] # 事件处理器 self.event_handlers = {} # 插件状态 self.is_initialized = False self.is_enabled = False self.is_playing = False # 性能监控 self.performance_stats = { 'initialization_time': 0.0, 'enable_time': 0.0, 'last_update_time': 0.0, 'total_updates': 0, 'total_processing_time': 0.0, 'themes_loaded': 0, 'transitions_processed': 0 } # 配置参数 self.master_volume = 1.0 self.crossfade_duration = 2.0 self.intensity_smoothing = 0.1 self.auto_intensity = True def initialize(self) -> bool: """ 初始化插件 """ try: if self.is_initialized: return True init_start_time = time.time() print(f"初始化动态音乐系统插件: {self.name}") # 初始化核心组件 from .core.music_manager import MusicManager from .transitions.transition_manager import TransitionManager from .composition.composition_engine import CompositionEngine from .analysis.analysis_engine import AnalysisEngine from .effects.effect_processor import EffectProcessor self.music_manager = MusicManager(self) self.transition_manager = TransitionManager(self) self.composition_engine = CompositionEngine(self) self.analysis_engine = AnalysisEngine(self) self.effect_processor = EffectProcessor(self) # 加载音乐资源 self._load_music_resources() self.is_initialized = True self.performance_stats['initialization_time'] = time.time() - init_start_time print("✓ 动态音乐系统插件初始化完成") return True except Exception as e: print(f"✗ 动态音乐系统插件初始化失败: {e}") import traceback traceback.print_exc() return False def enable(self) -> bool: """ 启用插件 """ if not super().enable(): return False if self.is_enabled: return True try: enable_start_time = time.time() print(f"启用动态音乐系统插件: {self.name}") # 注册事件处理器 self._register_event_handlers() # 创建GUI界面 self._create_gui() self.is_enabled = True self.performance_stats['enable_time'] = time.time() - enable_start_time print("✓ 动态音乐系统插件启用成功") return True except Exception as e: print(f"✗ 动态音乐系统插件启用失败: {e}") import traceback traceback.print_exc() return False def disable(self) -> bool: """ 禁用插件 """ if not super().disable(): return False if not self.is_enabled: return True try: print(f"禁用动态音乐系统插件: {self.name}") # 清理GUI界面 self._cleanup_gui() # 移除事件处理器 self._unregister_event_handlers() # 停止所有音乐 self.stop_all_music() self.is_enabled = False print("✓ 动态音乐系统插件禁用成功") return True except Exception as e: print(f"✗ 动态音乐系统插件禁用失败: {e}") import traceback traceback.print_exc() return False def finalize(self): """ 清理插件资源 """ print(f"清理动态音乐系统插件资源: {self.name}") # 停止所有音乐 self.stop_all_music() # 清理所有组件 components = [ self.music_manager, self.transition_manager, self.composition_engine, self.analysis_engine, self.effect_processor ] for component in components: if component: component.cleanup() self.music_manager = None self.transition_manager = None self.composition_engine = None self.analysis_engine = None self.effect_processor = None self.themes.clear() self.layers.clear() self.transitions.clear() self.sound_effects.clear() self.is_initialized = False self.is_enabled = False def _register_event_handlers(self): """ 注册事件处理器 """ world = self.plugin_manager.world # 音乐控制快捷键 self.event_handlers['f1'] = self.toggle_debug_mode self.event_handlers['f2'] = self.toggle_music_system self.event_handlers['f3'] = self.play_test_theme self.event_handlers['f4'] = self.increase_intensity self.event_handlers['f5'] = self.decrease_intensity self.event_handlers['f6'] = self.trigger_battle_music self.event_handlers['f7'] = self.trigger_exploration_music self.event_handlers['f8'] = self.trigger_ambient_music self.event_handlers['f9'] = self.show_stats self.event_handlers['f10'] = self.toggle_auto_intensity self.event_handlers['f11'] = self.show_detailed_stats self.event_handlers['f12'] = self.reset_music_system # 注册事件 for event, handler in self.event_handlers.items(): world.accept(event, handler) world.accept(event.upper(), handler) # 同时注册大写事件 def _unregister_event_handlers(self): """ 移除事件处理器 """ world = self.plugin_manager.world for event in self.event_handlers.keys(): world.ignore(event) world.ignore(event.upper()) self.event_handlers.clear() def _create_gui(self): """ 创建GUI界面 """ try: world = self.plugin_manager.world # 检查是否有GUI管理器 if not hasattr(world, 'gui_manager') or not world.gui_manager: print("⚠ GUI管理器不可用,跳过GUI创建") return gui_manager = world.gui_manager # 创建音乐系统控制面板 panel_button = gui_manager.createGUIButton( pos=(0.7, 0, 0.35), text="动态音乐", size=0.06 ) self.gui_elements.append(panel_button) # 创建功能按钮 functions = [ ("调试模式 [F1]", self.toggle_debug_mode), ("切换系统 [F2]", self.toggle_music_system), ("测试主题 [F3]", self.play_test_theme), ("增加强度 [F4]", self.increase_intensity), ("降低强度 [F5]", self.decrease_intensity), ("战斗音乐 [F6]", self.trigger_battle_music), ("探索音乐 [F7]", self.trigger_exploration_music), ("环境音乐 [F8]", self.trigger_ambient_music), ("音乐统计 [F9]", self.show_stats), ("自动强度 [F10]", self.toggle_auto_intensity), ("详细统计 [F11]", self.show_detailed_stats), ("重置系统 [F12]", self.reset_music_system) ] for i, (name, callback) in enumerate(functions): button = gui_manager.createGUIButton( pos=(0.7, 0, 0.28 - i * 0.055), text=name, size=0.045 ) self.gui_elements.append(button) world.accept(f"music_system_function_{i}", callback) except Exception as e: print(f"⚠ GUI创建失败: {e}") def _cleanup_gui(self): """ 清理GUI界面 """ try: world = self.plugin_manager.world if hasattr(world, 'gui_manager') and world.gui_manager: gui_manager = world.gui_manager # 删除所有GUI元素 for element in self.gui_elements: gui_manager.deleteGUIElement(element) self.gui_elements.clear() except Exception as e: print(f"⚠ GUI清理失败: {e}") # 事件处理方法 def toggle_debug_mode(self): """切换调试模式""" print("✓ 动态音乐系统调试模式切换") def toggle_music_system(self): """切换音乐系统""" if self.is_playing: self.stop_all_music() print("✓ 动态音乐系统已停止") else: self.play_theme("ambient") print("✓ 动态音乐系统已启动") def play_test_theme(self): """播放测试主题""" print("✓ 播放测试音乐主题") try: # 创建一个测试主题 self.create_theme("test_theme", { 'layers': ['test_layer_1', 'test_layer_2'], 'bpm': 120, 'key': 'C', 'mood': 'neutral' }) self.play_theme("test_theme") except Exception as e: print(f"✗ 播放测试主题失败: {e}") def increase_intensity(self): """增加音乐强度""" self.target_intensity = min(1.0, self.target_intensity + 0.1) print(f"✓ 音乐强度增加到: {self.target_intensity:.2f}") def decrease_intensity(self): """降低音乐强度""" self.target_intensity = max(0.0, self.target_intensity - 0.1) print(f"✓ 音乐强度降低到: {self.target_intensity:.2f}") def trigger_battle_music(self): """触发战斗音乐""" print("✓ 触发战斗音乐") self.target_intensity = 1.0 # 这里可以添加更多战斗音乐相关的逻辑 def trigger_exploration_music(self): """触发探索音乐""" print("✓ 触发探索音乐") self.target_intensity = 0.6 # 这里可以添加更多探索音乐相关的逻辑 def trigger_ambient_music(self): """触发环境音乐""" print("✓ 触发环境音乐") self.target_intensity = 0.3 # 这里可以添加更多环境音乐相关的逻辑 def show_stats(self): """显示音乐系统统计信息""" stats = self.get_stats() print("=== 动态音乐系统统计信息 ===") for key, value in stats.items(): print(f" {key}: {value}") def toggle_auto_intensity(self): """切换自动强度控制""" self.auto_intensity = not self.auto_intensity print(f"✓ 自动强度控制已{'启用' if self.auto_intensity else '禁用'}") def show_detailed_stats(self): """显示详细统计信息""" print("=== 动态音乐系统详细统计信息 ===") # 显示各组件统计 components = [ ('音乐管理器', self.music_manager), ('过渡管理器', self.transition_manager), ('作曲引擎', self.composition_engine), ('分析引擎', self.analysis_engine), ('效果处理器', self.effect_processor) ] for name, component in components: if component: component_stats = component.get_stats() print(f"{name}统计:") for key, value in component_stats.items(): print(f" {key}: {value}") # 显示性能统计 perf_stats = self.performance_stats print("性能统计:") for key, value in perf_stats.items(): print(f" {key}: {value}") def reset_music_system(self): """重置音乐系统""" print("✓ 重置动态音乐系统") self.current_theme = None self.current_intensity = 0.0 self.target_intensity = 0.0 self.current_layer_volumes.clear() self.stop_all_music() print("✓ 动态音乐系统已重置") def _load_music_resources(self): """加载音乐资源""" # 这里应该加载实际的音乐文件 # 为演示目的,我们创建一些虚拟的音乐主题和层 # 创建示例主题 self.themes = { 'ambient': { 'layers': ['ambient_base', 'ambient_high'], 'bpm': 60, 'key': 'Am', 'mood': 'calm' }, 'exploration': { 'layers': ['exploration_base', 'exploration_melody'], 'bpm': 90, 'key': 'C', 'mood': 'adventurous' }, 'battle': { 'layers': ['battle_drums', 'battle_melody', 'battle_bass'], 'bpm': 140, 'key': 'Em', 'mood': 'intense' }, 'victory': { 'layers': ['victory_fanfare', 'victory_melody'], 'bpm': 120, 'key': 'C', 'mood': 'triumphant' }, 'defeat': { 'layers': ['defeat_ambient', 'defeat_melody'], 'bpm': 50, 'key': 'Am', 'mood': 'melancholic' } } # 创建示例层 self.layers = { 'ambient_base': {'volume': 0.6, 'loop': True, 'priority': 1}, 'ambient_high': {'volume': 0.3, 'loop': True, 'priority': 2}, 'exploration_base': {'volume': 0.7, 'loop': True, 'priority': 1}, 'exploration_melody': {'volume': 0.5, 'loop': True, 'priority': 2}, 'battle_drums': {'volume': 0.8, 'loop': True, 'priority': 1}, 'battle_melody': {'volume': 0.7, 'loop': True, 'priority': 2}, 'battle_bass': {'volume': 0.6, 'loop': True, 'priority': 3}, 'victory_fanfare': {'volume': 1.0, 'loop': False, 'priority': 1}, 'victory_melody': {'volume': 0.8, 'loop': False, 'priority': 2}, 'defeat_ambient': {'volume': 0.4, 'loop': True, 'priority': 1}, 'defeat_melody': {'volume': 0.6, 'loop': True, 'priority': 2} } # 创建示例过渡 self.transitions = { 'ambient_to_exploration': { 'from_theme': 'ambient', 'to_theme': 'exploration', 'duration': 3.0, 'type': 'crossfade' }, 'exploration_to_battle': { 'from_theme': 'exploration', 'to_theme': 'battle', 'duration': 2.0, 'type': 'crossfade' }, 'battle_to_victory': { 'from_theme': 'battle', 'to_theme': 'victory', 'duration': 1.5, 'type': 'cut' }, 'battle_to_defeat': { 'from_theme': 'battle', 'to_theme': 'defeat', 'duration': 1.5, 'type': 'cut' } } self.performance_stats['themes_loaded'] = len(self.themes) print("✓ 音乐资源加载完成") def get_stats(self) -> Dict[str, Any]: """ 获取插件统计信息 Returns: 统计信息字典 """ stats = self.performance_stats.copy() # 收集各组件统计 components = [ self.music_manager, self.transition_manager, self.composition_engine, self.analysis_engine, self.effect_processor ] component_names = [ 'music', 'transition', 'composition', 'analysis', 'effect' ] for i, component in enumerate(components): if component: component_stats = component.get_stats() for key, value in component_stats.items(): stats[f"{component_names[i]}_{key}"] = value # 添加音乐系统统计 stats['current_theme'] = self.current_theme stats['current_intensity'] = self.current_intensity stats['target_intensity'] = self.target_intensity stats['is_playing'] = self.is_playing stats['auto_intensity'] = self.auto_intensity return stats # 公共接口方法 def create_theme(self, theme_name: str, theme_data: Dict[str, Any]) -> bool: """ 创建音乐主题 Args: theme_name: 主题名称 theme_data: 主题数据 Returns: 是否创建成功 """ try: self.themes[theme_name] = theme_data.copy() print(f"✓ 音乐主题创建成功: {theme_name}") return True except Exception as e: print(f"✗ 创建音乐主题失败: {e}") return False def play_theme(self, theme_name: str, force: bool = False) -> bool: """ 播放音乐主题 Args: theme_name: 主题名称 force: 是否强制播放(跳过过渡) Returns: 是否播放成功 """ if theme_name not in self.themes: print(f"✗ 音乐主题不存在: {theme_name}") return False try: if self.music_manager: success = self.music_manager.play_theme(theme_name, force) if success: self.current_theme = theme_name self.is_playing = True print(f"✓ 音乐主题开始播放: {theme_name}") return success return False except Exception as e: print(f"✗ 播放音乐主题失败: {e}") return False def stop_theme(self, theme_name: str) -> bool: """ 停止音乐主题 Args: theme_name: 主题名称 Returns: 是否停止成功 """ if theme_name not in self.themes: print(f"✗ 音乐主题不存在: {theme_name}") return False try: if self.music_manager: success = self.music_manager.stop_theme(theme_name) if success and self.current_theme == theme_name: self.current_theme = None if not self.music_manager.get_active_themes(): self.is_playing = False print(f"✓ 音乐主题已停止: {theme_name}") return success return False except Exception as e: print(f"✗ 停止音乐主题失败: {e}") return False def stop_all_music(self): """停止所有音乐""" try: if self.music_manager: self.music_manager.stop_all() self.current_theme = None self.is_playing = False print("✓ 所有音乐已停止") except Exception as e: print(f"✗ 停止所有音乐失败: {e}") def set_intensity(self, intensity: float): """ 设置音乐强度 Args: intensity: 强度值 (0.0-1.0) """ self.target_intensity = max(0.0, min(1.0, intensity)) print(f"✓ 音乐强度设置为: {self.target_intensity:.2f}") def get_intensity(self) -> float: """ 获取当前音乐强度 Returns: 当前强度值 (0.0-1.0) """ return self.current_intensity def set_layer_volume(self, layer_name: str, volume: float): """ 设置音乐层音量 Args: layer_name: 层名称 volume: 音量值 (0.0-1.0) """ if self.music_manager: self.music_manager.set_layer_volume(layer_name, volume) self.current_layer_volumes[layer_name] = volume print(f"✓ 音乐层 {layer_name} 音量设置为: {volume:.2f}") def get_layer_volume(self, layer_name: str) -> float: """ 获取音乐层音量 Args: layer_name: 层名称 Returns: 音量值 (0.0-1.0) """ return self.current_layer_volumes.get(layer_name, 1.0) def create_transition(self, transition_name: str, transition_data: Dict[str, Any]) -> bool: """ 创建音乐过渡 Args: transition_name: 过渡名称 transition_data: 过渡数据 Returns: 是否创建成功 """ try: self.transitions[transition_name] = transition_data.copy() if self.transition_manager: self.transition_manager.register_transition(transition_name, transition_data) print(f"✓ 音乐过渡创建成功: {transition_name}") return True except Exception as e: print(f"✗ 创建音乐过渡失败: {e}") return False def trigger_transition(self, transition_name: str) -> bool: """ 触发音乐过渡 Args: transition_name: 过渡名称 Returns: 是否触发成功 """ if transition_name not in self.transitions: print(f"✗ 音乐过渡不存在: {transition_name}") return False try: if self.transition_manager: success = self.transition_manager.trigger_transition(transition_name) if success: self.performance_stats['transitions_processed'] += 1 print(f"✓ 音乐过渡已触发: {transition_name}") return success return False except Exception as e: print(f"✗ 触发音乐过渡失败: {e}") return False def set_game_state(self, state: Dict[str, Any]): """ 设置游戏状态 Args: state: 游戏状态字典 """ self.game_state.update(state) print(f"✓ 游戏状态已更新: {state}") def set_environment_conditions(self, conditions: Dict[str, Any]): """ 设置环境条件 Args: conditions: 环境条件字典 """ self.environment_conditions.update(conditions) print(f"✓ 环境条件已更新: {conditions}") def set_player_state(self, state: Dict[str, Any]): """ 设置玩家状态 Args: state: 玩家状态字典 """ self.player_state.update(state) print(f"✓ 玩家状态已更新: {state}") def set_master_volume(self, volume: float): """ 设置主音量 Args: volume: 主音量 (0.0-1.0) """ self.master_volume = max(0.0, min(1.0, volume)) if self.music_manager: self.music_manager.set_master_volume(self.master_volume) print(f"✓ 主音量已设置: {self.master_volume:.2f}") def get_master_volume(self) -> float: """ 获取主音量 Returns: 主音量 (0.0-1.0) """ return self.master_volume def update(self, dt: float): """ 更新插件状态 Args: dt: 时间增量 """ update_start_time = time.time() # 更新当前强度(平滑过渡到目标强度) if self.current_intensity != self.target_intensity: intensity_diff = self.target_intensity - self.current_intensity self.current_intensity += intensity_diff * self.intensity_smoothing # 确保不会超过目标值 if (intensity_diff > 0 and self.current_intensity > self.target_intensity) or \ (intensity_diff < 0 and self.current_intensity < self.target_intensity): self.current_intensity = self.target_intensity # 更新各组件 components = [ self.music_manager, self.transition_manager, self.composition_engine, self.analysis_engine, self.effect_processor ] for component in components: if component: component.update(dt) # 更新性能统计 self.performance_stats['total_updates'] += 1 self.performance_stats['last_update_time'] = time.time() self.performance_stats['total_processing_time'] += (time.time() - update_start_time) # 自动强度控制 if self.auto_intensity: self._update_auto_intensity() def _update_auto_intensity(self): """更新自动强度控制""" # 基于游戏状态自动调整音乐强度 # 这里是一个简化的实现,实际应用中会更复杂 # 检查是否有战斗状态 if self.game_state.get('in_combat', False): self.target_intensity = 1.0 # 检查是否有探索状态 elif self.game_state.get('exploring', False): self.target_intensity = 0.6 # 默认环境音乐 else: self.target_intensity = 0.3