EG/scripts/Rotate_P.py

741 lines
25 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Rotate_P - 自定义脚本,支持动态挂载其他脚本到模型或子物体
"""
from core.script_system import ScriptBase
class RotateP(ScriptBase):
"""自定义脚本类 - 支持脚本挂载功能"""
def __init__(self):
super().__init__()
# 在这里初始化您的变量
self.mounted_scripts = {} # 存储已挂载的脚本 {object_name: [script_names]}
self.world = None # 世界对象引用
def start(self):
"""脚本开始时调用 - 当此脚本被挂载时自动执行挂载其他脚本"""
self.log("Rotate_P 脚本开始运行!")
# 获取世界对象引用
if hasattr(self.script_manager, 'world'):
self.world = self.script_manager.world
self.log("✓ 获取世界对象引用成功")
# 当此脚本被挂载时,自动执行脚本挂载操作
self.auto_mount_scripts_on_start()
else:
self.log("⚠️ 无法获取世界对象引用")
def auto_mount_scripts_on_start(self):
"""
当Rotate_P脚本被挂载时自动执行的脚本挂载操作
在这里定义要自动挂载的脚本和目标对象
"""
self.log("=== 开始自动挂载脚本 ===")
# 获取当前脚本所挂载的对象
current_object = self.gameObject
current_object_name = current_object.getName() if current_object else "Unknown"
self.log(f"当前脚本挂载在对象: {current_object_name}")
# 显示当前对象信息
self.get_current_object_info()
# ==================== 配置区域 ====================
# 请根据您的需求选择以下配置之一,或自定义配置
# 配置1机器人式旋转演示有停顿
self.setup_rotation_demo(max_angle=45.0, rotation_speed=25.0, robot_mode=True, pause_duration=0.8)
# 配置2工业机器人演示取消注释以使用
# self.setup_industrial_robot_demo()
# 配置3伺服电机演示取消注释以使用
# self.setup_servo_motor_demo()
# 配置4机器人手臂演示取消注释以使用
# self.setup_robot_arm_demo()
# 配置5为指定对象挂载机器人旋转脚本取消注释并修改
# self.mount_robot_rotator("arm_joint", max_angle=60.0, rotation_speed=15.0, pause_duration=1.0)
# self.mount_robot_rotator("gripper", max_angle=30.0, rotation_speed=20.0, pause_duration=0.5)
# 配置6平滑旋转无停顿取消注释以使用
# self.mount_smooth_rotator("wheel", max_angle=180.0, rotation_speed=90.0)
# 配置5自定义挂载配置取消注释并修改
# auto_mount_configs = [
# ("your_model_name", "RotatorScript"), # 将RotatorScript挂载到指定模型
# ("child_object_name", "MoverScript"), # 将MoverScript挂载到子物体
# ("another_object", "ScalerScript"), # 将ScalerScript挂载到另一个对象
# ]
# if auto_mount_configs:
# success_count = self.batch_mount_scripts(auto_mount_configs)
# self.log(f"✓ 自定义挂载完成,成功挂载 {success_count} 个脚本")
# ==================== 配置区域结束 ====================
# 显示使用说明
self.show_usage_examples()
# 列出已挂载的脚本
self.list_mounted_scripts()
def mount_script_to_current_object(self, script_name):
"""
将脚本挂载到当前对象即Rotate_P脚本所在的对象
Args:
script_name: 要挂载的脚本名称
Returns:
bool: 挂载是否成功
"""
if not self.gameObject:
self.log("错误: 无法获取当前对象")
return False
return self.mount_script_to_object(self.gameObject, script_name)
def auto_mount_to_all_children(self, script_name):
"""
自动将脚本挂载到当前对象的所有子物体
Args:
script_name: 要挂载的脚本名称
Returns:
int: 成功挂载的子物体数量
"""
if not self.gameObject:
self.log("错误: 无法获取当前对象")
return 0
# 获取所有子对象
children = self.gameObject.getChildren()
success_count = 0
self.log(f"开始为当前对象的 {len(children)} 个子物体挂载脚本 '{script_name}'")
for child in children:
if self.mount_script_to_object(child, script_name):
success_count += 1
self.log(f"✓ 成功为 {success_count}/{len(children)} 个子物体挂载脚本 '{script_name}'")
return success_count
def update(self, dt):
"""每帧更新"""
# 在这里编写更新逻辑
pass
def on_destroy(self):
"""脚本销毁时调用"""
self.log("脚本被销毁")
# ==================== 脚本挂载功能 ====================
def mount_script_to_object(self, target_object, script_name, script_config=None):
"""
将脚本挂载到指定对象上
Args:
target_object: 目标对象Panda3D NodePath
script_name: 要挂载的脚本名称(字符串)
script_config: 脚本配置参数(字典),可选
Returns:
bool: 挂载是否成功
"""
if not self.world:
self.log("错误: 世界对象引用不可用")
return False
try:
# 使用世界对象的addScript方法挂载脚本
success = self.world.addScript(target_object, script_name)
if success:
# 记录挂载信息
obj_name = target_object.getName()
if obj_name not in self.mounted_scripts:
self.mounted_scripts[obj_name] = []
self.mounted_scripts[obj_name].append(script_name)
# 如果提供了配置参数,尝试配置脚本
if script_config and script_name == "RotatorScript":
self.configure_rotator_script(target_object, script_config)
self.log(f"✓ 成功将脚本 '{script_name}' 挂载到对象 '{obj_name}'")
return True
else:
self.log(f"✗ 挂载脚本 '{script_name}' 失败")
return False
except Exception as e:
self.log(f"✗ 挂载脚本时出错: {str(e)}")
return False
def configure_rotator_script(self, target_object, config):
"""
配置已挂载的RotatorScript脚本
Args:
target_object: 目标对象
config: 配置字典,可包含 max_angle, rotation_speed, robot_mode, pause_duration 等
"""
try:
# 获取对象上的RotatorScript
scripts = self.world.getScripts(target_object)
for script_component in scripts:
if script_component.script_name == "RotatorScript":
script_instance = script_component.script_instance
# 配置最大角度
if 'max_angle' in config:
script_instance.set_max_angle(config['max_angle'])
# 配置旋转速度
if 'rotation_speed' in config:
script_instance.set_rotation_speed(config['rotation_speed'])
# 配置机器人模式
if 'robot_mode' in config:
script_instance.set_robot_mode(config['robot_mode'])
# 配置停顿时间
if 'pause_duration' in config:
script_instance.set_pause_duration(config['pause_duration'])
# 预设模式
if 'preset_mode' in config:
preset = config['preset_mode']
if preset == 'slow_robot':
script_instance.set_slow_robot_mode()
elif preset == 'fast_robot':
script_instance.set_fast_robot_mode()
elif preset == 'smooth':
script_instance.set_smooth_mode()
self.log(f"✓ 已配置 RotatorScript: {config}")
break
except Exception as e:
self.log(f"✗ 配置 RotatorScript 时出错: {str(e)}")
def unmount_script_from_object(self, target_object, script_name):
"""
从指定对象卸载脚本
Args:
target_object: 目标对象Panda3D NodePath
script_name: 要卸载的脚本名称(字符串)
Returns:
bool: 卸载是否成功
"""
if not self.world:
self.log("错误: 世界对象引用不可用")
return False
try:
# 使用世界对象的removeScript方法卸载脚本
success = self.world.removeScript(target_object, script_name)
if success:
# 更新挂载记录
obj_name = target_object.getName()
if obj_name in self.mounted_scripts and script_name in self.mounted_scripts[obj_name]:
self.mounted_scripts[obj_name].remove(script_name)
if not self.mounted_scripts[obj_name]: # 如果列表为空,删除键
del self.mounted_scripts[obj_name]
self.log(f"✓ 成功从对象 '{obj_name}' 卸载脚本 '{script_name}'")
return True
else:
self.log(f"✗ 卸载脚本 '{script_name}' 失败")
return False
except Exception as e:
self.log(f"✗ 卸载脚本时出错: {str(e)}")
return False
def mount_script_by_name(self, object_name, script_name):
"""
通过对象名称挂载脚本
Args:
object_name: 目标对象名称(字符串)
script_name: 要挂载的脚本名称(字符串)
Returns:
bool: 挂载是否成功
"""
if not self.world:
self.log("错误: 世界对象引用不可用")
return False
# 查找对象
target_object = self.find_object_by_name(object_name)
if not target_object:
self.log(f"✗ 未找到名为 '{object_name}' 的对象")
return False
return self.mount_script_to_object(target_object, script_name)
def find_object_by_name(self, object_name):
"""
通过名称查找对象
Args:
object_name: 对象名称(字符串)
Returns:
NodePath: 找到的对象如果未找到则返回None
"""
if not self.world:
return None
# 首先尝试使用世界的查找方法
if hasattr(self.world, 'findModelByName'):
obj = self.world.findModelByName(object_name)
if obj:
return obj
# 如果没有找到尝试在render下搜索
if hasattr(self.world, 'render'):
return self.world.render.find(f"**/{object_name}")
return None
def get_available_scripts(self):
"""
获取所有可用的脚本列表
Returns:
list: 可用脚本名称列表
"""
if not self.world:
self.log("错误: 世界对象引用不可用")
return []
try:
return self.world.getAvailableScripts()
except Exception as e:
self.log(f"✗ 获取可用脚本列表时出错: {str(e)}")
return []
def get_scripts_on_object(self, target_object):
"""
获取对象上已挂载的脚本
Args:
target_object: 目标对象Panda3D NodePath
Returns:
list: 脚本组件列表
"""
if not self.world:
self.log("错误: 世界对象引用不可用")
return []
try:
return self.world.getScripts(target_object)
except Exception as e:
self.log(f"✗ 获取对象脚本时出错: {str(e)}")
return []
def list_mounted_scripts(self):
"""
列出所有已挂载的脚本信息
"""
self.log("=== 已挂载脚本列表 ===")
if not self.mounted_scripts:
self.log("暂无已挂载的脚本")
return
for obj_name, script_names in self.mounted_scripts.items():
self.log(f"对象 '{obj_name}': {', '.join(script_names)}")
# ==================== 便捷方法 ====================
def mount_rotator_script(self, object_name):
"""
便捷方法:挂载旋转脚本到指定对象
Args:
object_name: 目标对象名称
Returns:
bool: 挂载是否成功
"""
return self.mount_script_by_name(object_name, "RotatorScript")
def mount_mover_script(self, object_name):
"""
便捷方法:挂载移动脚本到指定对象
Args:
object_name: 目标对象名称
Returns:
bool: 挂载是否成功
"""
return self.mount_script_by_name(object_name, "MoverScript")
def mount_scaler_script(self, object_name):
"""
便捷方法:挂载缩放脚本到指定对象
Args:
object_name: 目标对象名称
Returns:
bool: 挂载是否成功
"""
return self.mount_script_by_name(object_name, "ScalerScript")
# ==================== 示例使用方法 ====================
def example_mount_scripts(self):
"""
示例:如何使用脚本挂载功能
在start()方法中调用此方法来演示脚本挂载
"""
self.log("=== 脚本挂载示例 ===")
# 示例1挂载旋转脚本到特定对象
# self.mount_rotator_script("your_model_name")
# 示例2挂载多个脚本到同一个对象
# self.mount_script_by_name("your_model_name", "RotatorScript")
# self.mount_script_by_name("your_model_name", "MoverScript")
# 示例3查找并挂载脚本到子物体
# child_object = self.find_object_by_name("child_object_name")
# if child_object:
# self.mount_script_to_object(child_object, "RotatorScript")
# 示例4列出可用脚本
available_scripts = self.get_available_scripts()
self.log(f"可用脚本: {available_scripts}")
# 示例5列出已挂载的脚本
self.list_mounted_scripts()
def auto_mount_to_children(self, parent_object_name, script_name):
"""
自动将脚本挂载到指定父对象的所有子物体
Args:
parent_object_name: 父对象名称
script_name: 要挂载的脚本名称
Returns:
int: 成功挂载的子物体数量
"""
if not self.world:
self.log("错误: 世界对象引用不可用")
return 0
# 查找父对象
parent_object = self.find_object_by_name(parent_object_name)
if not parent_object:
self.log(f"✗ 未找到父对象 '{parent_object_name}'")
return 0
# 获取所有子对象
children = parent_object.getChildren()
success_count = 0
for child in children:
if self.mount_script_to_object(child, script_name):
success_count += 1
self.log(f"✓ 成功为 {success_count}/{len(children)} 个子物体挂载脚本 '{script_name}'")
return success_count
def batch_mount_scripts(self, object_script_pairs):
"""
批量挂载脚本
Args:
object_script_pairs: 对象-脚本对列表,格式:[(object_name, script_name), ...]
Returns:
int: 成功挂载的数量
"""
success_count = 0
for object_name, script_name in object_script_pairs:
if self.mount_script_by_name(object_name, script_name):
success_count += 1
self.log(f"✓ 批量挂载完成: {success_count}/{len(object_script_pairs)} 个脚本挂载成功")
return success_count
# ==================== 预设配置方法 ====================
def setup_rotation_demo(self, max_angle=30.0, rotation_speed=30.0, robot_mode=True, pause_duration=0.5):
"""
预设配置:旋转演示
为当前对象及其子物体挂载旋转脚本
Args:
max_angle: 最大旋转角度(相对于初始角度)
rotation_speed: 旋转速度(度/秒)
robot_mode: 是否启用机器人模式
pause_duration: 停顿时间(秒)
"""
self.log("=== 设置旋转演示 ===")
# 配置参数
config = {
'max_angle': max_angle,
'rotation_speed': rotation_speed,
'robot_mode': robot_mode,
'pause_duration': pause_duration
}
# 为当前对象挂载旋转脚本
self.mount_script_to_current_object_with_config("RotatorScript", config)
# 为所有子物体挂载旋转脚本
self.auto_mount_to_all_children_with_config("RotatorScript", config)
def setup_animation_combo(self):
"""
预设配置:动画组合
为对象挂载多种动画脚本
"""
self.log("=== 设置动画组合 ===")
# 为当前对象挂载多个脚本
scripts_to_mount = ["RotatorScript", "MoverScript", "ScalerScript"]
for script_name in scripts_to_mount:
self.mount_script_to_current_object(script_name)
def setup_child_animation(self, script_name="RotatorScript"):
"""
预设配置:子物体动画
只为子物体挂载脚本,不影响父对象
Args:
script_name: 要挂载的脚本名称默认为RotatorScript
"""
self.log(f"=== 设置子物体动画 ({script_name}) ===")
self.auto_mount_to_all_children(script_name)
def setup_specific_objects(self, object_names, script_name="RotatorScript"):
"""
预设配置:为指定的对象列表挂载脚本
Args:
object_names: 对象名称列表
script_name: 要挂载的脚本名称
"""
self.log(f"=== 为指定对象挂载脚本 ({script_name}) ===")
for obj_name in object_names:
self.mount_script_by_name(obj_name, script_name)
def setup_robot_arm_demo(self):
"""
预设配置:机器人手臂演示
为不同关节设置不同的机器人旋转参数
"""
self.log("=== 设置机器人手臂演示 ===")
# 为当前对象设置慢速机器人模式
config = {'preset_mode': 'slow_robot'}
self.mount_script_to_current_object_with_config("RotatorScript", config)
# 为子物体设置快速机器人模式
config = {'preset_mode': 'fast_robot'}
self.auto_mount_to_all_children_with_config("RotatorScript", config)
def setup_industrial_robot_demo(self):
"""
预设配置:工业机器人演示
模拟工业机器人的精确停顿动作
"""
self.log("=== 设置工业机器人演示 ===")
# 工业机器人配置:慢速、长停顿
config = {
'max_angle': 45.0,
'rotation_speed': 15.0,
'robot_mode': True,
'pause_duration': 1.2
}
self.mount_script_to_current_object_with_config("RotatorScript", config)
self.auto_mount_to_all_children_with_config("RotatorScript", config)
def setup_servo_motor_demo(self):
"""
预设配置:伺服电机演示
模拟伺服电机的快速精确定位
"""
self.log("=== 设置伺服电机演示 ===")
# 伺服电机配置:快速、短停顿
config = {
'max_angle': 60.0,
'rotation_speed': 50.0,
'robot_mode': True,
'pause_duration': 0.2
}
self.mount_script_to_current_object_with_config("RotatorScript", config)
self.auto_mount_to_all_children_with_config("RotatorScript", config)
# ==================== 使用示例和说明 ====================
def show_usage_examples(self):
"""
显示使用示例和说明
"""
self.log("=== Rotate_P 脚本使用说明 ===")
self.log("此脚本被挂载时会自动执行脚本挂载操作")
self.log("")
self.log("可用的预设配置方法:")
self.log("1. setup_rotation_demo() - 为当前对象和子物体挂载旋转脚本")
self.log("2. setup_animation_combo() - 为当前对象挂载多种动画脚本")
self.log("3. setup_child_animation() - 只为子物体挂载脚本")
self.log("4. setup_specific_objects() - 为指定对象挂载脚本")
self.log("")
self.log("修改 auto_mount_scripts_on_start() 方法来自定义自动挂载行为")
self.log("=== 使用说明结束 ===")
def get_current_object_info(self):
"""
获取当前对象的详细信息
"""
if not self.gameObject:
self.log("错误: 无法获取当前对象")
return
obj_name = self.gameObject.getName()
children = self.gameObject.getChildren()
child_names = [child.getName() for child in children]
self.log("=== 当前对象信息 ===")
self.log(f"对象名称: {obj_name}")
self.log(f"子物体数量: {len(children)}")
if child_names:
self.log(f"子物体名称: {', '.join(child_names)}")
else:
self.log("无子物体")
self.log("=== 对象信息结束 ===")
# ==================== 带配置的便捷方法 ====================
def mount_script_to_current_object_with_config(self, script_name, config=None):
"""
将脚本挂载到当前对象并配置参数
Args:
script_name: 脚本名称
config: 配置参数字典
Returns:
bool: 挂载是否成功
"""
if not self.gameObject:
self.log("错误: 无法获取当前对象")
return False
return self.mount_script_to_object(self.gameObject, script_name, config)
def auto_mount_to_all_children_with_config(self, script_name, config=None):
"""
自动将脚本挂载到当前对象的所有子物体并配置参数
Args:
script_name: 要挂载的脚本名称
config: 配置参数字典
Returns:
int: 成功挂载的子物体数量
"""
if not self.gameObject:
self.log("错误: 无法获取当前对象")
return 0
# 获取所有子对象
children = self.gameObject.getChildren()
success_count = 0
self.log(f"开始为当前对象的 {len(children)} 个子物体挂载脚本 '{script_name}'")
if config:
self.log(f"使用配置: {config}")
for child in children:
if self.mount_script_to_object(child, script_name, config):
success_count += 1
self.log(f"✓ 成功为 {success_count}/{len(children)} 个子物体挂载脚本 '{script_name}'")
return success_count
def mount_rotator_with_custom_angle(self, object_name, max_angle=45.0, rotation_speed=20.0, robot_mode=True, pause_duration=0.5):
"""
便捷方法:挂载自定义角度的旋转脚本
Args:
object_name: 目标对象名称
max_angle: 最大旋转角度
rotation_speed: 旋转速度
robot_mode: 是否启用机器人模式
pause_duration: 停顿时间(秒)
Returns:
bool: 挂载是否成功
"""
config = {
'max_angle': max_angle,
'rotation_speed': rotation_speed,
'robot_mode': robot_mode,
'pause_duration': pause_duration
}
target_object = self.find_object_by_name(object_name)
if not target_object:
self.log(f"✗ 未找到名为 '{object_name}' 的对象")
return False
return self.mount_script_to_object(target_object, "RotatorScript", config)
def mount_robot_rotator(self, object_name, max_angle=30.0, rotation_speed=20.0, pause_duration=0.8):
"""
便捷方法:挂载机器人式旋转脚本
Args:
object_name: 目标对象名称
max_angle: 最大旋转角度
rotation_speed: 旋转速度
pause_duration: 停顿时间
Returns:
bool: 挂载是否成功
"""
return self.mount_rotator_with_custom_angle(object_name, max_angle, rotation_speed, True, pause_duration)
def mount_smooth_rotator(self, object_name, max_angle=45.0, rotation_speed=30.0):
"""
便捷方法:挂载平滑旋转脚本(无停顿)
Args:
object_name: 目标对象名称
max_angle: 最大旋转角度
rotation_speed: 旋转速度
Returns:
bool: 挂载是否成功
"""
return self.mount_rotator_with_custom_angle(object_name, max_angle, rotation_speed, False, 0.0)