""" 高级骨骼动画系统 - 工具模块 提供动画编辑、调试和分析工具 """ import math import json from typing import Dict, List, Optional, Tuple, Any, Callable from dataclasses import dataclass, field from enum import Enum from panda3d.core import * from direct.actor.Actor import Actor from direct.interval.IntervalGlobal import * # 定义常量 TOOL_SETTINGS = { 'analyzer_update_rate': 10, 'debug_visualization_enabled': True, 'profiler_sampling_rate': 60 } # 枚举定义 class AnimationAnalysisType(Enum): """动画分析类型枚举""" PERFORMANCE = 0 QUALITY = 1 MEMORY = 2 COMPRESSION = 3 class DebugVisualizationMode(Enum): """调试可视化模式枚举""" SKELETON = 0 BOUNDS = 1 NORMALS = 2 WIREFRAME = 3 COLLISION = 4 class AnimationEditMode(Enum): """动画编辑模式枚举""" VIEW = 0 EDIT_KEYFRAME = 1 EDIT_CURVE = 2 EDIT_BONE = 3 @dataclass class AnimationAnalysisResult: """动画分析结果数据类""" actor_id: str anim_name: str analysis_type: AnimationAnalysisType metrics: Dict[str, Any] timestamp: float recommendations: List[str] = field(default_factory=list) @dataclass class AnimationEditorState: """动画编辑器状态数据类""" actor_id: str anim_name: str current_frame: int selected_bones: List[str] edit_mode: AnimationEditMode keyframe_selection: List[int] curve_editor_state: Dict[str, Any] @dataclass class PerformanceMetrics: """性能指标数据类""" fps: float frame_time: float animation_update_time: float memory_usage: int actor_count: int active_animations: int class AnimationAnalyzer: """ 动画分析器 提供动画性能、质量和内存使用分析 """ def __init__(self, core_system): """ 初始化动画分析器 :param core_system: 核心动画系统 """ self.core_system = core_system self.analysis_history: List[AnimationAnalysisResult] = [] self.is_analyzing = False self.update_rate = TOOL_SETTINGS['analyzer_update_rate'] self.last_update_time = 0.0 print("动画分析器初始化完成") def start_analysis(self) -> None: """ 开始分析 """ self.is_analyzing = True print("动画分析已启动") def stop_analysis(self) -> None: """ 停止分析 """ self.is_analyzing = False print("动画分析已停止") def analyze_animation(self, actor_id: str, anim_name: str, analysis_type: AnimationAnalysisType = AnimationAnalysisType.PERFORMANCE) -> Optional[AnimationAnalysisResult]: """ 分析指定动画 :param actor_id: Actor ID :param anim_name: 动画名称 :param analysis_type: 分析类型 :return: 分析结果 """ if actor_id not in self.core_system.actors: print(f"错误: Actor {actor_id} 不存在") return None actor_info = self.core_system.actors[actor_id] actor = actor_info.actor if anim_name not in actor.getAnimNames(): print(f"错误: 动画 {anim_name} 不存在于Actor {actor_id} 中") return None metrics = {} recommendations = [] # 根据分析类型执行不同的分析 if analysis_type == AnimationAnalysisType.PERFORMANCE: result = self._analyze_performance(actor_info, anim_name) metrics.update(result[0]) recommendations.extend(result[1]) elif analysis_type == AnimationAnalysisType.QUALITY: result = self._analyze_quality(actor_info, anim_name) metrics.update(result[0]) recommendations.extend(result[1]) elif analysis_type == AnimationAnalysisType.MEMORY: result = self._analyze_memory(actor_info, anim_name) metrics.update(result[0]) recommendations.extend(result[1]) elif analysis_type == AnimationAnalysisType.COMPRESSION: result = self._analyze_compression(actor_info, anim_name) metrics.update(result[0]) recommendations.extend(result[1]) # 创建分析结果 analysis_result = AnimationAnalysisResult( actor_id=actor_id, anim_name=anim_name, analysis_type=analysis_type, metrics=metrics, timestamp=globalClock.getRealTime(), recommendations=recommendations ) # 添加到历史记录 self.analysis_history.append(analysis_result) if len(self.analysis_history) > 100: # 限制历史记录大小 self.analysis_history.pop(0) return analysis_result def _analyze_performance(self, actor_info: Any, anim_name: str) -> Tuple[Dict[str, Any], List[str]]: """ 分析动画性能 :param actor_info: Actor信息 :param anim_name: 动画名称 :return: (指标, 建议) """ actor = actor_info.actor metrics = {} recommendations = [] # 获取动画控制 control = actor.getAnimControl(anim_name) if control: # 基本性能指标 metrics['frame_rate'] = actor.getFrameRate(anim_name) metrics['num_frames'] = actor.getNumFrames(anim_name) metrics['duration'] = control.getDuration() metrics['is_looping'] = control.getLoop() # 性能建议 if metrics['frame_rate'] and metrics['frame_rate'] < 15: recommendations.append("动画帧率过低,建议优化关键帧") if metrics['num_frames'] and metrics['num_frames'] > 1000: recommendations.append("动画帧数过多,考虑分割或简化") # 骨骼数量分析 bundle = actor.getPartBundleDict().get('modelRoot') if bundle: bone_count = bundle.getNumChildren() metrics['bone_count'] = bone_count if bone_count > 100: recommendations.append("骨骼数量较多,可能影响性能") return metrics, recommendations def _analyze_quality(self, actor_info: Any, anim_name: str) -> Tuple[Dict[str, Any], List[str]]: """ 分析动画质量 :param actor_info: Actor信息 :param anim_name: 动画名称 :return: (指标, 建议) """ actor = actor_info.actor metrics = {} recommendations = [] # 检查动画是否存在突变 prev_frame_data = None large_changes = 0 control = actor.getAnimControl(anim_name) if control: num_frames = control.getNumFrames() for frame in range(min(100, num_frames)): # 采样前100帧 actor.pose(anim_name, frame) # 检查所有骨骼的变化 bundle = actor.getPartBundleDict().get('modelRoot') if bundle: for i in range(min(10, bundle.getNumChildren())): # 检查前10个骨骼 child = bundle.getChild(i) if hasattr(child, 'getName'): bone_name = child.getName() joint = actor.exposeJoint(None, "modelRoot", bone_name) if joint: current_pos = joint.getPos() if prev_frame_data and bone_name in prev_frame_data: prev_pos = prev_frame_data[bone_name] distance = (current_pos - prev_pos).length() if distance > 1.0: # 阈值 large_changes += 1 if bone_name not in prev_frame_data: prev_frame_data = {} prev_frame_data[bone_name] = current_pos metrics['large_position_changes'] = large_changes if large_changes > 10: recommendations.append("检测到大量位置突变,可能存在动画质量问题") return metrics, recommendations def _analyze_memory(self, actor_info: Any, anim_name: str) -> Tuple[Dict[str, Any], List[str]]: """ 分析动画内存使用 :param actor_info: Actor信息 :param anim_name: 动画名称 :return: (指标, 建议) """ actor = actor_info.actor metrics = {} recommendations = [] # 估算内存使用 (简化) control = actor.getAnimControl(anim_name) if control: num_frames = control.getNumFrames() bundle = actor.getPartBundleDict().get('modelRoot') bone_count = bundle.getNumChildren() if bundle else 0 # 简化的内存估算公式 estimated_memory = num_frames * bone_count * 64 # 每个骨骼关键帧约64字节 metrics['estimated_memory_bytes'] = estimated_memory metrics['estimated_memory_kb'] = estimated_memory / 1024 if estimated_memory > 1024 * 1024: # 超过1MB recommendations.append("动画内存使用较大,考虑压缩或简化") return metrics, recommendations def _analyze_compression(self, actor_info: Any, anim_name: str) -> Tuple[Dict[str, Any], List[str]]: """ 分析动画压缩潜力 :param actor_info: Actor信息 :param anim_name: 动画名称 :return: (指标, 建议) """ actor = actor_info.actor metrics = {} recommendations = [] # 检查关键帧密度 control = actor.getAnimControl(anim_name) if control: num_frames = control.getNumFrames() duration = control.getDuration() if duration > 0: fps = num_frames / duration metrics['actual_fps'] = fps # 检查是否可以降低帧率 if fps > 30: metrics['recommended_fps'] = 30 recommendations.append(f"可以将帧率从{fps:.1f}降低到30以节省内存") elif fps > 15: metrics['recommended_fps'] = 15 recommendations.append(f"可以将帧率从{fps:.1f}降低到15以节省内存") return metrics, recommendations def get_actor_analysis_summary(self, actor_id: str) -> Optional[Dict[str, Any]]: """ 获取Actor分析摘要 :param actor_id: Actor ID :return: 分析摘要 """ if actor_id not in self.core_system.actors: return None # 获取最新的分析结果 actor_analyses = [a for a in self.analysis_history if a.actor_id == actor_id] if not actor_analyses: return None # 统计各类分析结果 performance_issues = len([a for a in actor_analyses if a.analysis_type == AnimationAnalysisType.PERFORMANCE and a.recommendations]) quality_issues = len([a for a in actor_analyses if a.analysis_type == AnimationAnalysisType.QUALITY and a.recommendations]) memory_issues = len([a for a in actor_analyses if a.analysis_type == AnimationAnalysisType.MEMORY and a.recommendations]) return { 'actor_id': actor_id, 'total_analyses': len(actor_analyses), 'performance_issues': performance_issues, 'quality_issues': quality_issues, 'memory_issues': memory_issues, 'last_analysis_time': actor_analyses[-1].timestamp if actor_analyses else 0 } def get_system_analysis_summary(self) -> Dict[str, Any]: """ 获取系统分析摘要 :return: 分析摘要 """ total_analyses = len(self.analysis_history) actors_with_issues = len(set(a.actor_id for a in self.analysis_history if a.recommendations)) return { 'total_analyses': total_analyses, 'actors_analyzed': len(set(a.actor_id for a in self.analysis_history)), 'actors_with_issues': actors_with_issues, 'performance_analyses': len([a for a in self.analysis_history if a.analysis_type == AnimationAnalysisType.PERFORMANCE]), 'quality_analyses': len([a for a in self.analysis_history if a.analysis_type == AnimationAnalysisType.QUALITY]), 'memory_analyses': len([a for a in self.analysis_history if a.analysis_type == AnimationAnalysisType.MEMORY]) } class AnimationEditor: """ 动画编辑器 提供关键帧编辑、曲线编辑等功能 """ def __init__(self, core_system): """ 初始化动画编辑器 :param core_system: 核心动画系统 """ self.core_system = core_system self.editor_states: Dict[str, AnimationEditorState] = {} self.is_editing = False self.edit_callbacks: List[Callable] = [] print("动画编辑器初始化完成") def start_editing(self, actor_id: str, anim_name: str) -> bool: """ 开始编辑动画 :param actor_id: Actor ID :param anim_name: 动画名称 :return: 是否成功开始编辑 """ if actor_id not in self.core_system.actors: print(f"错误: Actor {actor_id} 不存在") return False actor_info = self.core_system.actors[actor_id] actor = actor_info.actor if anim_name not in actor.getAnimNames(): print(f"错误: 动画 {anim_name} 不存在于Actor {actor_id} 中") return False # 创建编辑器状态 editor_state = AnimationEditorState( actor_id=actor_id, anim_name=anim_name, current_frame=0, selected_bones=[], edit_mode=AnimationEditMode.VIEW, keyframe_selection=[], curve_editor_state={} ) self.editor_states[f"{actor_id}:{anim_name}"] = editor_state self.is_editing = True print(f"开始编辑动画: {anim_name} (Actor: {actor_id})") return True def stop_editing(self, actor_id: str, anim_name: str) -> None: """ 停止编辑动画 :param actor_id: Actor ID :param anim_name: 动画名称 """ key = f"{actor_id}:{anim_name}" if key in self.editor_states: del self.editor_states[key] if not self.editor_states: self.is_editing = False print(f"停止编辑动画: {anim_name} (Actor: {actor_id})") def set_edit_mode(self, actor_id: str, anim_name: str, mode: AnimationEditMode) -> None: """ 设置编辑模式 :param actor_id: Actor ID :param anim_name: 动画名称 :param mode: 编辑模式 """ key = f"{actor_id}:{anim_name}" if key in self.editor_states: self.editor_states[key].edit_mode = mode print(f"设置编辑模式为: {mode.name} (Actor: {actor_id}, 动画: {anim_name})") def select_bones(self, actor_id: str, anim_name: str, bone_names: List[str]) -> None: """ 选择骨骼 :param actor_id: Actor ID :param anim_name: 动画名称 :param bone_names: 骨骼名称列表 """ key = f"{actor_id}:{anim_name}" if key in self.editor_states: self.editor_states[key].selected_bones = bone_names print(f"选择骨骼: {bone_names} (Actor: {actor_id}, 动画: {anim_name})") def set_current_frame(self, actor_id: str, anim_name: str, frame: int) -> None: """ 设置当前帧 :param actor_id: Actor ID :param anim_name: 动画名称 :param frame: 帧号 """ key = f"{actor_id}:{anim_name}" if key in self.editor_states: editor_state = self.editor_states[key] editor_state.current_frame = frame # 定位到指定帧 actor_info = self.core_system.actors[actor_id] actor_info.actor.pose(anim_name, frame) print(f"设置当前帧为: {frame} (Actor: {actor_id}, 动画: {anim_name})") def add_keyframe(self, actor_id: str, anim_name: str, bone_name: str, frame: int, position: Optional[Tuple[float, float, float]] = None, rotation: Optional[Tuple[float, float, float]] = None, scale: Optional[Tuple[float, float, float]] = None) -> None: """ 添加关键帧 :param actor_id: Actor ID :param anim_name: 动画名称 :param bone_name: 骨骼名称 :param frame: 帧号 :param position: 位置 :param rotation: 旋转 :param scale: 缩放 """ # 这是一个简化的实现,实际项目中需要直接操作动画数据 print(f"添加关键帧: 骨骼={bone_name}, 帧={frame} (Actor: {actor_id}, 动画: {anim_name})") print(f" 位置: {position}") print(f" 旋转: {rotation}") print(f" 缩放: {scale}") # 触发编辑回调 for callback in self.edit_callbacks: try: callback('add_keyframe', { 'actor_id': actor_id, 'anim_name': anim_name, 'bone_name': bone_name, 'frame': frame, 'position': position, 'rotation': rotation, 'scale': scale }) except Exception as e: print(f"执行编辑回调失败: {e}") def remove_keyframe(self, actor_id: str, anim_name: str, bone_name: str, frame: int) -> None: """ 移除关键帧 :param actor_id: Actor ID :param anim_name: 动画名称 :param bone_name: 骨骼名称 :param frame: 帧号 """ print(f"移除关键帧: 骨骼={bone_name}, 帧={frame} (Actor: {actor_id}, 动画: {anim_name})") # 触发编辑回调 for callback in self.edit_callbacks: try: callback('remove_keyframe', { 'actor_id': actor_id, 'anim_name': anim_name, 'bone_name': bone_name, 'frame': frame }) except Exception as e: print(f"执行编辑回调失败: {e}") def modify_keyframe(self, actor_id: str, anim_name: str, bone_name: str, frame: int, position: Optional[Tuple[float, float, float]] = None, rotation: Optional[Tuple[float, float, float]] = None, scale: Optional[Tuple[float, float, float]] = None) -> None: """ 修改关键帧 :param actor_id: Actor ID :param anim_name: 动画名称 :param bone_name: 骨骼名称 :param frame: 帧号 :param position: 新位置 :param rotation: 新旋转 :param scale: 新缩放 """ print(f"修改关键帧: 骨骼={bone_name}, 帧={frame} (Actor: {actor_id}, 动画: {anim_name})") print(f" 新位置: {position}") print(f" 新旋转: {rotation}") print(f" 新缩放: {scale}") # 触发编辑回调 for callback in self.edit_callbacks: try: callback('modify_keyframe', { 'actor_id': actor_id, 'anim_name': anim_name, 'bone_name': bone_name, 'frame': frame, 'position': position, 'rotation': rotation, 'scale': scale }) except Exception as e: print(f"执行编辑回调失败: {e}") def add_edit_callback(self, callback: Callable) -> None: """ 添加编辑回调 :param callback: 回调函数 """ self.edit_callbacks.append(callback) print("添加编辑回调") def remove_edit_callback(self, callback: Callable) -> None: """ 移除编辑回调 :param callback: 回调函数 """ if callback in self.edit_callbacks: self.edit_callbacks.remove(callback) print("移除编辑回调") class DebugVisualizer: """ 调试可视化工具 提供骨骼、边界框等可视化功能 """ def __init__(self, world): """ 初始化调试可视化工具 :param world: 世界对象 """ self.world = world self.visualizations: Dict[str, NodePath] = {} self.enabled = TOOL_SETTINGS['debug_visualization_enabled'] self.mode = DebugVisualizationMode.SKELETON print("调试可视化工具初始化完成") def set_mode(self, mode: DebugVisualizationMode) -> None: """ 设置可视化模式 :param mode: 模式 """ self.mode = mode print(f"调试可视化模式设置为: {mode.name}") def enable_visualization(self, enabled: bool = True) -> None: """ 启用/禁用可视化 :param enabled: 是否启用 """ self.enabled = enabled if not enabled: self.clear_all_visualizations() print(f"调试可视化已{'启用' if enabled else '禁用'}") def visualize_actor_skeleton(self, actor_id: str, actor: Actor) -> None: """ 可视化Actor骨骼 :param actor_id: Actor ID :param actor: Actor对象 """ if not self.enabled or self.mode != DebugVisualizationMode.SKELETON: return # 清除旧的可视化 self.clear_visualization(actor_id) # 创建骨骼可视化节点 skeleton_node = self.world.render.attachNewNode(f"skeleton_vis_{actor_id}") self.visualizations[actor_id] = skeleton_node # 获取骨骼信息并绘制连线 bundle = actor.getPartBundleDict().get('modelRoot') if bundle: self._draw_skeleton_hierarchy(actor, bundle, skeleton_node) def _draw_skeleton_hierarchy(self, actor: Actor, bundle, parent_node: NodePath) -> None: """ 绘制骨骼层级 :param actor: Actor对象 :param bundle: 骨骼包 :param parent_node: 父节点 """ # 这里简化实现,实际项目中需要遍历骨骼树并绘制连线 # 可以使用LineSegs或其他Panda3D绘图功能 # 示例:绘制一个简单的可视化表示 from panda3d.core import LineSegs segs = LineSegs(f"skeleton_lines_{actor.getName()}") segs.setColor(0, 1, 0, 1) # 绿色 segs.setThickness(2.0) # 从根节点到各个子节点绘制线段(简化) root_pos = Point3(0, 0, 0) segs.moveTo(root_pos) for i in range(min(5, bundle.getNumChildren())): # 只绘制前5个骨骼 child = bundle.getChild(i) if hasattr(child, 'getName'): bone_name = child.getName() joint = actor.exposeJoint(None, "modelRoot", bone_name) if joint: joint_pos = joint.getPos() segs.drawTo(joint_pos) segs.moveTo(root_pos) # 创建节点并附加到场景 lines_node = segs.create() np = parent_node.attachNewNode(lines_node) np.setBin("fixed", 40) np.setDepthTest(False) np.setDepthWrite(False) def visualize_actor_bounds(self, actor_id: str, actor: Actor) -> None: """ 可视化Actor边界框 :param actor_id: Actor ID :param actor: Actor对象 """ if not self.enabled or self.mode != DebugVisualizationMode.BOUNDS: return # 清除旧的可视化 self.clear_visualization(actor_id) # 获取边界框 bounds = actor.getTightBounds() if bounds: min_point, max_point = bounds # 创建边界框可视化 from panda3d.core import LineSegs segs = LineSegs(f"bounds_vis_{actor_id}") segs.setColor(1, 0, 0, 1) # 红色 segs.setThickness(1.0) # 绘制立方体边界框 self._draw_wire_cube(segs, min_point, max_point) # 创建节点并附加到场景 bounds_node = self.world.render.attachNewNode(segs.create()) bounds_node.setBin("fixed", 40) bounds_node.setDepthTest(False) bounds_node.setDepthWrite(False) self.visualizations[actor_id] = bounds_node def _draw_wire_cube(self, segs: LineSegs, min_point: Point3, max_point: Point3) -> None: """ 绘制线框立方体 :param segs: LineSegs对象 :param min_point: 最小点 :param max_point: 最大点 """ # 获取立方体的8个顶点 vertices = [ Point3(min_point.x, min_point.y, min_point.z), Point3(max_point.x, min_point.y, min_point.z), Point3(max_point.x, max_point.y, min_point.z), Point3(min_point.x, max_point.y, min_point.z), Point3(min_point.x, min_point.y, max_point.z), Point3(max_point.x, min_point.y, max_point.z), Point3(max_point.x, max_point.y, max_point.z), Point3(min_point.x, max_point.y, max_point.z) ] # 绘制12条边 edges = [ (0, 1), (1, 2), (2, 3), (3, 0), # 底面 (4, 5), (5, 6), (6, 7), (7, 4), # 顶面 (0, 4), (1, 5), (2, 6), (3, 7) # 垂直边 ] for start, end in edges: segs.moveTo(vertices[start]) segs.drawTo(vertices[end]) def clear_visualization(self, actor_id: str) -> None: """ 清除指定Actor的可视化 :param actor_id: Actor ID """ if actor_id in self.visualizations: self.visualizations[actor_id].removeNode() del self.visualizations[actor_id] def clear_all_visualizations(self) -> None: """ 清除所有可视化 """ for np in self.visualizations.values(): np.removeNode() self.visualizations.clear() def update_visualizations(self, actors: Dict[str, Any]) -> None: """ 更新所有可视化 :param actors: Actor字典 """ if not self.enabled: return for actor_id, actor_info in actors.items(): actor = actor_info.actor if self.mode == DebugVisualizationMode.SKELETON: self.visualize_actor_skeleton(actor_id, actor) elif self.mode == DebugVisualizationMode.BOUNDS: self.visualize_actor_bounds(actor_id, actor) class AnimationProfiler: """ 动画性能分析器 提供详细的性能分析和优化建议 """ def __init__(self, core_system): """ 初始化动画性能分析器 :param core_system: 核心动画系统 """ self.core_system = core_system self.sampling_rate = TOOL_SETTINGS['profiler_sampling_rate'] self.is_profiling = False self.profile_data: List[PerformanceMetrics] = [] self.last_sample_time = 0.0 print("动画性能分析器初始化完成") def start_profiling(self) -> None: """ 开始性能分析 """ self.is_profiling = True print("动画性能分析已启动") def stop_profiling(self) -> None: """ 停止性能分析 """ self.is_profiling = False print("动画性能分析已停止") def sample_performance(self) -> None: """ 采样性能数据 """ if not self.is_profiling: return current_time = globalClock.getRealTime() if current_time - self.last_sample_time < 1.0 / self.sampling_rate: return self.last_sample_time = current_time # 收集性能指标 metrics = self._collect_metrics() self.profile_data.append(metrics) # 限制数据大小 if len(self.profile_data) > 1000: self.profile_data.pop(0) def _collect_metrics(self) -> PerformanceMetrics: """ 收集性能指标 :return: 性能指标 """ # 获取FPS和帧时间 fps = globalClock.getAverageFrameRate() frame_time = globalClock.getDt() # 估算动画更新时间(简化) animation_update_time = frame_time * 0.3 # 假设动画更新占总帧时间的30% # 估算内存使用(简化) memory_usage = len(self.core_system.actors) * 1024 * 1024 # 假设每个Actor约1MB # 统计Actor和动画数量 actor_count = len(self.core_system.actors) active_animations = sum(len(info.active_animations) for info in self.core_system.actors.values()) return PerformanceMetrics( fps=fps, frame_time=frame_time, animation_update_time=animation_update_time, memory_usage=memory_usage, actor_count=actor_count, active_animations=active_animations ) def get_performance_report(self) -> Dict[str, Any]: """ 获取性能报告 :return: 性能报告 """ if not self.profile_data: return {} # 计算统计数据 fps_values = [m.fps for m in self.profile_data] frame_time_values = [m.frame_time for m in self.profile_data] update_time_values = [m.animation_update_time for m in self.profile_data] memory_values = [m.memory_usage for m in self.profile_data] return { 'sample_count': len(self.profile_data), 'duration_seconds': len(self.profile_data) / self.sampling_rate, 'fps': { 'average': sum(fps_values) / len(fps_values), 'min': min(fps_values), 'max': max(fps_values), 'std_dev': self._calculate_std_dev(fps_values) }, 'frame_time': { 'average': sum(frame_time_values) / len(frame_time_values), 'min': min(frame_time_values), 'max': max(frame_time_values), 'std_dev': self._calculate_std_dev(frame_time_values) }, 'animation_update_time': { 'average': sum(update_time_values) / len(update_time_values), 'min': min(update_time_values), 'max': max(update_time_values), 'std_dev': self._calculate_std_dev(update_time_values) }, 'memory_usage': { 'average': sum(memory_values) / len(memory_values), 'min': min(memory_values), 'max': max(memory_values), 'current': memory_values[-1] if memory_values else 0 }, 'actor_stats': { 'current_actor_count': self.profile_data[-1].actor_count if self.profile_data else 0, 'current_active_animations': self.profile_data[-1].active_animations if self.profile_data else 0 } } def _calculate_std_dev(self, values: List[float]) -> float: """ 计算标准差 :param values: 数值列表 :return: 标准差 """ if len(values) < 2: return 0.0 mean = sum(values) / len(values) variance = sum((x - mean) ** 2 for x in values) / (len(values) - 1) return math.sqrt(variance) def get_optimization_recommendations(self) -> List[str]: """ 获取优化建议 :return: 优化建议列表 """ if not self.profile_data: return [] latest = self.profile_data[-1] recommendations = [] # FPS相关建议 if latest.fps < 30: recommendations.append("FPS过低,建议优化动画系统或减少同时播放的动画数量") # 内存相关建议 if latest.memory_usage > 512 * 1024 * 1024: # 超过512MB recommendations.append("内存使用过高,建议检查Actor加载和卸载逻辑") # Actor数量建议 if latest.actor_count > 100: recommendations.append("Actor数量较多,建议使用LOD或视锥剔除优化") # 动画数量建议 if latest.active_animations > 200: recommendations.append("同时播放的动画过多,建议限制同时活动的动画数量") return recommendations # 使用示例和测试代码 def example_analyzer_usage(core_system): """ 动画分析器使用示例 """ print("=== 动画分析器使用示例 ===") # 创建分析器 analyzer = AnimationAnalyzer(core_system) analyzer.start_analysis() # 分析示例(假设有Actor) # 在实际使用中,这里会分析真实的Actor和动画 print("动画分析器示例完成") return analyzer def example_editor_usage(core_system): """ 动画编辑器使用示例 """ print("=== 动画编辑器使用示例 ===") # 创建编辑器 editor = AnimationEditor(core_system) # 添加编辑回调 def edit_callback(event_type, data): print(f"编辑事件: {event_type}, 数据: {data}") editor.add_edit_callback(edit_callback) print("动画编辑器示例完成") return editor def example_visualizer_usage(world): """ 调试可视化工具使用示例 """ print("=== 调试可视化工具使用示例 ===") # 创建可视化工具 visualizer = DebugVisualizer(world) visualizer.enable_visualization(True) visualizer.set_mode(DebugVisualizationMode.SKELETON) print("调试可视化工具示例完成") return visualizer def example_profiler_usage(core_system): """ 动画性能分析器使用示例 """ print("=== 动画性能分析器使用示例 ===") # 创建分析器 profiler = AnimationProfiler(core_system) profiler.start_profiling() # 采样性能数据 profiler.sample_performance() # 获取性能报告 report = profiler.get_performance_report() print(f"性能报告: {report}") # 获取优化建议 recommendations = profiler.get_optimization_recommendations() print(f"优化建议: {recommendations}") print("动画性能分析器示例完成") return profiler if __name__ == "__main__": print("动画工具模块加载完成")