""" 骨骼动画系统插件 提供完整的骨骼动画支持,包括加载、播放、控制、混合等高级功能 """ from plugins.plugin_manager import BasePlugin from direct.actor.Actor import Actor from direct.interval.IntervalGlobal import * from panda3d.core import Filename, ConfigVariableBool from panda3d.core import NodePath, Vec3, Point3 import os import json import math # 导入高级功能模块 from .advanced_features import AdvancedAnimationManager from .animation_optimization import AnimationCompression, AnimationCaching, AnimationLOD from .network_sync import DistributedAnimationManager, AnimationStateSerializer class SkeletalAnimationManager: """ 骨骼动画管理器类 负责管理场景中所有的骨骼动画Actor """ def __init__(self, world): self.world = world self.actors = {} # 存储所有Actor {actor_id: actor_object} self.actor_configs = {} # 存储Actor配置 {actor_id: config_dict} self.active_animations = {} # 存储活动动画 {actor_id: {anim_name: control_object}} self.animation_intervals = {} # 存储动画间隔 {actor_id: {interval_name: interval_object}} self.blend_intervals = {} # 存储混合动画 {actor_id: {blend_name: blend_object}} # 高级功能管理器 self.advanced_managers = {} # {actor_id: AdvancedAnimationManager} self.compression_system = AnimationCompression() self.caching_system = AnimationCaching() self.lod_system = AnimationLOD(world) self.distributed_manager = DistributedAnimationManager(world) self.serializer = AnimationStateSerializer() def load_actor(self, model_path, anim_dict=None, actor_id=None, position=None, scale=None): """ 加载Actor模型 :param model_path: 模型文件路径 :param anim_dict: 动画字典,格式 {'anim_name': 'anim_path'} :param actor_id: Actor标识符,如果为None则自动生成 :param position: 位置坐标 (x, y, z) :param scale: 缩放比例 (x, y, z) 或单个数值 :return: Actor对象和actor_id """ try: if not os.path.exists(model_path): print(f"错误: 模型文件不存在: {model_path}") return None, None if actor_id is None: actor_id = f"actor_{len(self.actors)}" # 检查缓存 cached_actor = self.caching_system.get_cached_animation(actor_id, "model") if cached_actor: actor = cached_actor else: # 创建Actor if anim_dict: # 验证动画文件存在性 validated_anims = {} for anim_name, anim_path in anim_dict.items(): if os.path.exists(anim_path): validated_anims[anim_name] = anim_path else: print(f"警告: 动画文件不存在: {anim_path}") actor = Actor(model_path, validated_anims) else: actor = Actor(model_path) # 缓存Actor self.caching_system.cache_animation(actor_id, "model", actor) # 设置位置和缩放 if position: actor.setPos(*position) if scale: if isinstance(scale, (int, float)): actor.setScale(scale) else: actor.setScale(*scale) # 将Actor添加到场景中 actor.reparentTo(self.world.render) actor.setName(actor_id) # 存储Actor和配置 self.actors[actor_id] = actor self.actor_configs[actor_id] = { 'model_path': model_path, 'anim_dict': anim_dict, 'position': position, 'scale': scale } # 创建高级动画管理器 self.advanced_managers[actor_id] = AdvancedAnimationManager(actor) print(f"成功加载Actor: {actor_id}") print(f" 模型: {model_path}") print(f" 位置: {position}") print(f" 缩放: {scale}") print(f" 可用动画: {actor.getAnimNames()}") return actor, actor_id except Exception as e: print(f"加载Actor失败: {e}") import traceback traceback.print_exc() return None, None def unload_actor(self, actor_id): """ 卸载Actor :param actor_id: 要卸载的Actor标识符 """ if actor_id in self.actors: # 停止所有活动动画 self.stop_all_animations(actor_id) # 清理混合动画 if actor_id in self.blend_intervals: for blend in self.blend_intervals[actor_id].values(): if blend: blend.finish() del self.blend_intervals[actor_id] # 清理动画间隔 if actor_id in self.animation_intervals: for interval in self.animation_intervals[actor_id].values(): if interval: interval.finish() del self.animation_intervals[actor_id] # 清理高级动画管理器 if actor_id in self.advanced_managers: del self.advanced_managers[actor_id] # 清理Actor actor = self.actors[actor_id] actor.cleanup() del self.actors[actor_id] # 清理配置 if actor_id in self.actor_configs: del self.actor_configs[actor_id] # 清理活动动画记录 if actor_id in self.active_animations: del self.active_animations[actor_id] # 使缓存失效 self.caching_system.invalidate_cache(actor_id) print(f"已卸载Actor: {actor_id}") def get_actor(self, actor_id): """ 获取Actor对象 :param actor_id: Actor标识符 :return: Actor对象或None """ return self.actors.get(actor_id) def get_actor_animations(self, actor_id): """ 获取Actor的所有动画名称 :param actor_id: Actor标识符 :return: 动画名称列表 """ if actor_id in self.actors: return self.actors[actor_id].getAnimNames() return [] def play_animation(self, actor_id, anim_name, loop=False, play_rate=1.0, start_frame=None, end_frame=None): """ 播放动画 :param actor_id: Actor标识符 :param anim_name: 动画名称 :param loop: 是否循环播放 :param play_rate: 播放速度 :param start_frame: 起始帧 :param end_frame: 结束帧 """ if actor_id not in self.actors: print(f"错误: Actor {actor_id} 不存在") return False actor = self.actors[actor_id] # 检查动画是否存在 if anim_name not in actor.getAnimNames(): print(f"错误: 动画 {anim_name} 不存在于Actor {actor_id} 中") print(f" 可用动画: {actor.getAnimNames()}") return False try: # 设置播放速度 actor.setPlayRate(play_rate, anim_name) # 播放动画 if loop: if start_frame is not None and end_frame is not None: actor.loop(anim_name, restart=False, fromFrame=start_frame, toFrame=end_frame) else: actor.loop(anim_name, restart=False) else: if start_frame is not None and end_frame is not None: actor.play(anim_name, fromFrame=start_frame, toFrame=end_frame) else: actor.play(anim_name) # 记录活动动画 if actor_id not in self.active_animations: self.active_animations[actor_id] = {} self.active_animations[actor_id][anim_name] = actor.getAnimControl(anim_name) print(f"播放动画: {anim_name} (Actor: {actor_id}, 循环: {loop}, 速度: {play_rate}x)") return True except Exception as e: print(f"播放动画失败: {e}") import traceback traceback.print_exc() return False def stop_animation(self, actor_id, anim_name=None): """ 停止动画 :param actor_id: Actor标识符 :param anim_name: 动画名称,如果为None则停止所有动画 """ if actor_id not in self.actors: print(f"错误: Actor {actor_id} 不存在") return actor = self.actors[actor_id] try: if anim_name: # 停止指定动画 if anim_name in actor.getAnimNames(): actor.stop(anim_name) # 从活动动画中移除 if actor_id in self.active_animations and anim_name in self.active_animations[actor_id]: del self.active_animations[actor_id][anim_name] print(f"停止动画: {anim_name} (Actor: {actor_id})") else: print(f"警告: 动画 {anim_name} 不存在于Actor {actor_id} 中") else: # 停止所有动画 actor.stop() # 清空活动动画记录 if actor_id in self.active_animations: self.active_animations[actor_id].clear() print(f"停止所有动画 (Actor: {actor_id})") except Exception as e: print(f"停止动画失败: {e}") import traceback traceback.print_exc() def stop_all_animations(self, actor_id): """ 停止指定Actor的所有动画 :param actor_id: Actor标识符 """ self.stop_animation(actor_id) def set_animation_speed(self, actor_id, anim_name, speed): """ 设置动画播放速度 :param actor_id: Actor标识符 :param anim_name: 动画名称 :param speed: 播放速度 """ if actor_id not in self.actors: print(f"错误: Actor {actor_id} 不存在") return actor = self.actors[actor_id] try: if anim_name in actor.getAnimNames(): actor.setPlayRate(speed, anim_name) print(f"设置动画速度: {anim_name} 为 {speed}x (Actor: {actor_id})") else: print(f"警告: 动画 {anim_name} 不存在于Actor {actor_id} 中") except Exception as e: print(f"设置动画速度失败: {e}") import traceback traceback.print_exc() def pause_animation(self, actor_id, anim_name=None): """ 暂停动画 :param actor_id: Actor标识符 :param anim_name: 动画名称,如果为None则暂停所有动画 """ if actor_id not in self.actors: print(f"错误: Actor {actor_id} 不存在") return actor = self.actors[actor_id] try: if anim_name: if anim_name in actor.getAnimNames(): control = actor.getAnimControl(anim_name) if control and control.isPlaying(): control.setPlayRate(0) # 通过设置播放速度为0来模拟暂停 print(f"暂停动画: {anim_name} (Actor: {actor_id})") else: print(f"警告: 动画 {anim_name} 不存在于Actor {actor_id} 中") else: # 暂停所有活动动画 if actor_id in self.active_animations: for anim_name, control in self.active_animations[actor_id].items(): if control and control.isPlaying(): control.setPlayRate(0) print(f"暂停所有动画 (Actor: {actor_id})") except Exception as e: print(f"暂停动画失败: {e}") import traceback traceback.print_exc() def resume_animation(self, actor_id, anim_name=None): """ 恢复动画播放 :param actor_id: Actor标识符 :param anim_name: 动画名称,如果为None则恢复所有动画 """ if actor_id not in self.actors: print(f"错误: Actor {actor_id} 不存在") return actor = self.actors[actor_id] try: if anim_name: if anim_name in actor.getAnimNames(): control = actor.getAnimControl(anim_name) if control and control.getPlayRate() == 0: control.setPlayRate(1.0) # 恢复正常播放速度 print(f"恢复动画: {anim_name} (Actor: {actor_id})") else: print(f"警告: 动画 {anim_name} 不存在于Actor {actor_id} 中") else: # 恢复所有暂停的动画 if actor_id in self.active_animations: for anim_name, control in self.active_animations[actor_id].items(): if control and control.getPlayRate() == 0: control.setPlayRate(1.0) print(f"恢复所有动画 (Actor: {actor_id})") except Exception as e: print(f"恢复动画失败: {e}") import traceback traceback.print_exc() def get_animation_info(self, actor_id, anim_name): """ 获取动画信息 :param actor_id: Actor标识符 :param anim_name: 动画名称 :return: 动画信息字典 """ if actor_id not in self.actors: print(f"错误: Actor {actor_id} 不存在") return None actor = self.actors[actor_id] if anim_name not in actor.getAnimNames(): print(f"错误: 动画 {anim_name} 不存在于Actor {actor_id} 中") return None try: control = actor.getAnimControl(anim_name) info = { 'name': anim_name, 'frame_rate': actor.getFrameRate(anim_name), 'num_frames': actor.getNumFrames(anim_name), 'play_rate': actor.getPlayRate(anim_name), 'is_playing': control.isPlaying() if control else False, 'is_paused': control.getPlayRate() == 0 if control else False, 'current_frame': actor.getCurrentFrame(anim_name) if control else 0 } return info except Exception as e: print(f"获取动画信息失败: {e}") import traceback traceback.print_exc() return None def blend_animations(self, actor_id, from_anim, to_anim, blend_time=1.0, loop=True): """ 混合两个动画 :param actor_id: Actor标识符 :param from_anim: 起始动画名称 :param to_anim: 目标动画名称 :param blend_time: 混合时间 :param loop: 是否循环混合 """ if actor_id not in self.actors: print(f"错误: Actor {actor_id} 不存在") return None actor = self.actors[actor_id] # 检查动画是否存在 if from_anim not in actor.getAnimNames(): print(f"错误: 起始动画 {from_anim} 不存在于Actor {actor_id} 中") return None if to_anim not in actor.getAnimNames(): print(f"错误: 目标动画 {to_anim} 不存在于Actor {actor_id} 中") return None try: # 创建动画混合 blend_name = f"{from_anim}_to_{to_anim}" blend = actor.actorInterval(from_anim, endTime=actor.getDuration(from_anim)) \ + actor.actorInterval(to_anim, loop=loop) # 存储混合动画 if actor_id not in self.blend_intervals: self.blend_intervals[actor_id] = {} self.blend_intervals[actor_id][blend_name] = blend # 播放混合动画 blend.start() print(f"开始动画混合: {from_anim} -> {to_anim} (Actor: {actor_id}, 时间: {blend_time}s)") return blend except Exception as e: print(f"动画混合失败: {e}") import traceback traceback.print_exc() return None def stop_blend(self, actor_id, blend_name=None): """ 停止动画混合 :param actor_id: Actor标识符 :param blend_name: 混合动画名称,如果为None则停止所有混合 """ if actor_id not in self.blend_intervals: return try: if blend_name: if blend_name in self.blend_intervals[actor_id]: blend = self.blend_intervals[actor_id][blend_name] if blend: blend.finish() del self.blend_intervals[actor_id][blend_name] print(f"停止动画混合: {blend_name} (Actor: {actor_id})") else: # 停止所有混合 for blend in self.blend_intervals[actor_id].values(): if blend: blend.finish() self.blend_intervals[actor_id].clear() print(f"停止所有动画混合 (Actor: {actor_id})") except Exception as e: print(f"停止动画混合失败: {e}") import traceback traceback.print_exc() def create_animation_sequence(self, actor_id, anim_list, loop=False): """ 创建动画序列 :param actor_id: Actor标识符 :param anim_list: 动画名称列表 :param loop: 是否循环播放序列 :return: 序列间隔对象 """ if actor_id not in self.actors: print(f"错误: Actor {actor_id} 不存在") return None actor = self.actors[actor_id] try: # 验证动画存在性 for anim_name in anim_list: if anim_name not in actor.getAnimNames(): print(f"错误: 动画 {anim_name} 不存在于Actor {actor_id} 中") return None # 创建动画序列 sequence = Sequence() for anim_name in anim_list: interval = actor.actorInterval(anim_name) sequence.append(interval) # 存储序列 sequence_name = f"seq_{'_'.join(anim_list)}" if actor_id not in self.animation_intervals: self.animation_intervals[actor_id] = {} self.animation_intervals[actor_id][sequence_name] = sequence # 设置循环 if loop: sequence.loop() else: sequence.start() print(f"创建动画序列: {sequence_name} (Actor: {actor_id})") return sequence except Exception as e: print(f"创建动画序列失败: {e}") import traceback traceback.print_exc() return None def stop_animation_sequence(self, actor_id, sequence_name=None): """ 停止动画序列 :param actor_id: Actor标识符 :param sequence_name: 序列名称,如果为None则停止所有序列 """ if actor_id not in self.animation_intervals: return try: if sequence_name: if sequence_name in self.animation_intervals[actor_id]: sequence = self.animation_intervals[actor_id][sequence_name] if sequence: sequence.finish() del self.animation_intervals[actor_id][sequence_name] print(f"停止动画序列: {sequence_name} (Actor: {actor_id})") else: # 停止所有序列 for sequence in self.animation_intervals[actor_id].values(): if sequence: sequence.finish() self.animation_intervals[actor_id].clear() print(f"停止所有动画序列 (Actor: {actor_id})") except Exception as e: print(f"停止动画序列失败: {e}") import traceback traceback.print_exc() def get_actor_info(self, actor_id): """ 获取Actor详细信息 :param actor_id: Actor标识符 :return: Actor信息字典 """ if actor_id not in self.actors: print(f"错误: Actor {actor_id} 不存在") return None actor = self.actors[actor_id] config = self.actor_configs.get(actor_id, {}) try: info = { 'id': actor_id, 'model_path': config.get('model_path'), 'position': actor.getPos().toTuple(), 'scale': actor.getScale().toTuple(), 'available_animations': actor.getAnimNames(), 'active_animations': list(self.active_animations.get(actor_id, {}).keys()), 'has_character': actor.hasCharacter(), 'num_parts': actor.getNumParts(), 'bounds': { 'min': actor.getTightBounds()[0].toTuple() if actor.getTightBounds() else None, 'max': actor.getTightBounds()[1].toTuple() if actor.getTightBounds() else None } } return info except Exception as e: print(f"获取Actor信息失败: {e}") import traceback traceback.print_exc() return None def set_actor_position(self, actor_id, x, y, z): """ 设置Actor位置 :param actor_id: Actor标识符 :param x: X坐标 :param y: Y坐标 :param z: Z坐标 """ if actor_id in self.actors: self.actors[actor_id].setPos(x, y, z) # 更新配置 if actor_id in self.actor_configs: self.actor_configs[actor_id]['position'] = (x, y, z) print(f"设置Actor {actor_id} 位置: ({x}, {y}, {z})") def set_actor_scale(self, actor_id, scale): """ 设置Actor缩放 :param actor_id: Actor标识符 :param scale: 缩放值 (数值或(x, y, z)元组) """ if actor_id in self.actors: if isinstance(scale, (int, float)): self.actors[actor_id].setScale(scale) else: self.actors[actor_id].setScale(*scale) # 更新配置 if actor_id in self.actor_configs: self.actor_configs[actor_id]['scale'] = scale print(f"设置Actor {actor_id} 缩放: {scale}") def get_advanced_manager(self, actor_id): """ 获取指定Actor的高级动画管理器 :param actor_id: Actor标识符 :return: AdvancedAnimationManager实例 """ return self.advanced_managers.get(actor_id) def compress_animation(self, actor_id, anim_name, output_path=None): """ 压缩指定动画 :param actor_id: Actor标识符 :param anim_name: 动画名称 :param output_path: 输出路径 """ if actor_id in self.actors: actor = self.actors[actor_id] return self.compression_system.compress_animation(actor, anim_name, output_path) return None def get_cache_stats(self): """ 获取缓存统计信息 :return: 缓存统计 """ return self.caching_system.get_cache_stats() def update_lod(self, camera_pos): """ 更新LOD系统 :param camera_pos: 摄像机位置 """ self.lod_system.update_lod_levels(camera_pos) def get_lod_stats(self): """ 获取LOD统计信息 :return: LOD统计 """ return self.lod_system.get_lod_stats() def enable_distributed_mode(self, mode='server'): """ 启用分布式模式 :param mode: 模式 ('server' 或 'client') """ self.distributed_manager.enable_distributed_mode(mode) def create_distributed_actor(self, actor_id, model_path, anim_dict=None): """ 创建分布式Actor :param actor_id: Actor ID :param model_path: 模型路径 :param anim_dict: 动画字典 :return: Actor对象 """ return self.distributed_manager.create_distributed_actor(actor_id, model_path, anim_dict) def serialize_actor_state(self, actor_id, file_path=None): """ 序列化Actor状态 :param actor_id: Actor ID :param file_path: 文件路径 """ if actor_id in self.actors: actor = self.actors[actor_id] if file_path: self.serializer.save_state_to_file(actor, file_path) else: return self.serializer.serialize_actor_state(actor) return None class AnimationEventManager: """ 动画事件管理器 处理动画事件和回调 """ def __init__(self, world, animation_manager): self.world = world self.animation_manager = animation_manager self.event_callbacks = {} # 存储事件回调 {event_name: [callback_list]} def register_event_callback(self, event_name, callback): """ 注册事件回调 :param event_name: 事件名称 :param callback: 回调函数 """ if event_name not in self.event_callbacks: self.event_callbacks[event_name] = [] self.event_callbacks[event_name].append(callback) print(f"注册事件回调: {event_name}") def unregister_event_callback(self, event_name, callback): """ 注销事件回调 :param event_name: 事件名称 :param callback: 回调函数 """ if event_name in self.event_callbacks: if callback in self.event_callbacks[event_name]: self.event_callbacks[event_name].remove(callback) print(f"注销事件回调: {event_name}") def trigger_event(self, event_name, *args, **kwargs): """ 触发事件 :param event_name: 事件名称 :param args: 位置参数 :param kwargs: 关键字参数 """ if event_name in self.event_callbacks: for callback in self.event_callbacks[event_name]: try: callback(*args, **kwargs) except Exception as e: print(f"执行事件回调失败 {event_name}: {e}") import traceback traceback.print_exc() def setup_default_events(self): """ 设置默认事件处理器 """ # 注册基本动画控制事件 self.world.accept("skeletal.load_actor", self._handle_load_actor) self.world.accept("skeletal.play_animation", self._handle_play_animation) self.world.accept("skeletal.stop_animation", self._handle_stop_animation) self.world.accept("skeletal.set_animation_speed", self._handle_set_animation_speed) self.world.accept("skeletal.pause_animation", self._handle_pause_animation) self.world.accept("skeletal.resume_animation", self._handle_resume_animation) print("已设置默认动画事件处理器") def _handle_load_actor(self, model_path, anim_dict=None, actor_id=None, position=None, scale=None): """处理加载Actor事件""" self.animation_manager.load_actor(model_path, anim_dict, actor_id, position, scale) def _handle_play_animation(self, actor_id, anim_name, loop=False, play_rate=1.0): """处理播放动画事件""" self.animation_manager.play_animation(actor_id, anim_name, loop, play_rate) def _handle_stop_animation(self, actor_id, anim_name=None): """处理停止动画事件""" self.animation_manager.stop_animation(actor_id, anim_name) def _handle_set_animation_speed(self, actor_id, anim_name, speed): """处理设置动画速度事件""" self.animation_manager.set_animation_speed(actor_id, anim_name, speed) def _handle_pause_animation(self, actor_id, anim_name=None): """处理暂停动画事件""" self.animation_manager.pause_animation(actor_id, anim_name) def _handle_resume_animation(self, actor_id, anim_name=None): """处理恢复动画事件""" self.animation_manager.resume_animation(actor_id, anim_name) class SkeletalAnimationGUI: """ 骨骼动画GUI界面 提供可视化控制界面 """ def __init__(self, world, animation_manager, event_manager): self.world = world self.animation_manager = animation_manager self.event_manager = event_manager self.panel = None self.actor_list_elements = {} # 存储Actor列表元素 self.animation_list_elements = {} # 存储动画列表元素 def create_control_panel(self): """ 创建控制面板 """ if not hasattr(self.world, 'gui_manager') or not self.world.gui_manager: print("警告: GUI管理器不可用,无法创建控制面板") return try: # 创建主面板 self.panel = self.world.gui_manager.createGUIPanel( pos=(0.7, 0, 0.5), size=(0.25, 0.4), title="骨骼动画控制面板" ) # 创建Actor控制区域 actor_label = self.world.gui_manager.createGUIText( parent=self.panel, text="Actor列表:", pos=(0.02, 0, 0.35), scale=0.04 ) # 创建Actor列表框 self.actor_listbox = self.world.gui_manager.createGUIScrollableFrame( parent=self.panel, pos=(0.02, 0, 0.15), size=(0.22, 0.18) ) # 创建动画控制区域 anim_label = self.world.gui_manager.createGUIText( parent=self.panel, text="动画控制:", pos=(0.02, 0, 0.1), scale=0.04 ) # 创建控制按钮 button_y = 0.02 button_spacing = 0.06 self.play_button = self.world.gui_manager.createGUIButton( parent=self.panel, pos=(0.03, 0, button_y), size=0.05, text="播放" ) self.world.accept("skeletal_gui_play", self._on_play_clicked) self.stop_button = self.world.gui_manager.createGUIButton( parent=self.panel, pos=(0.09, 0, button_y), size=0.05, text="停止" ) self.world.accept("skeletal_gui_stop", self._on_stop_clicked) self.pause_button = self.world.gui_manager.createGUIButton( parent=self.panel, pos=(0.15, 0, button_y), size=0.05, text="暂停" ) self.world.accept("skeletal_gui_pause", self._on_pause_clicked) # 创建速度控制 speed_label = self.world.gui_manager.createGUIText( parent=self.panel, text="速度:", pos=(0.02, 0, button_y - button_spacing), scale=0.03 ) self.speed_slider = self.world.gui_manager.createGUISlider( parent=self.panel, pos=(0.08, 0, button_y - button_spacing), size=0.15, min_value=0.0, max_value=3.0, initial_value=1.0 ) print("骨骼动画控制面板创建成功") except Exception as e: print(f"创建控制面板失败: {e}") import traceback traceback.print_exc() def update_actor_list(self): """ 更新Actor列表 """ if not hasattr(self, 'actor_listbox') or not self.actor_listbox: return try: # 清除现有元素 for element in self.actor_list_elements.values(): self.world.gui_manager.deleteGUIElement(element) self.actor_list_elements.clear() # 添加Actor列表项 actors = self.animation_manager.actors y_offset = 0.15 y_spacing = 0.03 for i, (actor_id, actor) in enumerate(actors.items()): # 创建Actor列表项 actor_button = self.world.gui_manager.createGUIButton( parent=self.actor_listbox, pos=(0.01, 0, y_offset - i * y_spacing), size=0.04, text=actor_id ) # 注册点击事件 self.world.accept(f"skeletal_select_actor_{actor_id}", lambda aid=actor_id: self._on_actor_selected(aid)) self.actor_list_elements[actor_id] = actor_button except Exception as e: print(f"更新Actor列表失败: {e}") import traceback traceback.print_exc() def _on_actor_selected(self, actor_id): """ 当Actor被选中时的处理函数 :param actor_id: 选中的Actor ID """ print(f"选中Actor: {actor_id}") # 更新动画列表 self.update_animation_list(actor_id) def update_animation_list(self, actor_id): """ 更新动画列表 :param actor_id: Actor ID """ if not hasattr(self, 'actor_listbox') or not self.actor_listbox: return try: # 清除现有元素 for element in self.animation_list_elements.values(): self.world.gui_manager.deleteGUIElement(element) self.animation_list_elements.clear() # 获取Actor动画列表 animations = self.animation_manager.get_actor_animations(actor_id) y_offset = -0.05 y_spacing = 0.03 for i, anim_name in enumerate(animations): # 创建动画列表项 anim_button = self.world.gui_manager.createGUIButton( parent=self.actor_listbox, pos=(0.01, 0, y_offset - i * y_spacing), size=0.04, text=anim_name ) # 注册点击事件 self.world.accept(f"skeletal_select_anim_{actor_id}_{anim_name}", lambda aid=actor_id, an=anim_name: self._on_animation_selected(aid, an)) self.animation_list_elements[f"{actor_id}_{anim_name}"] = anim_button except Exception as e: print(f"更新动画列表失败: {e}") import traceback traceback.print_exc() def _on_animation_selected(self, actor_id, anim_name): """ 当动画被选中时的处理函数 :param actor_id: Actor ID :param anim_name: 动画名称 """ print(f"选中动画: {anim_name} (Actor: {actor_id})") def _on_play_clicked(self): """ 当播放按钮被点击时的处理函数 """ print("播放按钮被点击") # 这里应该实现实际的播放逻辑 def _on_stop_clicked(self): """ 当停止按钮被点击时的处理函数 """ print("停止按钮被点击") # 这里应该实现实际的停止逻辑 def _on_pause_clicked(self): """ 当暂停按钮被点击时的处理函数 """ print("暂停按钮被点击") # 这里应该实现实际的暂停逻辑 def destroy(self): """ 销毁GUI界面 """ try: if self.panel: self.world.gui_manager.deleteGUIElement(self.panel) self.panel = None print("骨骼动画GUI界面已销毁") except Exception as e: print(f"销毁GUI界面失败: {e}") 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.animation_manager = None self.event_manager = None self.gui = None self.is_enabled = False self.update_task = None def initialize(self) -> bool: """ 初始化插件 """ print(f"初始化骨骼动画插件: {self.name}") try: # 创建动画管理器 self.animation_manager = SkeletalAnimationManager(self.plugin_manager.world) # 创建事件管理器 self.event_manager = AnimationEventManager(self.plugin_manager.world, self.animation_manager) # 创建GUI self.gui = SkeletalAnimationGUI(self.plugin_manager.world, self.animation_manager, self.event_manager) print(f"骨骼动画插件初始化成功: {self.name}") 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: print(f"骨骼动画插件已启用: {self.name}") return True print(f"启用骨骼动画插件: {self.name}") try: # 设置默认事件处理器 self.event_manager.setup_default_events() # 创建GUI控制面板 self.gui.create_control_panel() # 启动更新任务 self.update_task = self.plugin_manager.world.taskMgr.add( self._update_task, f"skeletal_animation_update_{self.name}", sort=30 ) # 标记为已启用 self.is_enabled = True print(f"骨骼动画插件启用成功: {self.name}") 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: print(f"骨骼动画插件已禁用: {self.name}") return True print(f"禁用骨骼动画插件: {self.name}") try: # 停止更新任务 if self.update_task: self.plugin_manager.world.taskMgr.remove(self.update_task) self.update_task = None # 移除事件处理器 self.plugin_manager.world.ignore("skeletal.load_actor") self.plugin_manager.world.ignore("skeletal.play_animation") self.plugin_manager.world.ignore("skeletal.stop_animation") self.plugin_manager.world.ignore("skeletal.set_animation_speed") self.plugin_manager.world.ignore("skeletal.pause_animation") self.plugin_manager.world.ignore("skeletal.resume_animation") # 销毁GUI self.gui.destroy() # 标记为已禁用 self.is_enabled = False print(f"骨骼动画插件禁用成功: {self.name}") return True except Exception as e: print(f"骨骼动画插件禁用失败: {e}") import traceback traceback.print_exc() return False def finalize(self): """ 清理插件资源 """ print(f"清理骨骼动画插件资源: {self.name}") try: # 停止更新任务 if self.update_task: self.plugin_manager.world.taskMgr.remove(self.update_task) self.update_task = None # 停止所有动画 for actor_id in list(self.animation_manager.actors.keys()): self.animation_manager.unload_actor(actor_id) # 清理事件处理器 self.event_manager = None # 清理GUI self.gui = None # 清理动画管理器 self.animation_manager = None print(f"骨骼动画插件资源清理完成: {self.name}") except Exception as e: print(f"清理骨骼动画插件资源失败: {e}") import traceback traceback.print_exc() def _update_task(self, task): """ 插件更新任务 """ try: # 获取摄像机位置用于LOD计算 if hasattr(self.plugin_manager.world, 'camera'): camera_pos = self.plugin_manager.world.camera.getPos() self.animation_manager.update_lod(camera_pos) # 更新高级动画系统 dt = globalClock.getDt() time = globalClock.getRealTime() for actor_id, advanced_manager in self.animation_manager.advanced_managers.items(): advanced_manager.update(dt, time) except Exception as e: print(f"插件更新任务出错: {e}") return task.cont def get_animation_manager(self): """ 获取动画管理器 :return: SkeletalAnimationManager实例 """ return self.animation_manager def get_event_manager(self): """ 获取事件管理器 :return: AnimationEventManager实例 """ return self.event_manager def get_gui(self): """ 获取GUI界面 :return: SkeletalAnimationGUI实例 """ return self.gui