打包功能
This commit is contained in:
parent
6524f8306b
commit
da629e508d
BIN
111/111.png
Normal file
BIN
111/111.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
8
111/project.json
Normal file
8
111/project.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "111",
|
||||
"path": "D:\\IMGUI\\EG\\111",
|
||||
"last_modified": "2026-03-18 10:56:00",
|
||||
"scene_file": "scenes\\scene.bam",
|
||||
"created_at": "2026-03-18 09:46:18",
|
||||
"version": "1.0"
|
||||
}
|
||||
BIN
111/scenes/scene.bam
Normal file
BIN
111/scenes/scene.bam
Normal file
Binary file not shown.
102
111/scripts/BouncerScript.py
Normal file
102
111/scripts/BouncerScript.py
Normal file
@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
跳跃脚本 - 让对象产生上下跳跃效果
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
import math
|
||||
|
||||
class BouncerScript(ScriptBase):
|
||||
"""跳跃脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# 跳跃参数
|
||||
self.jump_height = 2.0 # 跳跃高度
|
||||
self.jump_speed = 3.0 # 跳跃速度 (跳跃/秒)
|
||||
self.bounce_type = "sine" # 跳跃类型: "sine", "abs_sine", "square"
|
||||
|
||||
# 内部变量
|
||||
self.time_accumulator = 0.0 # 时间累积器
|
||||
self.original_y = None # 原始Y位置
|
||||
self.is_bouncing = True # 是否正在跳跃
|
||||
self.bounce_direction = 1 # 跳跃方向
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("跳跃脚本启动!")
|
||||
self.log(f"跳跃参数: 高度={self.jump_height}, 速度={self.jump_speed}, 类型={self.bounce_type}")
|
||||
|
||||
# 记录原始Y位置
|
||||
self.original_y = self.gameObject.getZ() # Z轴是高度
|
||||
self.log(f"原始高度: {self.original_y}")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_bouncing:
|
||||
return
|
||||
|
||||
# 累积时间
|
||||
self.time_accumulator += dt * self.bounce_direction
|
||||
|
||||
# 根据类型计算跳跃高度
|
||||
if self.bounce_type == "sine":
|
||||
# 标准正弦波跳跃
|
||||
height_offset = math.sin(self.time_accumulator * self.jump_speed * 2 * math.pi) * self.jump_height
|
||||
elif self.bounce_type == "abs_sine":
|
||||
# 绝对值正弦波(始终向上)
|
||||
height_offset = abs(math.sin(self.time_accumulator * self.jump_speed * 2 * math.pi)) * self.jump_height
|
||||
elif self.bounce_type == "square":
|
||||
# 方波跳跃(突然跳起落下)
|
||||
sine_val = math.sin(self.time_accumulator * self.jump_speed * 2 * math.pi)
|
||||
height_offset = self.jump_height if sine_val > 0 else 0
|
||||
else:
|
||||
height_offset = 0
|
||||
|
||||
# 应用跳跃
|
||||
current_pos = self.gameObject.getPos()
|
||||
new_z = self.original_y + height_offset
|
||||
self.gameObject.setPos(current_pos.getX(), current_pos.getY(), new_z)
|
||||
|
||||
def set_bounce_parameters(self, height=None, speed=None, bounce_type=None):
|
||||
"""设置跳跃参数"""
|
||||
if height is not None:
|
||||
self.jump_height = height
|
||||
if speed is not None:
|
||||
self.jump_speed = speed
|
||||
if bounce_type is not None and bounce_type in ["sine", "abs_sine", "square"]:
|
||||
self.bounce_type = bounce_type
|
||||
|
||||
self.log(f"跳跃参数更新: 高度={self.jump_height}, 速度={self.jump_speed}, 类型={self.bounce_type}")
|
||||
|
||||
def toggle_bouncing(self):
|
||||
"""切换跳跃状态"""
|
||||
self.is_bouncing = not self.is_bouncing
|
||||
status = "恢复" if self.is_bouncing else "暂停"
|
||||
self.log(f"跳跃{status}")
|
||||
|
||||
def reverse_direction(self):
|
||||
"""反转跳跃方向"""
|
||||
self.bounce_direction *= -1
|
||||
direction = "正向" if self.bounce_direction > 0 else "反向"
|
||||
self.log(f"跳跃方向改为{direction}")
|
||||
|
||||
def reset_position(self):
|
||||
"""重置到原始高度"""
|
||||
if self.original_y is not None:
|
||||
current_pos = self.gameObject.getPos()
|
||||
self.gameObject.setPos(current_pos.getX(), current_pos.getY(), self.original_y)
|
||||
self.time_accumulator = 0.0
|
||||
self.log("位置已重置到原始高度")
|
||||
|
||||
def jump_once(self):
|
||||
"""执行一次跳跃"""
|
||||
self.time_accumulator = 0.0
|
||||
self.log("执行单次跳跃")
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("跳跃脚本停止")
|
||||
160
111/scripts/ColorChangerScript.py
Normal file
160
111/scripts/ColorChangerScript.py
Normal file
@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
颜色变化脚本 - 让对象颜色产生循环变化
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
from panda3d.core import Vec4
|
||||
import math
|
||||
|
||||
class ColorChangerScript(ScriptBase):
|
||||
"""颜色变化脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# 颜色参数
|
||||
self.color_speed = 1.0 # 颜色变化速度 (周期/秒)
|
||||
self.color_mode = "rainbow" # 颜色模式: "rainbow", "pulse", "fade", "strobe"
|
||||
self.base_color = Vec4(1, 1, 1, 1) # 基础颜色
|
||||
self.intensity = 1.0 # 颜色强度
|
||||
|
||||
# 内部变量
|
||||
self.time_accumulator = 0.0 # 时间累积器
|
||||
self.original_color = None # 原始颜色
|
||||
self.is_changing = True # 是否正在变化
|
||||
self.strobe_state = False # 闪烁状态
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("颜色变化脚本启动!")
|
||||
self.log(f"颜色参数: 速度={self.color_speed}, 模式={self.color_mode}, 强度={self.intensity}")
|
||||
|
||||
# 记录原始颜色
|
||||
self.original_color = self.gameObject.getColor()
|
||||
self.log(f"原始颜色: {self.original_color}")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_changing:
|
||||
return
|
||||
|
||||
# 累积时间
|
||||
self.time_accumulator += dt
|
||||
|
||||
# 根据模式计算新颜色
|
||||
if self.color_mode == "rainbow":
|
||||
new_color = self._calculate_rainbow_color()
|
||||
elif self.color_mode == "pulse":
|
||||
new_color = self._calculate_pulse_color()
|
||||
elif self.color_mode == "fade":
|
||||
new_color = self._calculate_fade_color()
|
||||
elif self.color_mode == "strobe":
|
||||
new_color = self._calculate_strobe_color()
|
||||
else:
|
||||
new_color = self.base_color
|
||||
|
||||
# 应用颜色
|
||||
self.gameObject.setColor(new_color)
|
||||
|
||||
def _calculate_rainbow_color(self):
|
||||
"""计算彩虹颜色"""
|
||||
# 使用HSV到RGB的转换创建彩虹效果
|
||||
hue = (self.time_accumulator * self.color_speed) % 1.0
|
||||
|
||||
# 简单的HSV到RGB转换
|
||||
i = int(hue * 6.0)
|
||||
f = (hue * 6.0) - i
|
||||
p = 0.0
|
||||
q = 1.0 - f
|
||||
t = f
|
||||
|
||||
if i % 6 == 0:
|
||||
r, g, b = 1.0, t, p
|
||||
elif i % 6 == 1:
|
||||
r, g, b = q, 1.0, p
|
||||
elif i % 6 == 2:
|
||||
r, g, b = p, 1.0, t
|
||||
elif i % 6 == 3:
|
||||
r, g, b = p, q, 1.0
|
||||
elif i % 6 == 4:
|
||||
r, g, b = t, p, 1.0
|
||||
else:
|
||||
r, g, b = 1.0, p, q
|
||||
|
||||
return Vec4(r * self.intensity, g * self.intensity, b * self.intensity, 1.0)
|
||||
|
||||
def _calculate_pulse_color(self):
|
||||
"""计算脉冲颜色"""
|
||||
pulse = (math.sin(self.time_accumulator * self.color_speed * 2 * math.pi) + 1.0) / 2.0
|
||||
multiplier = pulse * self.intensity
|
||||
return Vec4(
|
||||
self.base_color.getX() * multiplier,
|
||||
self.base_color.getY() * multiplier,
|
||||
self.base_color.getZ() * multiplier,
|
||||
self.base_color.getW()
|
||||
)
|
||||
|
||||
def _calculate_fade_color(self):
|
||||
"""计算淡入淡出颜色"""
|
||||
fade = (math.sin(self.time_accumulator * self.color_speed * 2 * math.pi) + 1.0) / 2.0
|
||||
alpha = fade * self.intensity
|
||||
return Vec4(
|
||||
self.base_color.getX(),
|
||||
self.base_color.getY(),
|
||||
self.base_color.getZ(),
|
||||
alpha
|
||||
)
|
||||
|
||||
def _calculate_strobe_color(self):
|
||||
"""计算闪烁颜色"""
|
||||
# 根据时间间隔切换状态
|
||||
interval = 1.0 / (self.color_speed * 2) # 闪烁间隔
|
||||
if int(self.time_accumulator / interval) % 2 == 0:
|
||||
return Vec4(
|
||||
self.base_color.getX() * self.intensity,
|
||||
self.base_color.getY() * self.intensity,
|
||||
self.base_color.getZ() * self.intensity,
|
||||
self.base_color.getW()
|
||||
)
|
||||
else:
|
||||
return Vec4(0.1, 0.1, 0.1, self.base_color.getW()) # 暗色状态
|
||||
|
||||
def set_color_parameters(self, speed=None, mode=None, base_color=None, intensity=None):
|
||||
"""设置颜色参数"""
|
||||
if speed is not None:
|
||||
self.color_speed = speed
|
||||
if mode is not None and mode in ["rainbow", "pulse", "fade", "strobe"]:
|
||||
self.color_mode = mode
|
||||
if base_color is not None:
|
||||
self.base_color = base_color
|
||||
if intensity is not None:
|
||||
self.intensity = intensity
|
||||
|
||||
self.log(f"颜色参数更新: 速度={self.color_speed}, 模式={self.color_mode}, 强度={self.intensity}")
|
||||
|
||||
def toggle_color_change(self):
|
||||
"""切换颜色变化状态"""
|
||||
self.is_changing = not self.is_changing
|
||||
status = "恢复" if self.is_changing else "暂停"
|
||||
self.log(f"颜色变化{status}")
|
||||
|
||||
def reset_color(self):
|
||||
"""重置到原始颜色"""
|
||||
if self.original_color:
|
||||
self.gameObject.setColor(self.original_color)
|
||||
self.time_accumulator = 0.0
|
||||
self.log("颜色已重置到原始值")
|
||||
|
||||
def set_solid_color(self, r=1.0, g=1.0, b=1.0, a=1.0):
|
||||
"""设置固定颜色"""
|
||||
color = Vec4(r, g, b, a)
|
||||
self.gameObject.setColor(color)
|
||||
self.base_color = color
|
||||
self.log(f"设置固定颜色: {color}")
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("颜色变化脚本停止")
|
||||
39
111/scripts/ComboAnimatorScript.py
Normal file
39
111/scripts/ComboAnimatorScript.py
Normal file
@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
复合动画脚本 - 结合旋转和跳跃效果
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
import math
|
||||
|
||||
class ComboAnimatorScript(ScriptBase):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.time = 0.0
|
||||
self.original_pos = None
|
||||
self.is_active = True
|
||||
|
||||
def start(self):
|
||||
self.log("复合动画脚本启动!")
|
||||
self.original_pos = self.gameObject.getPos()
|
||||
|
||||
def update(self, dt):
|
||||
if not self.is_active:
|
||||
return
|
||||
|
||||
self.time += dt
|
||||
|
||||
# 旋转效果
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
new_h = current_hpr.getX() + 45.0 * dt
|
||||
self.gameObject.setHpr(new_h, current_hpr.getY(), current_hpr.getZ())
|
||||
|
||||
# 跳跃效果
|
||||
if self.original_pos:
|
||||
bounce_offset = abs(math.sin(self.time * 3.0)) * 1.0
|
||||
self.gameObject.setZ(self.original_pos.getZ() + bounce_offset)
|
||||
|
||||
def on_destroy(self):
|
||||
self.log("复合动画脚本停止")
|
||||
69
111/scripts/FollowerScript.py
Normal file
69
111/scripts/FollowerScript.py
Normal file
@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
跟随脚本 - 让对象跟随指定的目标对象
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
from panda3d.core import Vec3
|
||||
|
||||
class FollowerScript(ScriptBase):
|
||||
"""跟随脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.target = None # 跟随目标
|
||||
self.follow_speed = 5.0 # 跟随速度
|
||||
self.follow_distance = 2.0 # 跟随距离
|
||||
self.is_following = True # 是否正在跟随
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("跟随脚本启动!")
|
||||
self.log(f"跟随参数: 速度={self.follow_speed}, 距离={self.follow_distance}")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_following or self.target is None:
|
||||
return
|
||||
|
||||
target_pos = self.target.getPos()
|
||||
current_pos = self.gameObject.getPos()
|
||||
|
||||
# 计算目标方向
|
||||
direction = target_pos - current_pos
|
||||
distance = direction.length()
|
||||
|
||||
# 如果距离大于跟随距离,则移动
|
||||
if distance > self.follow_distance:
|
||||
if distance > 0:
|
||||
direction.normalize()
|
||||
|
||||
# 计算目标位置(保持跟随距离)
|
||||
target_follow_pos = target_pos - direction * self.follow_distance
|
||||
|
||||
# 平滑移动到目标位置
|
||||
move_direction = target_follow_pos - current_pos
|
||||
move_distance = move_direction.length()
|
||||
|
||||
if move_distance > 0:
|
||||
move_direction.normalize()
|
||||
move_amount = min(self.follow_speed * dt, move_distance)
|
||||
new_pos = current_pos + move_direction * move_amount
|
||||
self.gameObject.setPos(new_pos)
|
||||
|
||||
# 朝向目标
|
||||
self.gameObject.lookAt(target_pos)
|
||||
|
||||
def set_target(self, target):
|
||||
"""设置跟随目标"""
|
||||
self.target = target
|
||||
if target:
|
||||
self.log(f"设置跟随目标: {target.getName()}")
|
||||
else:
|
||||
self.log("清除跟随目标")
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("跟随脚本停止")
|
||||
91
111/scripts/MoverScript.py
Normal file
91
111/scripts/MoverScript.py
Normal file
@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
移动脚本 - 让对象在指定方向上来回移动
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
import math
|
||||
|
||||
class MoverScript(ScriptBase):
|
||||
"""移动脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# 移动参数
|
||||
self.move_distance = 5.0 # 移动距离
|
||||
self.move_speed = 2.0 # 移动速度 (单位/秒)
|
||||
self.move_axis = "x" # 移动轴: "x", "y", "z"
|
||||
|
||||
# 内部变量
|
||||
self.start_position = None # 起始位置
|
||||
self.current_direction = 1 # 当前移动方向: 1或-1
|
||||
self.current_distance = 0.0 # 当前移动距离
|
||||
self.is_moving = True # 是否正在移动
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("移动脚本启动!")
|
||||
self.log(f"移动参数: 距离={self.move_distance}, 速度={self.move_speed}, 轴={self.move_axis}")
|
||||
|
||||
# 记录起始位置
|
||||
self.start_position = self.gameObject.getPos()
|
||||
self.log(f"起始位置: {self.start_position}")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_moving or self.start_position is None:
|
||||
return
|
||||
|
||||
# 计算移动增量
|
||||
move_delta = self.move_speed * dt * self.current_direction
|
||||
self.current_distance += abs(move_delta)
|
||||
|
||||
# 检查是否需要改变方向
|
||||
if self.current_distance >= self.move_distance:
|
||||
self.current_direction *= -1
|
||||
self.current_distance = 0.0
|
||||
|
||||
# 应用移动
|
||||
current_pos = self.gameObject.getPos()
|
||||
new_pos = [current_pos.getX(), current_pos.getY(), current_pos.getZ()]
|
||||
|
||||
if self.move_axis == "x":
|
||||
new_pos[0] += move_delta
|
||||
elif self.move_axis == "y":
|
||||
new_pos[1] += move_delta
|
||||
elif self.move_axis == "z":
|
||||
new_pos[2] += move_delta
|
||||
|
||||
self.gameObject.setPos(new_pos[0], new_pos[1], new_pos[2])
|
||||
|
||||
def set_move_parameters(self, distance=None, speed=None, axis=None):
|
||||
"""设置移动参数"""
|
||||
if distance is not None:
|
||||
self.move_distance = distance
|
||||
if speed is not None:
|
||||
self.move_speed = speed
|
||||
if axis is not None and axis in ["x", "y", "z"]:
|
||||
self.move_axis = axis
|
||||
|
||||
self.log(f"移动参数更新: 距离={self.move_distance}, 速度={self.move_speed}, 轴={self.move_axis}")
|
||||
|
||||
def toggle_movement(self):
|
||||
"""切换移动状态"""
|
||||
self.is_moving = not self.is_moving
|
||||
status = "恢复" if self.is_moving else "暂停"
|
||||
self.log(f"移动{status}")
|
||||
|
||||
def reset_position(self):
|
||||
"""重置到起始位置"""
|
||||
if self.start_position:
|
||||
self.gameObject.setPos(self.start_position)
|
||||
self.current_distance = 0.0
|
||||
self.current_direction = 1
|
||||
self.log("位置已重置到起始点")
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("移动脚本停止")
|
||||
133
111/scripts/R_P.py
Normal file
133
111/scripts/R_P.py
Normal file
@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
旋转脚本 - 让对象持续旋转
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
|
||||
class RotatorScript(ScriptBase):
|
||||
"""旋转脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.rotation_speed_y = 30.0 # Y轴旋转速度 (度/秒)
|
||||
self.max_angle = 30.0 # 最大旋转角度(相对于初始角度)
|
||||
self.direction = 1
|
||||
self.current_offset = 0.0 # 当前相对于初始角度的偏移
|
||||
self.initial_angle = None # 模型的初始角度
|
||||
self.is_rotating = True # 是否正在旋转
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("旋转脚本启动!")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"最大旋转角度: ±{self.max_angle}度")
|
||||
|
||||
# 记录模型的初始角度
|
||||
if self.gameObject:
|
||||
initial_hpr = self.gameObject.getHpr()
|
||||
self.initial_angle = initial_hpr.getZ() # 记录Z轴的初始角度
|
||||
self.log(f"模型初始角度: {self.initial_angle}度")
|
||||
self.log(f"旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
else:
|
||||
self.log("⚠️ 无法获取游戏对象,使用默认初始角度0")
|
||||
self.initial_angle = 0.0
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_rotating or self.initial_angle is None:
|
||||
return
|
||||
|
||||
# 计算角度变化量
|
||||
delta_angle = self.rotation_speed_y * dt * self.direction
|
||||
self.current_offset += delta_angle
|
||||
|
||||
# 如果超出角度范围,则反向并限制在边界
|
||||
if self.current_offset > self.max_angle:
|
||||
self.current_offset = self.max_angle
|
||||
self.direction *= -1
|
||||
elif self.current_offset < -self.max_angle:
|
||||
self.current_offset = -self.max_angle
|
||||
self.direction *= -1
|
||||
|
||||
# 计算最终角度(初始角度 + 偏移量)
|
||||
final_angle = self.initial_angle + self.current_offset
|
||||
|
||||
# 设置新的旋转(只改变Z轴,保持其他不变)
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), final_angle, current_hpr.getZ())
|
||||
|
||||
# if not self.is_rotating:
|
||||
# return
|
||||
#
|
||||
# # 获取当前旋转并应用增量
|
||||
# current_hpr = self.gameObject.getHpr()
|
||||
# new_r = current_hpr.getZ() + self.rotation_speed_y * dt
|
||||
# self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), new_r)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("旋转脚本停止")
|
||||
|
||||
# ==================== 控制方法 ====================
|
||||
|
||||
def set_max_angle(self, new_max_angle):
|
||||
"""
|
||||
设置新的最大旋转角度
|
||||
|
||||
Args:
|
||||
new_max_angle: 新的最大角度值
|
||||
"""
|
||||
self.max_angle = new_max_angle
|
||||
self.log(f"最大旋转角度已设置为: ±{self.max_angle}度")
|
||||
if self.initial_angle is not None:
|
||||
self.log(f"新的旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
|
||||
def set_rotation_speed(self, new_speed):
|
||||
"""
|
||||
设置新的旋转速度
|
||||
|
||||
Args:
|
||||
new_speed: 新的旋转速度(度/秒)
|
||||
"""
|
||||
self.rotation_speed_y = new_speed
|
||||
self.log(f"旋转速度已设置为: {self.rotation_speed_y}度/秒")
|
||||
|
||||
def pause_rotation(self):
|
||||
"""暂停旋转"""
|
||||
self.is_rotating = False
|
||||
self.log("旋转已暂停")
|
||||
|
||||
def resume_rotation(self):
|
||||
"""恢复旋转"""
|
||||
self.is_rotating = True
|
||||
self.log("旋转已恢复")
|
||||
|
||||
def reset_to_initial_angle(self):
|
||||
"""重置到初始角度"""
|
||||
if self.initial_angle is not None and self.gameObject:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), self.initial_angle)
|
||||
self.current_offset = 0.0
|
||||
self.direction = 1
|
||||
self.log(f"已重置到初始角度: {self.initial_angle}度")
|
||||
|
||||
def get_current_info(self):
|
||||
"""获取当前旋转信息"""
|
||||
if self.gameObject and self.initial_angle is not None:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
current_angle = current_hpr.getZ()
|
||||
self.log("=== 当前旋转信息 ===")
|
||||
self.log(f"初始角度: {self.initial_angle}度")
|
||||
self.log(f"当前角度: {current_angle}度")
|
||||
self.log(f"偏移量: {self.current_offset}度")
|
||||
self.log(f"最大角度: ±{self.max_angle}度")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"旋转方向: {'正向' if self.direction > 0 else '反向'}")
|
||||
self.log(f"旋转状态: {'运行中' if self.is_rotating else '已暂停'}")
|
||||
self.log("=== 信息结束 ===")
|
||||
else:
|
||||
self.log("无法获取旋转信息")
|
||||
133
111/scripts/R_R.py
Normal file
133
111/scripts/R_R.py
Normal file
@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
旋转脚本 - 让对象持续旋转
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
|
||||
class RotatorScript(ScriptBase):
|
||||
"""旋转脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.rotation_speed_y = 30.0 # Y轴旋转速度 (度/秒)
|
||||
self.max_angle = 30.0 # 最大旋转角度(相对于初始角度)
|
||||
self.direction = 1
|
||||
self.current_offset = 0.0 # 当前相对于初始角度的偏移
|
||||
self.initial_angle = None # 模型的初始角度
|
||||
self.is_rotating = True # 是否正在旋转
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("旋转脚本启动!")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"最大旋转角度: ±{self.max_angle}度")
|
||||
|
||||
# 记录模型的初始角度
|
||||
if self.gameObject:
|
||||
initial_hpr = self.gameObject.getHpr()
|
||||
self.initial_angle = initial_hpr.getZ() # 记录Z轴的初始角度
|
||||
self.log(f"模型初始角度: {self.initial_angle}度")
|
||||
self.log(f"旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
else:
|
||||
self.log("⚠️ 无法获取游戏对象,使用默认初始角度0")
|
||||
self.initial_angle = 0.0
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_rotating or self.initial_angle is None:
|
||||
return
|
||||
|
||||
# 计算角度变化量
|
||||
delta_angle = self.rotation_speed_y * dt * self.direction
|
||||
self.current_offset += delta_angle
|
||||
|
||||
# 如果超出角度范围,则反向并限制在边界
|
||||
if self.current_offset > self.max_angle:
|
||||
self.current_offset = self.max_angle
|
||||
self.direction *= -1
|
||||
elif self.current_offset < -self.max_angle:
|
||||
self.current_offset = -self.max_angle
|
||||
self.direction *= -1
|
||||
|
||||
# 计算最终角度(初始角度 + 偏移量)
|
||||
final_angle = self.initial_angle + self.current_offset
|
||||
|
||||
# 设置新的旋转(只改变Z轴,保持其他不变)
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), final_angle)
|
||||
|
||||
# if not self.is_rotating:
|
||||
# return
|
||||
#
|
||||
# # 获取当前旋转并应用增量
|
||||
# current_hpr = self.gameObject.getHpr()
|
||||
# new_r = current_hpr.getZ() + self.rotation_speed_y * dt
|
||||
# self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), new_r)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("旋转脚本停止")
|
||||
|
||||
# ==================== 控制方法 ====================
|
||||
|
||||
def set_max_angle(self, new_max_angle):
|
||||
"""
|
||||
设置新的最大旋转角度
|
||||
|
||||
Args:
|
||||
new_max_angle: 新的最大角度值
|
||||
"""
|
||||
self.max_angle = new_max_angle
|
||||
self.log(f"最大旋转角度已设置为: ±{self.max_angle}度")
|
||||
if self.initial_angle is not None:
|
||||
self.log(f"新的旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
|
||||
def set_rotation_speed(self, new_speed):
|
||||
"""
|
||||
设置新的旋转速度
|
||||
|
||||
Args:
|
||||
new_speed: 新的旋转速度(度/秒)
|
||||
"""
|
||||
self.rotation_speed_y = new_speed
|
||||
self.log(f"旋转速度已设置为: {self.rotation_speed_y}度/秒")
|
||||
|
||||
def pause_rotation(self):
|
||||
"""暂停旋转"""
|
||||
self.is_rotating = False
|
||||
self.log("旋转已暂停")
|
||||
|
||||
def resume_rotation(self):
|
||||
"""恢复旋转"""
|
||||
self.is_rotating = True
|
||||
self.log("旋转已恢复")
|
||||
|
||||
def reset_to_initial_angle(self):
|
||||
"""重置到初始角度"""
|
||||
if self.initial_angle is not None and self.gameObject:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), self.initial_angle)
|
||||
self.current_offset = 0.0
|
||||
self.direction = 1
|
||||
self.log(f"已重置到初始角度: {self.initial_angle}度")
|
||||
|
||||
def get_current_info(self):
|
||||
"""获取当前旋转信息"""
|
||||
if self.gameObject and self.initial_angle is not None:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
current_angle = current_hpr.getZ()
|
||||
self.log("=== 当前旋转信息 ===")
|
||||
self.log(f"初始角度: {self.initial_angle}度")
|
||||
self.log(f"当前角度: {current_angle}度")
|
||||
self.log(f"偏移量: {self.current_offset}度")
|
||||
self.log(f"最大角度: ±{self.max_angle}度")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"旋转方向: {'正向' if self.direction > 0 else '反向'}")
|
||||
self.log(f"旋转状态: {'运行中' if self.is_rotating else '已暂停'}")
|
||||
self.log("=== 信息结束 ===")
|
||||
else:
|
||||
self.log("无法获取旋转信息")
|
||||
215
111/scripts/Rotate_H_Script.py
Normal file
215
111/scripts/Rotate_H_Script.py
Normal file
@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
旋转脚本 - 让对象持续旋转
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
|
||||
class RotatorScript(ScriptBase):
|
||||
"""旋转脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.rotation_speed_y = 30.0 # Y轴旋转速度 (度/秒)
|
||||
self.max_angle = 30.0 # 最大旋转角度(相对于初始角度)
|
||||
self.direction = 1
|
||||
self.current_offset = 0.0 # 当前相对于初始角度的偏移
|
||||
self.initial_angle = None # 模型的初始角度
|
||||
self.is_rotating = True # 是否正在旋转
|
||||
|
||||
# 机器人式停顿参数
|
||||
self.pause_duration = 0.5 # 停顿时间(秒)
|
||||
self.current_pause_time = 0.0 # 当前停顿计时
|
||||
self.is_paused = False # 是否正在停顿
|
||||
self.robot_mode = True # 是否启用机器人模式
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("机器人旋转脚本启动!")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"最大旋转角度: ±{self.max_angle}度")
|
||||
self.log(f"机器人模式: {'开启' if self.robot_mode else '关闭'}")
|
||||
if self.robot_mode:
|
||||
self.log(f"停顿时间: {self.pause_duration}秒")
|
||||
|
||||
# 记录模型的初始角度
|
||||
if self.gameObject:
|
||||
initial_hpr = self.gameObject.getHpr()
|
||||
self.initial_angle = initial_hpr.getY() # 记录Y轴的初始角度(Pitch)
|
||||
self.log(f"模型初始角度: {self.initial_angle}度")
|
||||
self.log(f"旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
else:
|
||||
self.log("⚠️ 无法获取游戏对象,使用默认初始角度0")
|
||||
self.initial_angle = 0.0
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新 - 机器人式旋转"""
|
||||
if not self.is_rotating or self.initial_angle is None:
|
||||
return
|
||||
|
||||
# 如果正在停顿中
|
||||
if self.is_paused:
|
||||
self.current_pause_time += dt
|
||||
if self.current_pause_time >= self.pause_duration:
|
||||
# 停顿结束,继续旋转
|
||||
self.is_paused = False
|
||||
self.current_pause_time = 0.0
|
||||
self.log(f"停顿结束,继续旋转,方向: {'正向' if self.direction > 0 else '反向'}")
|
||||
return
|
||||
|
||||
# 计算角度变化量
|
||||
delta_angle = self.rotation_speed_y * dt * self.direction
|
||||
self.current_offset += delta_angle
|
||||
|
||||
# 检查是否到达边界
|
||||
reached_boundary = False
|
||||
if self.current_offset > self.max_angle:
|
||||
self.current_offset = self.max_angle
|
||||
self.direction *= -1
|
||||
reached_boundary = True
|
||||
elif self.current_offset < -self.max_angle:
|
||||
self.current_offset = -self.max_angle
|
||||
self.direction *= -1
|
||||
reached_boundary = True
|
||||
|
||||
# 如果到达边界且启用机器人模式,开始停顿
|
||||
if reached_boundary and self.robot_mode:
|
||||
self.is_paused = True
|
||||
self.current_pause_time = 0.0
|
||||
self.log(f"到达边界 ({self.current_offset}°),开始停顿 {self.pause_duration}秒")
|
||||
|
||||
# 计算最终角度(初始角度 + 偏移量)
|
||||
final_angle = self.initial_angle + self.current_offset
|
||||
|
||||
# 设置新的旋转(只改变Y轴,保持其他不变)
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(final_angle, current_hpr.getY(), current_hpr.getZ())
|
||||
|
||||
# if not self.is_rotating:
|
||||
# return
|
||||
#
|
||||
# # 获取当前旋转并应用增量
|
||||
# current_hpr = self.gameObject.getHpr()
|
||||
# new_r = current_hpr.getZ() + self.rotation_speed_y * dt
|
||||
# self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), new_r)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("机器人旋转脚本停止")
|
||||
|
||||
# ==================== 机器人模式控制方法 ====================
|
||||
|
||||
def set_robot_mode(self, enabled=True):
|
||||
"""
|
||||
启用或禁用机器人模式
|
||||
|
||||
Args:
|
||||
enabled: 是否启用机器人模式
|
||||
"""
|
||||
self.robot_mode = enabled
|
||||
self.log(f"机器人模式: {'开启' if enabled else '关闭'}")
|
||||
if not enabled:
|
||||
self.is_paused = False # 如果禁用机器人模式,立即结束停顿
|
||||
|
||||
def set_pause_duration(self, duration):
|
||||
"""
|
||||
设置停顿时间
|
||||
|
||||
Args:
|
||||
duration: 停顿时间(秒)
|
||||
"""
|
||||
self.pause_duration = max(0.1, duration) # 最小0.1秒
|
||||
self.log(f"停顿时间已设置为: {self.pause_duration}秒")
|
||||
|
||||
def set_max_angle(self, new_max_angle):
|
||||
"""
|
||||
设置新的最大旋转角度
|
||||
|
||||
Args:
|
||||
new_max_angle: 新的最大角度值
|
||||
"""
|
||||
self.max_angle = new_max_angle
|
||||
self.log(f"最大旋转角度已设置为: ±{self.max_angle}度")
|
||||
if self.initial_angle is not None:
|
||||
self.log(f"新的旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
|
||||
def set_rotation_speed(self, new_speed):
|
||||
"""
|
||||
设置新的旋转速度
|
||||
|
||||
Args:
|
||||
new_speed: 新的旋转速度(度/秒)
|
||||
"""
|
||||
self.rotation_speed_y = new_speed
|
||||
self.log(f"旋转速度已设置为: {self.rotation_speed_y}度/秒")
|
||||
|
||||
def pause_rotation(self):
|
||||
"""暂停旋转"""
|
||||
self.is_rotating = False
|
||||
self.log("旋转已暂停")
|
||||
|
||||
def resume_rotation(self):
|
||||
"""恢复旋转"""
|
||||
self.is_rotating = True
|
||||
self.is_paused = False # 同时结束停顿状态
|
||||
self.log("旋转已恢复")
|
||||
|
||||
def reset_to_initial_angle(self):
|
||||
"""重置到初始角度"""
|
||||
if self.initial_angle is not None and self.gameObject:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), self.initial_angle, current_hpr.getZ())
|
||||
self.current_offset = 0.0
|
||||
self.direction = 1
|
||||
self.is_paused = False
|
||||
self.current_pause_time = 0.0
|
||||
self.log(f"已重置到初始角度: {self.initial_angle}度")
|
||||
|
||||
def get_current_info(self):
|
||||
"""获取当前旋转信息"""
|
||||
if self.gameObject and self.initial_angle is not None:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
current_angle = current_hpr.getY()
|
||||
self.log("=== 机器人旋转信息 ===")
|
||||
self.log(f"初始角度: {self.initial_angle}度")
|
||||
self.log(f"当前角度: {current_angle}度")
|
||||
self.log(f"偏移量: {self.current_offset}度")
|
||||
self.log(f"最大角度: ±{self.max_angle}度")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"旋转方向: {'正向' if self.direction > 0 else '反向'}")
|
||||
self.log(f"旋转状态: {'运行中' if self.is_rotating else '已暂停'}")
|
||||
self.log(f"机器人模式: {'开启' if self.robot_mode else '关闭'}")
|
||||
if self.robot_mode:
|
||||
self.log(f"停顿时间: {self.pause_duration}秒")
|
||||
self.log(f"当前状态: {'停顿中' if self.is_paused else '旋转中'}")
|
||||
if self.is_paused:
|
||||
remaining_time = self.pause_duration - self.current_pause_time
|
||||
self.log(f"剩余停顿时间: {remaining_time:.1f}秒")
|
||||
self.log("=== 信息结束 ===")
|
||||
else:
|
||||
self.log("无法获取旋转信息")
|
||||
|
||||
# ==================== 预设配置方法 ====================
|
||||
|
||||
def set_slow_robot_mode(self):
|
||||
"""预设:慢速机器人模式"""
|
||||
self.set_rotation_speed(15.0)
|
||||
self.set_pause_duration(1.0)
|
||||
self.set_robot_mode(True)
|
||||
self.log("已设置为慢速机器人模式")
|
||||
|
||||
def set_fast_robot_mode(self):
|
||||
"""预设:快速机器人模式"""
|
||||
self.set_rotation_speed(45.0)
|
||||
self.set_pause_duration(0.3)
|
||||
self.set_robot_mode(True)
|
||||
self.log("已设置为快速机器人模式")
|
||||
|
||||
def set_smooth_mode(self):
|
||||
"""预设:平滑模式(非机器人)"""
|
||||
self.set_robot_mode(False)
|
||||
self.set_rotation_speed(30.0)
|
||||
self.log("已设置为平滑旋转模式")
|
||||
215
111/scripts/Rotate_P_Script.py
Normal file
215
111/scripts/Rotate_P_Script.py
Normal file
@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
旋转脚本 - 让对象持续旋转
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
|
||||
class RotatorScript(ScriptBase):
|
||||
"""旋转脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.rotation_speed_y = 30.0 # Y轴旋转速度 (度/秒)
|
||||
self.max_angle = 25.0 # 最大旋转角度(相对于初始角度)
|
||||
self.direction = 1
|
||||
self.current_offset = 0.0 # 当前相对于初始角度的偏移
|
||||
self.initial_angle = None # 模型的初始角度
|
||||
self.is_rotating = True # 是否正在旋转
|
||||
|
||||
# 机器人式停顿参数
|
||||
self.pause_duration = 0.5 # 停顿时间(秒)
|
||||
self.current_pause_time = 0.0 # 当前停顿计时
|
||||
self.is_paused = False # 是否正在停顿
|
||||
self.robot_mode = True # 是否启用机器人模式
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("机器人旋转脚本启动!")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"最大旋转角度: ±{self.max_angle}度")
|
||||
self.log(f"机器人模式: {'开启' if self.robot_mode else '关闭'}")
|
||||
if self.robot_mode:
|
||||
self.log(f"停顿时间: {self.pause_duration}秒")
|
||||
|
||||
# 记录模型的初始角度
|
||||
if self.gameObject:
|
||||
initial_hpr = self.gameObject.getHpr()
|
||||
self.initial_angle = initial_hpr.getY() # 记录Y轴的初始角度(Pitch)
|
||||
self.log(f"模型初始角度: {self.initial_angle}度")
|
||||
self.log(f"旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
else:
|
||||
self.log("⚠️ 无法获取游戏对象,使用默认初始角度0")
|
||||
self.initial_angle = 0.0
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新 - 机器人式旋转"""
|
||||
if not self.is_rotating or self.initial_angle is None:
|
||||
return
|
||||
|
||||
# 如果正在停顿中
|
||||
if self.is_paused:
|
||||
self.current_pause_time += dt
|
||||
if self.current_pause_time >= self.pause_duration:
|
||||
# 停顿结束,继续旋转
|
||||
self.is_paused = False
|
||||
self.current_pause_time = 0.0
|
||||
self.log(f"停顿结束,继续旋转,方向: {'正向' if self.direction > 0 else '反向'}")
|
||||
return
|
||||
|
||||
# 计算角度变化量
|
||||
delta_angle = self.rotation_speed_y * dt * self.direction
|
||||
self.current_offset += delta_angle
|
||||
|
||||
# 检查是否到达边界
|
||||
reached_boundary = False
|
||||
if self.current_offset > self.max_angle:
|
||||
self.current_offset = self.max_angle
|
||||
self.direction *= -1
|
||||
reached_boundary = True
|
||||
elif self.current_offset < -self.max_angle:
|
||||
self.current_offset = -self.max_angle
|
||||
self.direction *= -1
|
||||
reached_boundary = True
|
||||
|
||||
# 如果到达边界且启用机器人模式,开始停顿
|
||||
if reached_boundary and self.robot_mode:
|
||||
self.is_paused = True
|
||||
self.current_pause_time = 0.0
|
||||
self.log(f"到达边界 ({self.current_offset}°),开始停顿 {self.pause_duration}秒")
|
||||
|
||||
# 计算最终角度(初始角度 + 偏移量)
|
||||
final_angle = self.initial_angle + self.current_offset
|
||||
|
||||
# 设置新的旋转(只改变Y轴,保持其他不变)
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), final_angle, current_hpr.getZ())
|
||||
|
||||
# if not self.is_rotating:
|
||||
# return
|
||||
#
|
||||
# # 获取当前旋转并应用增量
|
||||
# current_hpr = self.gameObject.getHpr()
|
||||
# new_r = current_hpr.getZ() + self.rotation_speed_y * dt
|
||||
# self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), new_r)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("机器人旋转脚本停止")
|
||||
|
||||
# ==================== 机器人模式控制方法 ====================
|
||||
|
||||
def set_robot_mode(self, enabled=True):
|
||||
"""
|
||||
启用或禁用机器人模式
|
||||
|
||||
Args:
|
||||
enabled: 是否启用机器人模式
|
||||
"""
|
||||
self.robot_mode = enabled
|
||||
self.log(f"机器人模式: {'开启' if enabled else '关闭'}")
|
||||
if not enabled:
|
||||
self.is_paused = False # 如果禁用机器人模式,立即结束停顿
|
||||
|
||||
def set_pause_duration(self, duration):
|
||||
"""
|
||||
设置停顿时间
|
||||
|
||||
Args:
|
||||
duration: 停顿时间(秒)
|
||||
"""
|
||||
self.pause_duration = max(0.1, duration) # 最小0.1秒
|
||||
self.log(f"停顿时间已设置为: {self.pause_duration}秒")
|
||||
|
||||
def set_max_angle(self, new_max_angle):
|
||||
"""
|
||||
设置新的最大旋转角度
|
||||
|
||||
Args:
|
||||
new_max_angle: 新的最大角度值
|
||||
"""
|
||||
self.max_angle = new_max_angle
|
||||
self.log(f"最大旋转角度已设置为: ±{self.max_angle}度")
|
||||
if self.initial_angle is not None:
|
||||
self.log(f"新的旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
|
||||
def set_rotation_speed(self, new_speed):
|
||||
"""
|
||||
设置新的旋转速度
|
||||
|
||||
Args:
|
||||
new_speed: 新的旋转速度(度/秒)
|
||||
"""
|
||||
self.rotation_speed_y = new_speed
|
||||
self.log(f"旋转速度已设置为: {self.rotation_speed_y}度/秒")
|
||||
|
||||
def pause_rotation(self):
|
||||
"""暂停旋转"""
|
||||
self.is_rotating = False
|
||||
self.log("旋转已暂停")
|
||||
|
||||
def resume_rotation(self):
|
||||
"""恢复旋转"""
|
||||
self.is_rotating = True
|
||||
self.is_paused = False # 同时结束停顿状态
|
||||
self.log("旋转已恢复")
|
||||
|
||||
def reset_to_initial_angle(self):
|
||||
"""重置到初始角度"""
|
||||
if self.initial_angle is not None and self.gameObject:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), self.initial_angle, current_hpr.getZ())
|
||||
self.current_offset = 0.0
|
||||
self.direction = 1
|
||||
self.is_paused = False
|
||||
self.current_pause_time = 0.0
|
||||
self.log(f"已重置到初始角度: {self.initial_angle}度")
|
||||
|
||||
def get_current_info(self):
|
||||
"""获取当前旋转信息"""
|
||||
if self.gameObject and self.initial_angle is not None:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
current_angle = current_hpr.getY()
|
||||
self.log("=== 机器人旋转信息 ===")
|
||||
self.log(f"初始角度: {self.initial_angle}度")
|
||||
self.log(f"当前角度: {current_angle}度")
|
||||
self.log(f"偏移量: {self.current_offset}度")
|
||||
self.log(f"最大角度: ±{self.max_angle}度")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"旋转方向: {'正向' if self.direction > 0 else '反向'}")
|
||||
self.log(f"旋转状态: {'运行中' if self.is_rotating else '已暂停'}")
|
||||
self.log(f"机器人模式: {'开启' if self.robot_mode else '关闭'}")
|
||||
if self.robot_mode:
|
||||
self.log(f"停顿时间: {self.pause_duration}秒")
|
||||
self.log(f"当前状态: {'停顿中' if self.is_paused else '旋转中'}")
|
||||
if self.is_paused:
|
||||
remaining_time = self.pause_duration - self.current_pause_time
|
||||
self.log(f"剩余停顿时间: {remaining_time:.1f}秒")
|
||||
self.log("=== 信息结束 ===")
|
||||
else:
|
||||
self.log("无法获取旋转信息")
|
||||
|
||||
# ==================== 预设配置方法 ====================
|
||||
|
||||
def set_slow_robot_mode(self):
|
||||
"""预设:慢速机器人模式"""
|
||||
self.set_rotation_speed(15.0)
|
||||
self.set_pause_duration(1.0)
|
||||
self.set_robot_mode(True)
|
||||
self.log("已设置为慢速机器人模式")
|
||||
|
||||
def set_fast_robot_mode(self):
|
||||
"""预设:快速机器人模式"""
|
||||
self.set_rotation_speed(45.0)
|
||||
self.set_pause_duration(0.3)
|
||||
self.set_robot_mode(True)
|
||||
self.log("已设置为快速机器人模式")
|
||||
|
||||
def set_smooth_mode(self):
|
||||
"""预设:平滑模式(非机器人)"""
|
||||
self.set_robot_mode(False)
|
||||
self.set_rotation_speed(30.0)
|
||||
self.log("已设置为平滑旋转模式")
|
||||
56
111/scripts/Rotate_R_Script.py
Normal file
56
111/scripts/Rotate_R_Script.py
Normal file
@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
旋转脚本 - 让对象持续旋转
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
|
||||
class RotatorScript(ScriptBase):
|
||||
"""旋转脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.rotation_speed_y = 30.0 # Y轴旋转速度 (度/秒)
|
||||
self.max_angle = 15.0
|
||||
self.direction = 1
|
||||
self.current_angle = 0.0
|
||||
self.is_rotating = True # 是否正在旋转
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("旋转脚本启动!")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
|
||||
delta_angle = self.rotation_speed_y * dt * self.direction
|
||||
self.current_angle += delta_angle
|
||||
|
||||
# 如果超出角度范围,则反向
|
||||
if self.current_angle > self.max_angle:
|
||||
self.current_angle = self.max_angle
|
||||
self.direction *= -1
|
||||
elif self.current_angle < -self.max_angle:
|
||||
self.current_angle = -self.max_angle
|
||||
self.direction *= -1
|
||||
|
||||
# 设置新的旋转(只改变Z轴,保持其他不变)
|
||||
base_hpr = self.gameObject.getHpr()
|
||||
new_r = self.current_angle
|
||||
self.gameObject.setHpr(base_hpr.getX(), base_hpr.getY(), new_r)
|
||||
|
||||
# if not self.is_rotating:
|
||||
# return
|
||||
#
|
||||
# # 获取当前旋转并应用增量
|
||||
# current_hpr = self.gameObject.getHpr()
|
||||
# new_r = current_hpr.getZ() + self.rotation_speed_y * dt
|
||||
# self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), new_r)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("旋转脚本停止")
|
||||
39
111/scripts/RotatorScript.py
Normal file
39
111/scripts/RotatorScript.py
Normal file
@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
旋转脚本 - 让对象持续旋转
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class RotatorScript(ScriptBase):
|
||||
"""旋转脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.rotation_speed_y = 30.0 # Y轴旋转速度 (度/秒)
|
||||
self.is_rotating = True # 是否正在旋转
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("旋转脚本启动!")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
|
||||
def update(self, dt):
|
||||
# 检查 gameObject 是否存在且不为空
|
||||
if not self.gameObject or self.gameObject.isEmpty():
|
||||
print("RotatorScript: gameObject is empty or None, skipping update")
|
||||
return
|
||||
"""每帧更新"""
|
||||
if not self.is_rotating:
|
||||
return
|
||||
|
||||
# 获取当前旋转并应用增量
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
new_h = current_hpr.getX() + self.rotation_speed_y * dt
|
||||
self.gameObject.setHpr(new_h, current_hpr.getY(), current_hpr.getZ())
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("旋转脚本停止")
|
||||
91
111/scripts/ScalerScript.py
Normal file
91
111/scripts/ScalerScript.py
Normal file
@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
缩放脚本 - 让对象产生呼吸般的缩放效果
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
import math
|
||||
|
||||
class ScalerScript(ScriptBase):
|
||||
"""缩放脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# 缩放参数
|
||||
self.base_scale = 1.0 # 基础缩放
|
||||
self.scale_amplitude = 0.3 # 缩放幅度
|
||||
self.scale_speed = 2.0 # 缩放速度 (周期/秒)
|
||||
self.uniform_scale = True # 是否统一缩放(所有轴)
|
||||
|
||||
# 内部变量
|
||||
self.time_accumulator = 0.0 # 时间累积器
|
||||
self.original_scale = None # 原始缩放
|
||||
self.is_scaling = True # 是否正在缩放
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("缩放脚本启动!")
|
||||
self.log(f"缩放参数: 基础={self.base_scale}, 幅度={self.scale_amplitude}, 速度={self.scale_speed}")
|
||||
|
||||
# 记录原始缩放
|
||||
self.original_scale = self.gameObject.getScale()
|
||||
self.log(f"原始缩放: {self.original_scale}")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_scaling:
|
||||
return
|
||||
|
||||
# 累积时间
|
||||
self.time_accumulator += dt
|
||||
|
||||
# 计算正弦波缩放值
|
||||
sine_value = math.sin(self.time_accumulator * self.scale_speed * 2 * math.pi)
|
||||
scale_factor = self.base_scale + (self.scale_amplitude * sine_value)
|
||||
|
||||
# 应用缩放
|
||||
if self.uniform_scale:
|
||||
# 统一缩放
|
||||
self.gameObject.setScale(scale_factor)
|
||||
else:
|
||||
# 非统一缩放(仅Z轴)
|
||||
current_scale = self.gameObject.getScale()
|
||||
self.gameObject.setScale(current_scale.getX(), current_scale.getY(), scale_factor)
|
||||
|
||||
def set_scale_parameters(self, base=None, amplitude=None, speed=None, uniform=None):
|
||||
"""设置缩放参数"""
|
||||
if base is not None:
|
||||
self.base_scale = base
|
||||
if amplitude is not None:
|
||||
self.scale_amplitude = amplitude
|
||||
if speed is not None:
|
||||
self.scale_speed = speed
|
||||
if uniform is not None:
|
||||
self.uniform_scale = uniform
|
||||
|
||||
self.log(f"缩放参数更新: 基础={self.base_scale}, 幅度={self.scale_amplitude}, 速度={self.scale_speed}")
|
||||
|
||||
def toggle_scaling(self):
|
||||
"""切换缩放状态"""
|
||||
self.is_scaling = not self.is_scaling
|
||||
status = "恢复" if self.is_scaling else "暂停"
|
||||
self.log(f"缩放{status}")
|
||||
|
||||
def reset_scale(self):
|
||||
"""重置到原始缩放"""
|
||||
if self.original_scale:
|
||||
self.gameObject.setScale(self.original_scale)
|
||||
self.time_accumulator = 0.0
|
||||
self.log("缩放已重置到原始值")
|
||||
|
||||
def pulse_once(self):
|
||||
"""执行一次脉冲缩放"""
|
||||
self.time_accumulator = 0.0
|
||||
self.log("执行脉冲缩放")
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("缩放脚本停止")
|
||||
41
111/scripts/TestMover.py
Normal file
41
111/scripts/TestMover.py
Normal file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
TestMover - 移动脚本
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class Testmover(ScriptBase):
|
||||
"""移动脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.speed = 5.0 # 移动速度
|
||||
self.direction = [1, 0, 0] # 移动方向
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("移动脚本开始运行!")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if self.transform:
|
||||
# 计算移动偏移
|
||||
offset_x = self.direction[0] * self.speed * dt
|
||||
offset_y = self.direction[1] * self.speed * dt
|
||||
offset_z = self.direction[2] * self.speed * dt
|
||||
|
||||
# 更新位置
|
||||
current_pos = self.transform.getPos()
|
||||
new_pos = (
|
||||
current_pos.x + offset_x,
|
||||
current_pos.y + offset_y,
|
||||
current_pos.z + offset_z
|
||||
)
|
||||
self.transform.setPos(*new_pos)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("移动脚本被销毁")
|
||||
28
111/scripts/TestRotator.py
Normal file
28
111/scripts/TestRotator.py
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
TestRotator - 自定义脚本
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class Testrotator(ScriptBase):
|
||||
"""自定义脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
# 在这里初始化您的变量
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("脚本开始运行!")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
# 在这里编写更新逻辑
|
||||
pass
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("脚本被销毁")
|
||||
28
111/scripts/TestScaler.py
Normal file
28
111/scripts/TestScaler.py
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
TestScaler - 自定义脚本
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class Testscaler(ScriptBase):
|
||||
"""自定义脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
# 在这里初始化您的变量
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("脚本开始运行!")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
# 在这里编写更新逻辑
|
||||
pass
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("脚本被销毁")
|
||||
28
111/scripts/a.py
Normal file
28
111/scripts/a.py
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
a - 自定义脚本
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class A(ScriptBase):
|
||||
"""自定义脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
# 在这里初始化您的变量
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("脚本开始运行!")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
# 在这里编写更新逻辑
|
||||
pass
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("脚本被销毁")
|
||||
47
111/scripts/example_script.py
Normal file
47
111/scripts/example_script.py
Normal file
@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
示例脚本 - 演示如何编写脚本
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class ExampleScript(ScriptBase):
|
||||
"""示例脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.counter = 0
|
||||
self.rotation_speed = 30.0 # 度/秒
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("示例脚本开始运行!")
|
||||
self.log(f"挂载到对象: {self.gameObject.getName()}")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
self.counter += 1
|
||||
|
||||
# 每60帧输出一次信息
|
||||
if self.counter % 60 == 0:
|
||||
self.log(f"运行了 {self.counter} 帧")
|
||||
|
||||
# 让对象旋转
|
||||
if self.transform:
|
||||
current_h = self.transform.getH()
|
||||
new_h = current_h + self.rotation_speed * dt
|
||||
self.transform.setH(new_h)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("示例脚本被销毁")
|
||||
|
||||
def on_enable(self):
|
||||
"""脚本启用时调用"""
|
||||
self.log("示例脚本被启用")
|
||||
|
||||
def on_disable(self):
|
||||
"""脚本禁用时调用"""
|
||||
self.log("示例脚本被禁用")
|
||||
28
111/scripts/test_quick_script.py
Normal file
28
111/scripts/test_quick_script.py
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
test_quick_script - 自定义脚本
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class TestQuickScript(ScriptBase):
|
||||
"""自定义脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
# 在这里初始化您的变量
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("脚本开始运行!")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
# 在这里编写更新逻辑
|
||||
pass
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("脚本被销毁")
|
||||
8
111/新项目/project.json
Normal file
8
111/新项目/project.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "新项目",
|
||||
"path": "D:\\IMGUI\\EG\\111\\新项目",
|
||||
"last_modified": "2026-03-18 12:12:50",
|
||||
"scene_file": "scenes\\scene.bam",
|
||||
"created_at": "2026-03-18 11:31:59",
|
||||
"version": "1.0"
|
||||
}
|
||||
BIN
111/新项目/scenes/scene.bam
Normal file
BIN
111/新项目/scenes/scene.bam
Normal file
Binary file not shown.
102
111/新项目/scripts/BouncerScript.py
Normal file
102
111/新项目/scripts/BouncerScript.py
Normal file
@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
跳跃脚本 - 让对象产生上下跳跃效果
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
import math
|
||||
|
||||
class BouncerScript(ScriptBase):
|
||||
"""跳跃脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# 跳跃参数
|
||||
self.jump_height = 2.0 # 跳跃高度
|
||||
self.jump_speed = 3.0 # 跳跃速度 (跳跃/秒)
|
||||
self.bounce_type = "sine" # 跳跃类型: "sine", "abs_sine", "square"
|
||||
|
||||
# 内部变量
|
||||
self.time_accumulator = 0.0 # 时间累积器
|
||||
self.original_y = None # 原始Y位置
|
||||
self.is_bouncing = True # 是否正在跳跃
|
||||
self.bounce_direction = 1 # 跳跃方向
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("跳跃脚本启动!")
|
||||
self.log(f"跳跃参数: 高度={self.jump_height}, 速度={self.jump_speed}, 类型={self.bounce_type}")
|
||||
|
||||
# 记录原始Y位置
|
||||
self.original_y = self.gameObject.getZ() # Z轴是高度
|
||||
self.log(f"原始高度: {self.original_y}")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_bouncing:
|
||||
return
|
||||
|
||||
# 累积时间
|
||||
self.time_accumulator += dt * self.bounce_direction
|
||||
|
||||
# 根据类型计算跳跃高度
|
||||
if self.bounce_type == "sine":
|
||||
# 标准正弦波跳跃
|
||||
height_offset = math.sin(self.time_accumulator * self.jump_speed * 2 * math.pi) * self.jump_height
|
||||
elif self.bounce_type == "abs_sine":
|
||||
# 绝对值正弦波(始终向上)
|
||||
height_offset = abs(math.sin(self.time_accumulator * self.jump_speed * 2 * math.pi)) * self.jump_height
|
||||
elif self.bounce_type == "square":
|
||||
# 方波跳跃(突然跳起落下)
|
||||
sine_val = math.sin(self.time_accumulator * self.jump_speed * 2 * math.pi)
|
||||
height_offset = self.jump_height if sine_val > 0 else 0
|
||||
else:
|
||||
height_offset = 0
|
||||
|
||||
# 应用跳跃
|
||||
current_pos = self.gameObject.getPos()
|
||||
new_z = self.original_y + height_offset
|
||||
self.gameObject.setPos(current_pos.getX(), current_pos.getY(), new_z)
|
||||
|
||||
def set_bounce_parameters(self, height=None, speed=None, bounce_type=None):
|
||||
"""设置跳跃参数"""
|
||||
if height is not None:
|
||||
self.jump_height = height
|
||||
if speed is not None:
|
||||
self.jump_speed = speed
|
||||
if bounce_type is not None and bounce_type in ["sine", "abs_sine", "square"]:
|
||||
self.bounce_type = bounce_type
|
||||
|
||||
self.log(f"跳跃参数更新: 高度={self.jump_height}, 速度={self.jump_speed}, 类型={self.bounce_type}")
|
||||
|
||||
def toggle_bouncing(self):
|
||||
"""切换跳跃状态"""
|
||||
self.is_bouncing = not self.is_bouncing
|
||||
status = "恢复" if self.is_bouncing else "暂停"
|
||||
self.log(f"跳跃{status}")
|
||||
|
||||
def reverse_direction(self):
|
||||
"""反转跳跃方向"""
|
||||
self.bounce_direction *= -1
|
||||
direction = "正向" if self.bounce_direction > 0 else "反向"
|
||||
self.log(f"跳跃方向改为{direction}")
|
||||
|
||||
def reset_position(self):
|
||||
"""重置到原始高度"""
|
||||
if self.original_y is not None:
|
||||
current_pos = self.gameObject.getPos()
|
||||
self.gameObject.setPos(current_pos.getX(), current_pos.getY(), self.original_y)
|
||||
self.time_accumulator = 0.0
|
||||
self.log("位置已重置到原始高度")
|
||||
|
||||
def jump_once(self):
|
||||
"""执行一次跳跃"""
|
||||
self.time_accumulator = 0.0
|
||||
self.log("执行单次跳跃")
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("跳跃脚本停止")
|
||||
160
111/新项目/scripts/ColorChangerScript.py
Normal file
160
111/新项目/scripts/ColorChangerScript.py
Normal file
@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
颜色变化脚本 - 让对象颜色产生循环变化
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
from panda3d.core import Vec4
|
||||
import math
|
||||
|
||||
class ColorChangerScript(ScriptBase):
|
||||
"""颜色变化脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# 颜色参数
|
||||
self.color_speed = 1.0 # 颜色变化速度 (周期/秒)
|
||||
self.color_mode = "rainbow" # 颜色模式: "rainbow", "pulse", "fade", "strobe"
|
||||
self.base_color = Vec4(1, 1, 1, 1) # 基础颜色
|
||||
self.intensity = 1.0 # 颜色强度
|
||||
|
||||
# 内部变量
|
||||
self.time_accumulator = 0.0 # 时间累积器
|
||||
self.original_color = None # 原始颜色
|
||||
self.is_changing = True # 是否正在变化
|
||||
self.strobe_state = False # 闪烁状态
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("颜色变化脚本启动!")
|
||||
self.log(f"颜色参数: 速度={self.color_speed}, 模式={self.color_mode}, 强度={self.intensity}")
|
||||
|
||||
# 记录原始颜色
|
||||
self.original_color = self.gameObject.getColor()
|
||||
self.log(f"原始颜色: {self.original_color}")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_changing:
|
||||
return
|
||||
|
||||
# 累积时间
|
||||
self.time_accumulator += dt
|
||||
|
||||
# 根据模式计算新颜色
|
||||
if self.color_mode == "rainbow":
|
||||
new_color = self._calculate_rainbow_color()
|
||||
elif self.color_mode == "pulse":
|
||||
new_color = self._calculate_pulse_color()
|
||||
elif self.color_mode == "fade":
|
||||
new_color = self._calculate_fade_color()
|
||||
elif self.color_mode == "strobe":
|
||||
new_color = self._calculate_strobe_color()
|
||||
else:
|
||||
new_color = self.base_color
|
||||
|
||||
# 应用颜色
|
||||
self.gameObject.setColor(new_color)
|
||||
|
||||
def _calculate_rainbow_color(self):
|
||||
"""计算彩虹颜色"""
|
||||
# 使用HSV到RGB的转换创建彩虹效果
|
||||
hue = (self.time_accumulator * self.color_speed) % 1.0
|
||||
|
||||
# 简单的HSV到RGB转换
|
||||
i = int(hue * 6.0)
|
||||
f = (hue * 6.0) - i
|
||||
p = 0.0
|
||||
q = 1.0 - f
|
||||
t = f
|
||||
|
||||
if i % 6 == 0:
|
||||
r, g, b = 1.0, t, p
|
||||
elif i % 6 == 1:
|
||||
r, g, b = q, 1.0, p
|
||||
elif i % 6 == 2:
|
||||
r, g, b = p, 1.0, t
|
||||
elif i % 6 == 3:
|
||||
r, g, b = p, q, 1.0
|
||||
elif i % 6 == 4:
|
||||
r, g, b = t, p, 1.0
|
||||
else:
|
||||
r, g, b = 1.0, p, q
|
||||
|
||||
return Vec4(r * self.intensity, g * self.intensity, b * self.intensity, 1.0)
|
||||
|
||||
def _calculate_pulse_color(self):
|
||||
"""计算脉冲颜色"""
|
||||
pulse = (math.sin(self.time_accumulator * self.color_speed * 2 * math.pi) + 1.0) / 2.0
|
||||
multiplier = pulse * self.intensity
|
||||
return Vec4(
|
||||
self.base_color.getX() * multiplier,
|
||||
self.base_color.getY() * multiplier,
|
||||
self.base_color.getZ() * multiplier,
|
||||
self.base_color.getW()
|
||||
)
|
||||
|
||||
def _calculate_fade_color(self):
|
||||
"""计算淡入淡出颜色"""
|
||||
fade = (math.sin(self.time_accumulator * self.color_speed * 2 * math.pi) + 1.0) / 2.0
|
||||
alpha = fade * self.intensity
|
||||
return Vec4(
|
||||
self.base_color.getX(),
|
||||
self.base_color.getY(),
|
||||
self.base_color.getZ(),
|
||||
alpha
|
||||
)
|
||||
|
||||
def _calculate_strobe_color(self):
|
||||
"""计算闪烁颜色"""
|
||||
# 根据时间间隔切换状态
|
||||
interval = 1.0 / (self.color_speed * 2) # 闪烁间隔
|
||||
if int(self.time_accumulator / interval) % 2 == 0:
|
||||
return Vec4(
|
||||
self.base_color.getX() * self.intensity,
|
||||
self.base_color.getY() * self.intensity,
|
||||
self.base_color.getZ() * self.intensity,
|
||||
self.base_color.getW()
|
||||
)
|
||||
else:
|
||||
return Vec4(0.1, 0.1, 0.1, self.base_color.getW()) # 暗色状态
|
||||
|
||||
def set_color_parameters(self, speed=None, mode=None, base_color=None, intensity=None):
|
||||
"""设置颜色参数"""
|
||||
if speed is not None:
|
||||
self.color_speed = speed
|
||||
if mode is not None and mode in ["rainbow", "pulse", "fade", "strobe"]:
|
||||
self.color_mode = mode
|
||||
if base_color is not None:
|
||||
self.base_color = base_color
|
||||
if intensity is not None:
|
||||
self.intensity = intensity
|
||||
|
||||
self.log(f"颜色参数更新: 速度={self.color_speed}, 模式={self.color_mode}, 强度={self.intensity}")
|
||||
|
||||
def toggle_color_change(self):
|
||||
"""切换颜色变化状态"""
|
||||
self.is_changing = not self.is_changing
|
||||
status = "恢复" if self.is_changing else "暂停"
|
||||
self.log(f"颜色变化{status}")
|
||||
|
||||
def reset_color(self):
|
||||
"""重置到原始颜色"""
|
||||
if self.original_color:
|
||||
self.gameObject.setColor(self.original_color)
|
||||
self.time_accumulator = 0.0
|
||||
self.log("颜色已重置到原始值")
|
||||
|
||||
def set_solid_color(self, r=1.0, g=1.0, b=1.0, a=1.0):
|
||||
"""设置固定颜色"""
|
||||
color = Vec4(r, g, b, a)
|
||||
self.gameObject.setColor(color)
|
||||
self.base_color = color
|
||||
self.log(f"设置固定颜色: {color}")
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("颜色变化脚本停止")
|
||||
39
111/新项目/scripts/ComboAnimatorScript.py
Normal file
39
111/新项目/scripts/ComboAnimatorScript.py
Normal file
@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
复合动画脚本 - 结合旋转和跳跃效果
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
import math
|
||||
|
||||
class ComboAnimatorScript(ScriptBase):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.time = 0.0
|
||||
self.original_pos = None
|
||||
self.is_active = True
|
||||
|
||||
def start(self):
|
||||
self.log("复合动画脚本启动!")
|
||||
self.original_pos = self.gameObject.getPos()
|
||||
|
||||
def update(self, dt):
|
||||
if not self.is_active:
|
||||
return
|
||||
|
||||
self.time += dt
|
||||
|
||||
# 旋转效果
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
new_h = current_hpr.getX() + 45.0 * dt
|
||||
self.gameObject.setHpr(new_h, current_hpr.getY(), current_hpr.getZ())
|
||||
|
||||
# 跳跃效果
|
||||
if self.original_pos:
|
||||
bounce_offset = abs(math.sin(self.time * 3.0)) * 1.0
|
||||
self.gameObject.setZ(self.original_pos.getZ() + bounce_offset)
|
||||
|
||||
def on_destroy(self):
|
||||
self.log("复合动画脚本停止")
|
||||
69
111/新项目/scripts/FollowerScript.py
Normal file
69
111/新项目/scripts/FollowerScript.py
Normal file
@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
跟随脚本 - 让对象跟随指定的目标对象
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
from panda3d.core import Vec3
|
||||
|
||||
class FollowerScript(ScriptBase):
|
||||
"""跟随脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.target = None # 跟随目标
|
||||
self.follow_speed = 5.0 # 跟随速度
|
||||
self.follow_distance = 2.0 # 跟随距离
|
||||
self.is_following = True # 是否正在跟随
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("跟随脚本启动!")
|
||||
self.log(f"跟随参数: 速度={self.follow_speed}, 距离={self.follow_distance}")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_following or self.target is None:
|
||||
return
|
||||
|
||||
target_pos = self.target.getPos()
|
||||
current_pos = self.gameObject.getPos()
|
||||
|
||||
# 计算目标方向
|
||||
direction = target_pos - current_pos
|
||||
distance = direction.length()
|
||||
|
||||
# 如果距离大于跟随距离,则移动
|
||||
if distance > self.follow_distance:
|
||||
if distance > 0:
|
||||
direction.normalize()
|
||||
|
||||
# 计算目标位置(保持跟随距离)
|
||||
target_follow_pos = target_pos - direction * self.follow_distance
|
||||
|
||||
# 平滑移动到目标位置
|
||||
move_direction = target_follow_pos - current_pos
|
||||
move_distance = move_direction.length()
|
||||
|
||||
if move_distance > 0:
|
||||
move_direction.normalize()
|
||||
move_amount = min(self.follow_speed * dt, move_distance)
|
||||
new_pos = current_pos + move_direction * move_amount
|
||||
self.gameObject.setPos(new_pos)
|
||||
|
||||
# 朝向目标
|
||||
self.gameObject.lookAt(target_pos)
|
||||
|
||||
def set_target(self, target):
|
||||
"""设置跟随目标"""
|
||||
self.target = target
|
||||
if target:
|
||||
self.log(f"设置跟随目标: {target.getName()}")
|
||||
else:
|
||||
self.log("清除跟随目标")
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("跟随脚本停止")
|
||||
91
111/新项目/scripts/MoverScript.py
Normal file
91
111/新项目/scripts/MoverScript.py
Normal file
@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
移动脚本 - 让对象在指定方向上来回移动
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
import math
|
||||
|
||||
class MoverScript(ScriptBase):
|
||||
"""移动脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# 移动参数
|
||||
self.move_distance = 5.0 # 移动距离
|
||||
self.move_speed = 2.0 # 移动速度 (单位/秒)
|
||||
self.move_axis = "x" # 移动轴: "x", "y", "z"
|
||||
|
||||
# 内部变量
|
||||
self.start_position = None # 起始位置
|
||||
self.current_direction = 1 # 当前移动方向: 1或-1
|
||||
self.current_distance = 0.0 # 当前移动距离
|
||||
self.is_moving = True # 是否正在移动
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("移动脚本启动!")
|
||||
self.log(f"移动参数: 距离={self.move_distance}, 速度={self.move_speed}, 轴={self.move_axis}")
|
||||
|
||||
# 记录起始位置
|
||||
self.start_position = self.gameObject.getPos()
|
||||
self.log(f"起始位置: {self.start_position}")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_moving or self.start_position is None:
|
||||
return
|
||||
|
||||
# 计算移动增量
|
||||
move_delta = self.move_speed * dt * self.current_direction
|
||||
self.current_distance += abs(move_delta)
|
||||
|
||||
# 检查是否需要改变方向
|
||||
if self.current_distance >= self.move_distance:
|
||||
self.current_direction *= -1
|
||||
self.current_distance = 0.0
|
||||
|
||||
# 应用移动
|
||||
current_pos = self.gameObject.getPos()
|
||||
new_pos = [current_pos.getX(), current_pos.getY(), current_pos.getZ()]
|
||||
|
||||
if self.move_axis == "x":
|
||||
new_pos[0] += move_delta
|
||||
elif self.move_axis == "y":
|
||||
new_pos[1] += move_delta
|
||||
elif self.move_axis == "z":
|
||||
new_pos[2] += move_delta
|
||||
|
||||
self.gameObject.setPos(new_pos[0], new_pos[1], new_pos[2])
|
||||
|
||||
def set_move_parameters(self, distance=None, speed=None, axis=None):
|
||||
"""设置移动参数"""
|
||||
if distance is not None:
|
||||
self.move_distance = distance
|
||||
if speed is not None:
|
||||
self.move_speed = speed
|
||||
if axis is not None and axis in ["x", "y", "z"]:
|
||||
self.move_axis = axis
|
||||
|
||||
self.log(f"移动参数更新: 距离={self.move_distance}, 速度={self.move_speed}, 轴={self.move_axis}")
|
||||
|
||||
def toggle_movement(self):
|
||||
"""切换移动状态"""
|
||||
self.is_moving = not self.is_moving
|
||||
status = "恢复" if self.is_moving else "暂停"
|
||||
self.log(f"移动{status}")
|
||||
|
||||
def reset_position(self):
|
||||
"""重置到起始位置"""
|
||||
if self.start_position:
|
||||
self.gameObject.setPos(self.start_position)
|
||||
self.current_distance = 0.0
|
||||
self.current_direction = 1
|
||||
self.log("位置已重置到起始点")
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("移动脚本停止")
|
||||
133
111/新项目/scripts/R_P.py
Normal file
133
111/新项目/scripts/R_P.py
Normal file
@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
旋转脚本 - 让对象持续旋转
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
|
||||
class RotatorScript(ScriptBase):
|
||||
"""旋转脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.rotation_speed_y = 30.0 # Y轴旋转速度 (度/秒)
|
||||
self.max_angle = 30.0 # 最大旋转角度(相对于初始角度)
|
||||
self.direction = 1
|
||||
self.current_offset = 0.0 # 当前相对于初始角度的偏移
|
||||
self.initial_angle = None # 模型的初始角度
|
||||
self.is_rotating = True # 是否正在旋转
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("旋转脚本启动!")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"最大旋转角度: ±{self.max_angle}度")
|
||||
|
||||
# 记录模型的初始角度
|
||||
if self.gameObject:
|
||||
initial_hpr = self.gameObject.getHpr()
|
||||
self.initial_angle = initial_hpr.getZ() # 记录Z轴的初始角度
|
||||
self.log(f"模型初始角度: {self.initial_angle}度")
|
||||
self.log(f"旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
else:
|
||||
self.log("⚠️ 无法获取游戏对象,使用默认初始角度0")
|
||||
self.initial_angle = 0.0
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_rotating or self.initial_angle is None:
|
||||
return
|
||||
|
||||
# 计算角度变化量
|
||||
delta_angle = self.rotation_speed_y * dt * self.direction
|
||||
self.current_offset += delta_angle
|
||||
|
||||
# 如果超出角度范围,则反向并限制在边界
|
||||
if self.current_offset > self.max_angle:
|
||||
self.current_offset = self.max_angle
|
||||
self.direction *= -1
|
||||
elif self.current_offset < -self.max_angle:
|
||||
self.current_offset = -self.max_angle
|
||||
self.direction *= -1
|
||||
|
||||
# 计算最终角度(初始角度 + 偏移量)
|
||||
final_angle = self.initial_angle + self.current_offset
|
||||
|
||||
# 设置新的旋转(只改变Z轴,保持其他不变)
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), final_angle, current_hpr.getZ())
|
||||
|
||||
# if not self.is_rotating:
|
||||
# return
|
||||
#
|
||||
# # 获取当前旋转并应用增量
|
||||
# current_hpr = self.gameObject.getHpr()
|
||||
# new_r = current_hpr.getZ() + self.rotation_speed_y * dt
|
||||
# self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), new_r)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("旋转脚本停止")
|
||||
|
||||
# ==================== 控制方法 ====================
|
||||
|
||||
def set_max_angle(self, new_max_angle):
|
||||
"""
|
||||
设置新的最大旋转角度
|
||||
|
||||
Args:
|
||||
new_max_angle: 新的最大角度值
|
||||
"""
|
||||
self.max_angle = new_max_angle
|
||||
self.log(f"最大旋转角度已设置为: ±{self.max_angle}度")
|
||||
if self.initial_angle is not None:
|
||||
self.log(f"新的旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
|
||||
def set_rotation_speed(self, new_speed):
|
||||
"""
|
||||
设置新的旋转速度
|
||||
|
||||
Args:
|
||||
new_speed: 新的旋转速度(度/秒)
|
||||
"""
|
||||
self.rotation_speed_y = new_speed
|
||||
self.log(f"旋转速度已设置为: {self.rotation_speed_y}度/秒")
|
||||
|
||||
def pause_rotation(self):
|
||||
"""暂停旋转"""
|
||||
self.is_rotating = False
|
||||
self.log("旋转已暂停")
|
||||
|
||||
def resume_rotation(self):
|
||||
"""恢复旋转"""
|
||||
self.is_rotating = True
|
||||
self.log("旋转已恢复")
|
||||
|
||||
def reset_to_initial_angle(self):
|
||||
"""重置到初始角度"""
|
||||
if self.initial_angle is not None and self.gameObject:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), self.initial_angle)
|
||||
self.current_offset = 0.0
|
||||
self.direction = 1
|
||||
self.log(f"已重置到初始角度: {self.initial_angle}度")
|
||||
|
||||
def get_current_info(self):
|
||||
"""获取当前旋转信息"""
|
||||
if self.gameObject and self.initial_angle is not None:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
current_angle = current_hpr.getZ()
|
||||
self.log("=== 当前旋转信息 ===")
|
||||
self.log(f"初始角度: {self.initial_angle}度")
|
||||
self.log(f"当前角度: {current_angle}度")
|
||||
self.log(f"偏移量: {self.current_offset}度")
|
||||
self.log(f"最大角度: ±{self.max_angle}度")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"旋转方向: {'正向' if self.direction > 0 else '反向'}")
|
||||
self.log(f"旋转状态: {'运行中' if self.is_rotating else '已暂停'}")
|
||||
self.log("=== 信息结束 ===")
|
||||
else:
|
||||
self.log("无法获取旋转信息")
|
||||
133
111/新项目/scripts/R_R.py
Normal file
133
111/新项目/scripts/R_R.py
Normal file
@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
旋转脚本 - 让对象持续旋转
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
|
||||
class RotatorScript(ScriptBase):
|
||||
"""旋转脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.rotation_speed_y = 30.0 # Y轴旋转速度 (度/秒)
|
||||
self.max_angle = 30.0 # 最大旋转角度(相对于初始角度)
|
||||
self.direction = 1
|
||||
self.current_offset = 0.0 # 当前相对于初始角度的偏移
|
||||
self.initial_angle = None # 模型的初始角度
|
||||
self.is_rotating = True # 是否正在旋转
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("旋转脚本启动!")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"最大旋转角度: ±{self.max_angle}度")
|
||||
|
||||
# 记录模型的初始角度
|
||||
if self.gameObject:
|
||||
initial_hpr = self.gameObject.getHpr()
|
||||
self.initial_angle = initial_hpr.getZ() # 记录Z轴的初始角度
|
||||
self.log(f"模型初始角度: {self.initial_angle}度")
|
||||
self.log(f"旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
else:
|
||||
self.log("⚠️ 无法获取游戏对象,使用默认初始角度0")
|
||||
self.initial_angle = 0.0
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_rotating or self.initial_angle is None:
|
||||
return
|
||||
|
||||
# 计算角度变化量
|
||||
delta_angle = self.rotation_speed_y * dt * self.direction
|
||||
self.current_offset += delta_angle
|
||||
|
||||
# 如果超出角度范围,则反向并限制在边界
|
||||
if self.current_offset > self.max_angle:
|
||||
self.current_offset = self.max_angle
|
||||
self.direction *= -1
|
||||
elif self.current_offset < -self.max_angle:
|
||||
self.current_offset = -self.max_angle
|
||||
self.direction *= -1
|
||||
|
||||
# 计算最终角度(初始角度 + 偏移量)
|
||||
final_angle = self.initial_angle + self.current_offset
|
||||
|
||||
# 设置新的旋转(只改变Z轴,保持其他不变)
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), final_angle)
|
||||
|
||||
# if not self.is_rotating:
|
||||
# return
|
||||
#
|
||||
# # 获取当前旋转并应用增量
|
||||
# current_hpr = self.gameObject.getHpr()
|
||||
# new_r = current_hpr.getZ() + self.rotation_speed_y * dt
|
||||
# self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), new_r)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("旋转脚本停止")
|
||||
|
||||
# ==================== 控制方法 ====================
|
||||
|
||||
def set_max_angle(self, new_max_angle):
|
||||
"""
|
||||
设置新的最大旋转角度
|
||||
|
||||
Args:
|
||||
new_max_angle: 新的最大角度值
|
||||
"""
|
||||
self.max_angle = new_max_angle
|
||||
self.log(f"最大旋转角度已设置为: ±{self.max_angle}度")
|
||||
if self.initial_angle is not None:
|
||||
self.log(f"新的旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
|
||||
def set_rotation_speed(self, new_speed):
|
||||
"""
|
||||
设置新的旋转速度
|
||||
|
||||
Args:
|
||||
new_speed: 新的旋转速度(度/秒)
|
||||
"""
|
||||
self.rotation_speed_y = new_speed
|
||||
self.log(f"旋转速度已设置为: {self.rotation_speed_y}度/秒")
|
||||
|
||||
def pause_rotation(self):
|
||||
"""暂停旋转"""
|
||||
self.is_rotating = False
|
||||
self.log("旋转已暂停")
|
||||
|
||||
def resume_rotation(self):
|
||||
"""恢复旋转"""
|
||||
self.is_rotating = True
|
||||
self.log("旋转已恢复")
|
||||
|
||||
def reset_to_initial_angle(self):
|
||||
"""重置到初始角度"""
|
||||
if self.initial_angle is not None and self.gameObject:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), self.initial_angle)
|
||||
self.current_offset = 0.0
|
||||
self.direction = 1
|
||||
self.log(f"已重置到初始角度: {self.initial_angle}度")
|
||||
|
||||
def get_current_info(self):
|
||||
"""获取当前旋转信息"""
|
||||
if self.gameObject and self.initial_angle is not None:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
current_angle = current_hpr.getZ()
|
||||
self.log("=== 当前旋转信息 ===")
|
||||
self.log(f"初始角度: {self.initial_angle}度")
|
||||
self.log(f"当前角度: {current_angle}度")
|
||||
self.log(f"偏移量: {self.current_offset}度")
|
||||
self.log(f"最大角度: ±{self.max_angle}度")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"旋转方向: {'正向' if self.direction > 0 else '反向'}")
|
||||
self.log(f"旋转状态: {'运行中' if self.is_rotating else '已暂停'}")
|
||||
self.log("=== 信息结束 ===")
|
||||
else:
|
||||
self.log("无法获取旋转信息")
|
||||
215
111/新项目/scripts/Rotate_H_Script.py
Normal file
215
111/新项目/scripts/Rotate_H_Script.py
Normal file
@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
旋转脚本 - 让对象持续旋转
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
|
||||
class RotatorScript(ScriptBase):
|
||||
"""旋转脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.rotation_speed_y = 30.0 # Y轴旋转速度 (度/秒)
|
||||
self.max_angle = 30.0 # 最大旋转角度(相对于初始角度)
|
||||
self.direction = 1
|
||||
self.current_offset = 0.0 # 当前相对于初始角度的偏移
|
||||
self.initial_angle = None # 模型的初始角度
|
||||
self.is_rotating = True # 是否正在旋转
|
||||
|
||||
# 机器人式停顿参数
|
||||
self.pause_duration = 0.5 # 停顿时间(秒)
|
||||
self.current_pause_time = 0.0 # 当前停顿计时
|
||||
self.is_paused = False # 是否正在停顿
|
||||
self.robot_mode = True # 是否启用机器人模式
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("机器人旋转脚本启动!")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"最大旋转角度: ±{self.max_angle}度")
|
||||
self.log(f"机器人模式: {'开启' if self.robot_mode else '关闭'}")
|
||||
if self.robot_mode:
|
||||
self.log(f"停顿时间: {self.pause_duration}秒")
|
||||
|
||||
# 记录模型的初始角度
|
||||
if self.gameObject:
|
||||
initial_hpr = self.gameObject.getHpr()
|
||||
self.initial_angle = initial_hpr.getY() # 记录Y轴的初始角度(Pitch)
|
||||
self.log(f"模型初始角度: {self.initial_angle}度")
|
||||
self.log(f"旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
else:
|
||||
self.log("⚠️ 无法获取游戏对象,使用默认初始角度0")
|
||||
self.initial_angle = 0.0
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新 - 机器人式旋转"""
|
||||
if not self.is_rotating or self.initial_angle is None:
|
||||
return
|
||||
|
||||
# 如果正在停顿中
|
||||
if self.is_paused:
|
||||
self.current_pause_time += dt
|
||||
if self.current_pause_time >= self.pause_duration:
|
||||
# 停顿结束,继续旋转
|
||||
self.is_paused = False
|
||||
self.current_pause_time = 0.0
|
||||
self.log(f"停顿结束,继续旋转,方向: {'正向' if self.direction > 0 else '反向'}")
|
||||
return
|
||||
|
||||
# 计算角度变化量
|
||||
delta_angle = self.rotation_speed_y * dt * self.direction
|
||||
self.current_offset += delta_angle
|
||||
|
||||
# 检查是否到达边界
|
||||
reached_boundary = False
|
||||
if self.current_offset > self.max_angle:
|
||||
self.current_offset = self.max_angle
|
||||
self.direction *= -1
|
||||
reached_boundary = True
|
||||
elif self.current_offset < -self.max_angle:
|
||||
self.current_offset = -self.max_angle
|
||||
self.direction *= -1
|
||||
reached_boundary = True
|
||||
|
||||
# 如果到达边界且启用机器人模式,开始停顿
|
||||
if reached_boundary and self.robot_mode:
|
||||
self.is_paused = True
|
||||
self.current_pause_time = 0.0
|
||||
self.log(f"到达边界 ({self.current_offset}°),开始停顿 {self.pause_duration}秒")
|
||||
|
||||
# 计算最终角度(初始角度 + 偏移量)
|
||||
final_angle = self.initial_angle + self.current_offset
|
||||
|
||||
# 设置新的旋转(只改变Y轴,保持其他不变)
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(final_angle, current_hpr.getY(), current_hpr.getZ())
|
||||
|
||||
# if not self.is_rotating:
|
||||
# return
|
||||
#
|
||||
# # 获取当前旋转并应用增量
|
||||
# current_hpr = self.gameObject.getHpr()
|
||||
# new_r = current_hpr.getZ() + self.rotation_speed_y * dt
|
||||
# self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), new_r)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("机器人旋转脚本停止")
|
||||
|
||||
# ==================== 机器人模式控制方法 ====================
|
||||
|
||||
def set_robot_mode(self, enabled=True):
|
||||
"""
|
||||
启用或禁用机器人模式
|
||||
|
||||
Args:
|
||||
enabled: 是否启用机器人模式
|
||||
"""
|
||||
self.robot_mode = enabled
|
||||
self.log(f"机器人模式: {'开启' if enabled else '关闭'}")
|
||||
if not enabled:
|
||||
self.is_paused = False # 如果禁用机器人模式,立即结束停顿
|
||||
|
||||
def set_pause_duration(self, duration):
|
||||
"""
|
||||
设置停顿时间
|
||||
|
||||
Args:
|
||||
duration: 停顿时间(秒)
|
||||
"""
|
||||
self.pause_duration = max(0.1, duration) # 最小0.1秒
|
||||
self.log(f"停顿时间已设置为: {self.pause_duration}秒")
|
||||
|
||||
def set_max_angle(self, new_max_angle):
|
||||
"""
|
||||
设置新的最大旋转角度
|
||||
|
||||
Args:
|
||||
new_max_angle: 新的最大角度值
|
||||
"""
|
||||
self.max_angle = new_max_angle
|
||||
self.log(f"最大旋转角度已设置为: ±{self.max_angle}度")
|
||||
if self.initial_angle is not None:
|
||||
self.log(f"新的旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
|
||||
def set_rotation_speed(self, new_speed):
|
||||
"""
|
||||
设置新的旋转速度
|
||||
|
||||
Args:
|
||||
new_speed: 新的旋转速度(度/秒)
|
||||
"""
|
||||
self.rotation_speed_y = new_speed
|
||||
self.log(f"旋转速度已设置为: {self.rotation_speed_y}度/秒")
|
||||
|
||||
def pause_rotation(self):
|
||||
"""暂停旋转"""
|
||||
self.is_rotating = False
|
||||
self.log("旋转已暂停")
|
||||
|
||||
def resume_rotation(self):
|
||||
"""恢复旋转"""
|
||||
self.is_rotating = True
|
||||
self.is_paused = False # 同时结束停顿状态
|
||||
self.log("旋转已恢复")
|
||||
|
||||
def reset_to_initial_angle(self):
|
||||
"""重置到初始角度"""
|
||||
if self.initial_angle is not None and self.gameObject:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), self.initial_angle, current_hpr.getZ())
|
||||
self.current_offset = 0.0
|
||||
self.direction = 1
|
||||
self.is_paused = False
|
||||
self.current_pause_time = 0.0
|
||||
self.log(f"已重置到初始角度: {self.initial_angle}度")
|
||||
|
||||
def get_current_info(self):
|
||||
"""获取当前旋转信息"""
|
||||
if self.gameObject and self.initial_angle is not None:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
current_angle = current_hpr.getY()
|
||||
self.log("=== 机器人旋转信息 ===")
|
||||
self.log(f"初始角度: {self.initial_angle}度")
|
||||
self.log(f"当前角度: {current_angle}度")
|
||||
self.log(f"偏移量: {self.current_offset}度")
|
||||
self.log(f"最大角度: ±{self.max_angle}度")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"旋转方向: {'正向' if self.direction > 0 else '反向'}")
|
||||
self.log(f"旋转状态: {'运行中' if self.is_rotating else '已暂停'}")
|
||||
self.log(f"机器人模式: {'开启' if self.robot_mode else '关闭'}")
|
||||
if self.robot_mode:
|
||||
self.log(f"停顿时间: {self.pause_duration}秒")
|
||||
self.log(f"当前状态: {'停顿中' if self.is_paused else '旋转中'}")
|
||||
if self.is_paused:
|
||||
remaining_time = self.pause_duration - self.current_pause_time
|
||||
self.log(f"剩余停顿时间: {remaining_time:.1f}秒")
|
||||
self.log("=== 信息结束 ===")
|
||||
else:
|
||||
self.log("无法获取旋转信息")
|
||||
|
||||
# ==================== 预设配置方法 ====================
|
||||
|
||||
def set_slow_robot_mode(self):
|
||||
"""预设:慢速机器人模式"""
|
||||
self.set_rotation_speed(15.0)
|
||||
self.set_pause_duration(1.0)
|
||||
self.set_robot_mode(True)
|
||||
self.log("已设置为慢速机器人模式")
|
||||
|
||||
def set_fast_robot_mode(self):
|
||||
"""预设:快速机器人模式"""
|
||||
self.set_rotation_speed(45.0)
|
||||
self.set_pause_duration(0.3)
|
||||
self.set_robot_mode(True)
|
||||
self.log("已设置为快速机器人模式")
|
||||
|
||||
def set_smooth_mode(self):
|
||||
"""预设:平滑模式(非机器人)"""
|
||||
self.set_robot_mode(False)
|
||||
self.set_rotation_speed(30.0)
|
||||
self.log("已设置为平滑旋转模式")
|
||||
215
111/新项目/scripts/Rotate_P_Script.py
Normal file
215
111/新项目/scripts/Rotate_P_Script.py
Normal file
@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
旋转脚本 - 让对象持续旋转
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
|
||||
class RotatorScript(ScriptBase):
|
||||
"""旋转脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.rotation_speed_y = 30.0 # Y轴旋转速度 (度/秒)
|
||||
self.max_angle = 25.0 # 最大旋转角度(相对于初始角度)
|
||||
self.direction = 1
|
||||
self.current_offset = 0.0 # 当前相对于初始角度的偏移
|
||||
self.initial_angle = None # 模型的初始角度
|
||||
self.is_rotating = True # 是否正在旋转
|
||||
|
||||
# 机器人式停顿参数
|
||||
self.pause_duration = 0.5 # 停顿时间(秒)
|
||||
self.current_pause_time = 0.0 # 当前停顿计时
|
||||
self.is_paused = False # 是否正在停顿
|
||||
self.robot_mode = True # 是否启用机器人模式
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("机器人旋转脚本启动!")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"最大旋转角度: ±{self.max_angle}度")
|
||||
self.log(f"机器人模式: {'开启' if self.robot_mode else '关闭'}")
|
||||
if self.robot_mode:
|
||||
self.log(f"停顿时间: {self.pause_duration}秒")
|
||||
|
||||
# 记录模型的初始角度
|
||||
if self.gameObject:
|
||||
initial_hpr = self.gameObject.getHpr()
|
||||
self.initial_angle = initial_hpr.getY() # 记录Y轴的初始角度(Pitch)
|
||||
self.log(f"模型初始角度: {self.initial_angle}度")
|
||||
self.log(f"旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
else:
|
||||
self.log("⚠️ 无法获取游戏对象,使用默认初始角度0")
|
||||
self.initial_angle = 0.0
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新 - 机器人式旋转"""
|
||||
if not self.is_rotating or self.initial_angle is None:
|
||||
return
|
||||
|
||||
# 如果正在停顿中
|
||||
if self.is_paused:
|
||||
self.current_pause_time += dt
|
||||
if self.current_pause_time >= self.pause_duration:
|
||||
# 停顿结束,继续旋转
|
||||
self.is_paused = False
|
||||
self.current_pause_time = 0.0
|
||||
self.log(f"停顿结束,继续旋转,方向: {'正向' if self.direction > 0 else '反向'}")
|
||||
return
|
||||
|
||||
# 计算角度变化量
|
||||
delta_angle = self.rotation_speed_y * dt * self.direction
|
||||
self.current_offset += delta_angle
|
||||
|
||||
# 检查是否到达边界
|
||||
reached_boundary = False
|
||||
if self.current_offset > self.max_angle:
|
||||
self.current_offset = self.max_angle
|
||||
self.direction *= -1
|
||||
reached_boundary = True
|
||||
elif self.current_offset < -self.max_angle:
|
||||
self.current_offset = -self.max_angle
|
||||
self.direction *= -1
|
||||
reached_boundary = True
|
||||
|
||||
# 如果到达边界且启用机器人模式,开始停顿
|
||||
if reached_boundary and self.robot_mode:
|
||||
self.is_paused = True
|
||||
self.current_pause_time = 0.0
|
||||
self.log(f"到达边界 ({self.current_offset}°),开始停顿 {self.pause_duration}秒")
|
||||
|
||||
# 计算最终角度(初始角度 + 偏移量)
|
||||
final_angle = self.initial_angle + self.current_offset
|
||||
|
||||
# 设置新的旋转(只改变Y轴,保持其他不变)
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), final_angle, current_hpr.getZ())
|
||||
|
||||
# if not self.is_rotating:
|
||||
# return
|
||||
#
|
||||
# # 获取当前旋转并应用增量
|
||||
# current_hpr = self.gameObject.getHpr()
|
||||
# new_r = current_hpr.getZ() + self.rotation_speed_y * dt
|
||||
# self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), new_r)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("机器人旋转脚本停止")
|
||||
|
||||
# ==================== 机器人模式控制方法 ====================
|
||||
|
||||
def set_robot_mode(self, enabled=True):
|
||||
"""
|
||||
启用或禁用机器人模式
|
||||
|
||||
Args:
|
||||
enabled: 是否启用机器人模式
|
||||
"""
|
||||
self.robot_mode = enabled
|
||||
self.log(f"机器人模式: {'开启' if enabled else '关闭'}")
|
||||
if not enabled:
|
||||
self.is_paused = False # 如果禁用机器人模式,立即结束停顿
|
||||
|
||||
def set_pause_duration(self, duration):
|
||||
"""
|
||||
设置停顿时间
|
||||
|
||||
Args:
|
||||
duration: 停顿时间(秒)
|
||||
"""
|
||||
self.pause_duration = max(0.1, duration) # 最小0.1秒
|
||||
self.log(f"停顿时间已设置为: {self.pause_duration}秒")
|
||||
|
||||
def set_max_angle(self, new_max_angle):
|
||||
"""
|
||||
设置新的最大旋转角度
|
||||
|
||||
Args:
|
||||
new_max_angle: 新的最大角度值
|
||||
"""
|
||||
self.max_angle = new_max_angle
|
||||
self.log(f"最大旋转角度已设置为: ±{self.max_angle}度")
|
||||
if self.initial_angle is not None:
|
||||
self.log(f"新的旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
|
||||
def set_rotation_speed(self, new_speed):
|
||||
"""
|
||||
设置新的旋转速度
|
||||
|
||||
Args:
|
||||
new_speed: 新的旋转速度(度/秒)
|
||||
"""
|
||||
self.rotation_speed_y = new_speed
|
||||
self.log(f"旋转速度已设置为: {self.rotation_speed_y}度/秒")
|
||||
|
||||
def pause_rotation(self):
|
||||
"""暂停旋转"""
|
||||
self.is_rotating = False
|
||||
self.log("旋转已暂停")
|
||||
|
||||
def resume_rotation(self):
|
||||
"""恢复旋转"""
|
||||
self.is_rotating = True
|
||||
self.is_paused = False # 同时结束停顿状态
|
||||
self.log("旋转已恢复")
|
||||
|
||||
def reset_to_initial_angle(self):
|
||||
"""重置到初始角度"""
|
||||
if self.initial_angle is not None and self.gameObject:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), self.initial_angle, current_hpr.getZ())
|
||||
self.current_offset = 0.0
|
||||
self.direction = 1
|
||||
self.is_paused = False
|
||||
self.current_pause_time = 0.0
|
||||
self.log(f"已重置到初始角度: {self.initial_angle}度")
|
||||
|
||||
def get_current_info(self):
|
||||
"""获取当前旋转信息"""
|
||||
if self.gameObject and self.initial_angle is not None:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
current_angle = current_hpr.getY()
|
||||
self.log("=== 机器人旋转信息 ===")
|
||||
self.log(f"初始角度: {self.initial_angle}度")
|
||||
self.log(f"当前角度: {current_angle}度")
|
||||
self.log(f"偏移量: {self.current_offset}度")
|
||||
self.log(f"最大角度: ±{self.max_angle}度")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"旋转方向: {'正向' if self.direction > 0 else '反向'}")
|
||||
self.log(f"旋转状态: {'运行中' if self.is_rotating else '已暂停'}")
|
||||
self.log(f"机器人模式: {'开启' if self.robot_mode else '关闭'}")
|
||||
if self.robot_mode:
|
||||
self.log(f"停顿时间: {self.pause_duration}秒")
|
||||
self.log(f"当前状态: {'停顿中' if self.is_paused else '旋转中'}")
|
||||
if self.is_paused:
|
||||
remaining_time = self.pause_duration - self.current_pause_time
|
||||
self.log(f"剩余停顿时间: {remaining_time:.1f}秒")
|
||||
self.log("=== 信息结束 ===")
|
||||
else:
|
||||
self.log("无法获取旋转信息")
|
||||
|
||||
# ==================== 预设配置方法 ====================
|
||||
|
||||
def set_slow_robot_mode(self):
|
||||
"""预设:慢速机器人模式"""
|
||||
self.set_rotation_speed(15.0)
|
||||
self.set_pause_duration(1.0)
|
||||
self.set_robot_mode(True)
|
||||
self.log("已设置为慢速机器人模式")
|
||||
|
||||
def set_fast_robot_mode(self):
|
||||
"""预设:快速机器人模式"""
|
||||
self.set_rotation_speed(45.0)
|
||||
self.set_pause_duration(0.3)
|
||||
self.set_robot_mode(True)
|
||||
self.log("已设置为快速机器人模式")
|
||||
|
||||
def set_smooth_mode(self):
|
||||
"""预设:平滑模式(非机器人)"""
|
||||
self.set_robot_mode(False)
|
||||
self.set_rotation_speed(30.0)
|
||||
self.log("已设置为平滑旋转模式")
|
||||
56
111/新项目/scripts/Rotate_R_Script.py
Normal file
56
111/新项目/scripts/Rotate_R_Script.py
Normal file
@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
旋转脚本 - 让对象持续旋转
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
|
||||
class RotatorScript(ScriptBase):
|
||||
"""旋转脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.rotation_speed_y = 30.0 # Y轴旋转速度 (度/秒)
|
||||
self.max_angle = 15.0
|
||||
self.direction = 1
|
||||
self.current_angle = 0.0
|
||||
self.is_rotating = True # 是否正在旋转
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("旋转脚本启动!")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
|
||||
delta_angle = self.rotation_speed_y * dt * self.direction
|
||||
self.current_angle += delta_angle
|
||||
|
||||
# 如果超出角度范围,则反向
|
||||
if self.current_angle > self.max_angle:
|
||||
self.current_angle = self.max_angle
|
||||
self.direction *= -1
|
||||
elif self.current_angle < -self.max_angle:
|
||||
self.current_angle = -self.max_angle
|
||||
self.direction *= -1
|
||||
|
||||
# 设置新的旋转(只改变Z轴,保持其他不变)
|
||||
base_hpr = self.gameObject.getHpr()
|
||||
new_r = self.current_angle
|
||||
self.gameObject.setHpr(base_hpr.getX(), base_hpr.getY(), new_r)
|
||||
|
||||
# if not self.is_rotating:
|
||||
# return
|
||||
#
|
||||
# # 获取当前旋转并应用增量
|
||||
# current_hpr = self.gameObject.getHpr()
|
||||
# new_r = current_hpr.getZ() + self.rotation_speed_y * dt
|
||||
# self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), new_r)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("旋转脚本停止")
|
||||
39
111/新项目/scripts/RotatorScript.py
Normal file
39
111/新项目/scripts/RotatorScript.py
Normal file
@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
旋转脚本 - 让对象持续旋转
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class RotatorScript(ScriptBase):
|
||||
"""旋转脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.rotation_speed_y = 30.0 # Y轴旋转速度 (度/秒)
|
||||
self.is_rotating = True # 是否正在旋转
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("旋转脚本启动!")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
|
||||
def update(self, dt):
|
||||
# 检查 gameObject 是否存在且不为空
|
||||
if not self.gameObject or self.gameObject.isEmpty():
|
||||
print("RotatorScript: gameObject is empty or None, skipping update")
|
||||
return
|
||||
"""每帧更新"""
|
||||
if not self.is_rotating:
|
||||
return
|
||||
|
||||
# 获取当前旋转并应用增量
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
new_h = current_hpr.getX() + self.rotation_speed_y * dt
|
||||
self.gameObject.setHpr(new_h, current_hpr.getY(), current_hpr.getZ())
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("旋转脚本停止")
|
||||
91
111/新项目/scripts/ScalerScript.py
Normal file
91
111/新项目/scripts/ScalerScript.py
Normal file
@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
缩放脚本 - 让对象产生呼吸般的缩放效果
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
import math
|
||||
|
||||
class ScalerScript(ScriptBase):
|
||||
"""缩放脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# 缩放参数
|
||||
self.base_scale = 1.0 # 基础缩放
|
||||
self.scale_amplitude = 0.3 # 缩放幅度
|
||||
self.scale_speed = 2.0 # 缩放速度 (周期/秒)
|
||||
self.uniform_scale = True # 是否统一缩放(所有轴)
|
||||
|
||||
# 内部变量
|
||||
self.time_accumulator = 0.0 # 时间累积器
|
||||
self.original_scale = None # 原始缩放
|
||||
self.is_scaling = True # 是否正在缩放
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("缩放脚本启动!")
|
||||
self.log(f"缩放参数: 基础={self.base_scale}, 幅度={self.scale_amplitude}, 速度={self.scale_speed}")
|
||||
|
||||
# 记录原始缩放
|
||||
self.original_scale = self.gameObject.getScale()
|
||||
self.log(f"原始缩放: {self.original_scale}")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_scaling:
|
||||
return
|
||||
|
||||
# 累积时间
|
||||
self.time_accumulator += dt
|
||||
|
||||
# 计算正弦波缩放值
|
||||
sine_value = math.sin(self.time_accumulator * self.scale_speed * 2 * math.pi)
|
||||
scale_factor = self.base_scale + (self.scale_amplitude * sine_value)
|
||||
|
||||
# 应用缩放
|
||||
if self.uniform_scale:
|
||||
# 统一缩放
|
||||
self.gameObject.setScale(scale_factor)
|
||||
else:
|
||||
# 非统一缩放(仅Z轴)
|
||||
current_scale = self.gameObject.getScale()
|
||||
self.gameObject.setScale(current_scale.getX(), current_scale.getY(), scale_factor)
|
||||
|
||||
def set_scale_parameters(self, base=None, amplitude=None, speed=None, uniform=None):
|
||||
"""设置缩放参数"""
|
||||
if base is not None:
|
||||
self.base_scale = base
|
||||
if amplitude is not None:
|
||||
self.scale_amplitude = amplitude
|
||||
if speed is not None:
|
||||
self.scale_speed = speed
|
||||
if uniform is not None:
|
||||
self.uniform_scale = uniform
|
||||
|
||||
self.log(f"缩放参数更新: 基础={self.base_scale}, 幅度={self.scale_amplitude}, 速度={self.scale_speed}")
|
||||
|
||||
def toggle_scaling(self):
|
||||
"""切换缩放状态"""
|
||||
self.is_scaling = not self.is_scaling
|
||||
status = "恢复" if self.is_scaling else "暂停"
|
||||
self.log(f"缩放{status}")
|
||||
|
||||
def reset_scale(self):
|
||||
"""重置到原始缩放"""
|
||||
if self.original_scale:
|
||||
self.gameObject.setScale(self.original_scale)
|
||||
self.time_accumulator = 0.0
|
||||
self.log("缩放已重置到原始值")
|
||||
|
||||
def pulse_once(self):
|
||||
"""执行一次脉冲缩放"""
|
||||
self.time_accumulator = 0.0
|
||||
self.log("执行脉冲缩放")
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("缩放脚本停止")
|
||||
41
111/新项目/scripts/TestMover.py
Normal file
41
111/新项目/scripts/TestMover.py
Normal file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
TestMover - 移动脚本
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class Testmover(ScriptBase):
|
||||
"""移动脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.speed = 5.0 # 移动速度
|
||||
self.direction = [1, 0, 0] # 移动方向
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("移动脚本开始运行!")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if self.transform:
|
||||
# 计算移动偏移
|
||||
offset_x = self.direction[0] * self.speed * dt
|
||||
offset_y = self.direction[1] * self.speed * dt
|
||||
offset_z = self.direction[2] * self.speed * dt
|
||||
|
||||
# 更新位置
|
||||
current_pos = self.transform.getPos()
|
||||
new_pos = (
|
||||
current_pos.x + offset_x,
|
||||
current_pos.y + offset_y,
|
||||
current_pos.z + offset_z
|
||||
)
|
||||
self.transform.setPos(*new_pos)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("移动脚本被销毁")
|
||||
28
111/新项目/scripts/TestRotator.py
Normal file
28
111/新项目/scripts/TestRotator.py
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
TestRotator - 自定义脚本
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class Testrotator(ScriptBase):
|
||||
"""自定义脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
# 在这里初始化您的变量
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("脚本开始运行!")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
# 在这里编写更新逻辑
|
||||
pass
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("脚本被销毁")
|
||||
28
111/新项目/scripts/TestScaler.py
Normal file
28
111/新项目/scripts/TestScaler.py
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
TestScaler - 自定义脚本
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class Testscaler(ScriptBase):
|
||||
"""自定义脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
# 在这里初始化您的变量
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("脚本开始运行!")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
# 在这里编写更新逻辑
|
||||
pass
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("脚本被销毁")
|
||||
28
111/新项目/scripts/a.py
Normal file
28
111/新项目/scripts/a.py
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
a - 自定义脚本
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class A(ScriptBase):
|
||||
"""自定义脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
# 在这里初始化您的变量
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("脚本开始运行!")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
# 在这里编写更新逻辑
|
||||
pass
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("脚本被销毁")
|
||||
47
111/新项目/scripts/example_script.py
Normal file
47
111/新项目/scripts/example_script.py
Normal file
@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
示例脚本 - 演示如何编写脚本
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class ExampleScript(ScriptBase):
|
||||
"""示例脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.counter = 0
|
||||
self.rotation_speed = 30.0 # 度/秒
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("示例脚本开始运行!")
|
||||
self.log(f"挂载到对象: {self.gameObject.getName()}")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
self.counter += 1
|
||||
|
||||
# 每60帧输出一次信息
|
||||
if self.counter % 60 == 0:
|
||||
self.log(f"运行了 {self.counter} 帧")
|
||||
|
||||
# 让对象旋转
|
||||
if self.transform:
|
||||
current_h = self.transform.getH()
|
||||
new_h = current_h + self.rotation_speed * dt
|
||||
self.transform.setH(new_h)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("示例脚本被销毁")
|
||||
|
||||
def on_enable(self):
|
||||
"""脚本启用时调用"""
|
||||
self.log("示例脚本被启用")
|
||||
|
||||
def on_disable(self):
|
||||
"""脚本禁用时调用"""
|
||||
self.log("示例脚本被禁用")
|
||||
28
111/新项目/scripts/test_quick_script.py
Normal file
28
111/新项目/scripts/test_quick_script.py
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
test_quick_script - 自定义脚本
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class TestQuickScript(ScriptBase):
|
||||
"""自定义脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
# 在这里初始化您的变量
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("脚本开始运行!")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
# 在这里编写更新逻辑
|
||||
pass
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("脚本被销毁")
|
||||
BIN
111/新项目/新项目.png
Normal file
BIN
111/新项目/新项目.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
BIN
Resources/models/jyc.glb
Normal file
BIN
Resources/models/jyc.glb
Normal file
Binary file not shown.
1
build/.111_staging/assets/gui/gui_elements.json
Normal file
1
build/.111_staging/assets/gui/gui_elements.json
Normal file
@ -0,0 +1 @@
|
||||
[]
|
||||
BIN
build/.111_staging/assets/scene.bam
Normal file
BIN
build/.111_staging/assets/scene.bam
Normal file
Binary file not shown.
102
build/.111_staging/assets/scripts/BouncerScript.py
Normal file
102
build/.111_staging/assets/scripts/BouncerScript.py
Normal file
@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
跳跃脚本 - 让对象产生上下跳跃效果
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
import math
|
||||
|
||||
class BouncerScript(ScriptBase):
|
||||
"""跳跃脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# 跳跃参数
|
||||
self.jump_height = 2.0 # 跳跃高度
|
||||
self.jump_speed = 3.0 # 跳跃速度 (跳跃/秒)
|
||||
self.bounce_type = "sine" # 跳跃类型: "sine", "abs_sine", "square"
|
||||
|
||||
# 内部变量
|
||||
self.time_accumulator = 0.0 # 时间累积器
|
||||
self.original_y = None # 原始Y位置
|
||||
self.is_bouncing = True # 是否正在跳跃
|
||||
self.bounce_direction = 1 # 跳跃方向
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("跳跃脚本启动!")
|
||||
self.log(f"跳跃参数: 高度={self.jump_height}, 速度={self.jump_speed}, 类型={self.bounce_type}")
|
||||
|
||||
# 记录原始Y位置
|
||||
self.original_y = self.gameObject.getZ() # Z轴是高度
|
||||
self.log(f"原始高度: {self.original_y}")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_bouncing:
|
||||
return
|
||||
|
||||
# 累积时间
|
||||
self.time_accumulator += dt * self.bounce_direction
|
||||
|
||||
# 根据类型计算跳跃高度
|
||||
if self.bounce_type == "sine":
|
||||
# 标准正弦波跳跃
|
||||
height_offset = math.sin(self.time_accumulator * self.jump_speed * 2 * math.pi) * self.jump_height
|
||||
elif self.bounce_type == "abs_sine":
|
||||
# 绝对值正弦波(始终向上)
|
||||
height_offset = abs(math.sin(self.time_accumulator * self.jump_speed * 2 * math.pi)) * self.jump_height
|
||||
elif self.bounce_type == "square":
|
||||
# 方波跳跃(突然跳起落下)
|
||||
sine_val = math.sin(self.time_accumulator * self.jump_speed * 2 * math.pi)
|
||||
height_offset = self.jump_height if sine_val > 0 else 0
|
||||
else:
|
||||
height_offset = 0
|
||||
|
||||
# 应用跳跃
|
||||
current_pos = self.gameObject.getPos()
|
||||
new_z = self.original_y + height_offset
|
||||
self.gameObject.setPos(current_pos.getX(), current_pos.getY(), new_z)
|
||||
|
||||
def set_bounce_parameters(self, height=None, speed=None, bounce_type=None):
|
||||
"""设置跳跃参数"""
|
||||
if height is not None:
|
||||
self.jump_height = height
|
||||
if speed is not None:
|
||||
self.jump_speed = speed
|
||||
if bounce_type is not None and bounce_type in ["sine", "abs_sine", "square"]:
|
||||
self.bounce_type = bounce_type
|
||||
|
||||
self.log(f"跳跃参数更新: 高度={self.jump_height}, 速度={self.jump_speed}, 类型={self.bounce_type}")
|
||||
|
||||
def toggle_bouncing(self):
|
||||
"""切换跳跃状态"""
|
||||
self.is_bouncing = not self.is_bouncing
|
||||
status = "恢复" if self.is_bouncing else "暂停"
|
||||
self.log(f"跳跃{status}")
|
||||
|
||||
def reverse_direction(self):
|
||||
"""反转跳跃方向"""
|
||||
self.bounce_direction *= -1
|
||||
direction = "正向" if self.bounce_direction > 0 else "反向"
|
||||
self.log(f"跳跃方向改为{direction}")
|
||||
|
||||
def reset_position(self):
|
||||
"""重置到原始高度"""
|
||||
if self.original_y is not None:
|
||||
current_pos = self.gameObject.getPos()
|
||||
self.gameObject.setPos(current_pos.getX(), current_pos.getY(), self.original_y)
|
||||
self.time_accumulator = 0.0
|
||||
self.log("位置已重置到原始高度")
|
||||
|
||||
def jump_once(self):
|
||||
"""执行一次跳跃"""
|
||||
self.time_accumulator = 0.0
|
||||
self.log("执行单次跳跃")
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("跳跃脚本停止")
|
||||
160
build/.111_staging/assets/scripts/ColorChangerScript.py
Normal file
160
build/.111_staging/assets/scripts/ColorChangerScript.py
Normal file
@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
颜色变化脚本 - 让对象颜色产生循环变化
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
from panda3d.core import Vec4
|
||||
import math
|
||||
|
||||
class ColorChangerScript(ScriptBase):
|
||||
"""颜色变化脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# 颜色参数
|
||||
self.color_speed = 1.0 # 颜色变化速度 (周期/秒)
|
||||
self.color_mode = "rainbow" # 颜色模式: "rainbow", "pulse", "fade", "strobe"
|
||||
self.base_color = Vec4(1, 1, 1, 1) # 基础颜色
|
||||
self.intensity = 1.0 # 颜色强度
|
||||
|
||||
# 内部变量
|
||||
self.time_accumulator = 0.0 # 时间累积器
|
||||
self.original_color = None # 原始颜色
|
||||
self.is_changing = True # 是否正在变化
|
||||
self.strobe_state = False # 闪烁状态
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("颜色变化脚本启动!")
|
||||
self.log(f"颜色参数: 速度={self.color_speed}, 模式={self.color_mode}, 强度={self.intensity}")
|
||||
|
||||
# 记录原始颜色
|
||||
self.original_color = self.gameObject.getColor()
|
||||
self.log(f"原始颜色: {self.original_color}")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_changing:
|
||||
return
|
||||
|
||||
# 累积时间
|
||||
self.time_accumulator += dt
|
||||
|
||||
# 根据模式计算新颜色
|
||||
if self.color_mode == "rainbow":
|
||||
new_color = self._calculate_rainbow_color()
|
||||
elif self.color_mode == "pulse":
|
||||
new_color = self._calculate_pulse_color()
|
||||
elif self.color_mode == "fade":
|
||||
new_color = self._calculate_fade_color()
|
||||
elif self.color_mode == "strobe":
|
||||
new_color = self._calculate_strobe_color()
|
||||
else:
|
||||
new_color = self.base_color
|
||||
|
||||
# 应用颜色
|
||||
self.gameObject.setColor(new_color)
|
||||
|
||||
def _calculate_rainbow_color(self):
|
||||
"""计算彩虹颜色"""
|
||||
# 使用HSV到RGB的转换创建彩虹效果
|
||||
hue = (self.time_accumulator * self.color_speed) % 1.0
|
||||
|
||||
# 简单的HSV到RGB转换
|
||||
i = int(hue * 6.0)
|
||||
f = (hue * 6.0) - i
|
||||
p = 0.0
|
||||
q = 1.0 - f
|
||||
t = f
|
||||
|
||||
if i % 6 == 0:
|
||||
r, g, b = 1.0, t, p
|
||||
elif i % 6 == 1:
|
||||
r, g, b = q, 1.0, p
|
||||
elif i % 6 == 2:
|
||||
r, g, b = p, 1.0, t
|
||||
elif i % 6 == 3:
|
||||
r, g, b = p, q, 1.0
|
||||
elif i % 6 == 4:
|
||||
r, g, b = t, p, 1.0
|
||||
else:
|
||||
r, g, b = 1.0, p, q
|
||||
|
||||
return Vec4(r * self.intensity, g * self.intensity, b * self.intensity, 1.0)
|
||||
|
||||
def _calculate_pulse_color(self):
|
||||
"""计算脉冲颜色"""
|
||||
pulse = (math.sin(self.time_accumulator * self.color_speed * 2 * math.pi) + 1.0) / 2.0
|
||||
multiplier = pulse * self.intensity
|
||||
return Vec4(
|
||||
self.base_color.getX() * multiplier,
|
||||
self.base_color.getY() * multiplier,
|
||||
self.base_color.getZ() * multiplier,
|
||||
self.base_color.getW()
|
||||
)
|
||||
|
||||
def _calculate_fade_color(self):
|
||||
"""计算淡入淡出颜色"""
|
||||
fade = (math.sin(self.time_accumulator * self.color_speed * 2 * math.pi) + 1.0) / 2.0
|
||||
alpha = fade * self.intensity
|
||||
return Vec4(
|
||||
self.base_color.getX(),
|
||||
self.base_color.getY(),
|
||||
self.base_color.getZ(),
|
||||
alpha
|
||||
)
|
||||
|
||||
def _calculate_strobe_color(self):
|
||||
"""计算闪烁颜色"""
|
||||
# 根据时间间隔切换状态
|
||||
interval = 1.0 / (self.color_speed * 2) # 闪烁间隔
|
||||
if int(self.time_accumulator / interval) % 2 == 0:
|
||||
return Vec4(
|
||||
self.base_color.getX() * self.intensity,
|
||||
self.base_color.getY() * self.intensity,
|
||||
self.base_color.getZ() * self.intensity,
|
||||
self.base_color.getW()
|
||||
)
|
||||
else:
|
||||
return Vec4(0.1, 0.1, 0.1, self.base_color.getW()) # 暗色状态
|
||||
|
||||
def set_color_parameters(self, speed=None, mode=None, base_color=None, intensity=None):
|
||||
"""设置颜色参数"""
|
||||
if speed is not None:
|
||||
self.color_speed = speed
|
||||
if mode is not None and mode in ["rainbow", "pulse", "fade", "strobe"]:
|
||||
self.color_mode = mode
|
||||
if base_color is not None:
|
||||
self.base_color = base_color
|
||||
if intensity is not None:
|
||||
self.intensity = intensity
|
||||
|
||||
self.log(f"颜色参数更新: 速度={self.color_speed}, 模式={self.color_mode}, 强度={self.intensity}")
|
||||
|
||||
def toggle_color_change(self):
|
||||
"""切换颜色变化状态"""
|
||||
self.is_changing = not self.is_changing
|
||||
status = "恢复" if self.is_changing else "暂停"
|
||||
self.log(f"颜色变化{status}")
|
||||
|
||||
def reset_color(self):
|
||||
"""重置到原始颜色"""
|
||||
if self.original_color:
|
||||
self.gameObject.setColor(self.original_color)
|
||||
self.time_accumulator = 0.0
|
||||
self.log("颜色已重置到原始值")
|
||||
|
||||
def set_solid_color(self, r=1.0, g=1.0, b=1.0, a=1.0):
|
||||
"""设置固定颜色"""
|
||||
color = Vec4(r, g, b, a)
|
||||
self.gameObject.setColor(color)
|
||||
self.base_color = color
|
||||
self.log(f"设置固定颜色: {color}")
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("颜色变化脚本停止")
|
||||
39
build/.111_staging/assets/scripts/ComboAnimatorScript.py
Normal file
39
build/.111_staging/assets/scripts/ComboAnimatorScript.py
Normal file
@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
复合动画脚本 - 结合旋转和跳跃效果
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
import math
|
||||
|
||||
class ComboAnimatorScript(ScriptBase):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.time = 0.0
|
||||
self.original_pos = None
|
||||
self.is_active = True
|
||||
|
||||
def start(self):
|
||||
self.log("复合动画脚本启动!")
|
||||
self.original_pos = self.gameObject.getPos()
|
||||
|
||||
def update(self, dt):
|
||||
if not self.is_active:
|
||||
return
|
||||
|
||||
self.time += dt
|
||||
|
||||
# 旋转效果
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
new_h = current_hpr.getX() + 45.0 * dt
|
||||
self.gameObject.setHpr(new_h, current_hpr.getY(), current_hpr.getZ())
|
||||
|
||||
# 跳跃效果
|
||||
if self.original_pos:
|
||||
bounce_offset = abs(math.sin(self.time * 3.0)) * 1.0
|
||||
self.gameObject.setZ(self.original_pos.getZ() + bounce_offset)
|
||||
|
||||
def on_destroy(self):
|
||||
self.log("复合动画脚本停止")
|
||||
69
build/.111_staging/assets/scripts/FollowerScript.py
Normal file
69
build/.111_staging/assets/scripts/FollowerScript.py
Normal file
@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
跟随脚本 - 让对象跟随指定的目标对象
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
from panda3d.core import Vec3
|
||||
|
||||
class FollowerScript(ScriptBase):
|
||||
"""跟随脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.target = None # 跟随目标
|
||||
self.follow_speed = 5.0 # 跟随速度
|
||||
self.follow_distance = 2.0 # 跟随距离
|
||||
self.is_following = True # 是否正在跟随
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("跟随脚本启动!")
|
||||
self.log(f"跟随参数: 速度={self.follow_speed}, 距离={self.follow_distance}")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_following or self.target is None:
|
||||
return
|
||||
|
||||
target_pos = self.target.getPos()
|
||||
current_pos = self.gameObject.getPos()
|
||||
|
||||
# 计算目标方向
|
||||
direction = target_pos - current_pos
|
||||
distance = direction.length()
|
||||
|
||||
# 如果距离大于跟随距离,则移动
|
||||
if distance > self.follow_distance:
|
||||
if distance > 0:
|
||||
direction.normalize()
|
||||
|
||||
# 计算目标位置(保持跟随距离)
|
||||
target_follow_pos = target_pos - direction * self.follow_distance
|
||||
|
||||
# 平滑移动到目标位置
|
||||
move_direction = target_follow_pos - current_pos
|
||||
move_distance = move_direction.length()
|
||||
|
||||
if move_distance > 0:
|
||||
move_direction.normalize()
|
||||
move_amount = min(self.follow_speed * dt, move_distance)
|
||||
new_pos = current_pos + move_direction * move_amount
|
||||
self.gameObject.setPos(new_pos)
|
||||
|
||||
# 朝向目标
|
||||
self.gameObject.lookAt(target_pos)
|
||||
|
||||
def set_target(self, target):
|
||||
"""设置跟随目标"""
|
||||
self.target = target
|
||||
if target:
|
||||
self.log(f"设置跟随目标: {target.getName()}")
|
||||
else:
|
||||
self.log("清除跟随目标")
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("跟随脚本停止")
|
||||
91
build/.111_staging/assets/scripts/MoverScript.py
Normal file
91
build/.111_staging/assets/scripts/MoverScript.py
Normal file
@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
移动脚本 - 让对象在指定方向上来回移动
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
import math
|
||||
|
||||
class MoverScript(ScriptBase):
|
||||
"""移动脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# 移动参数
|
||||
self.move_distance = 5.0 # 移动距离
|
||||
self.move_speed = 2.0 # 移动速度 (单位/秒)
|
||||
self.move_axis = "x" # 移动轴: "x", "y", "z"
|
||||
|
||||
# 内部变量
|
||||
self.start_position = None # 起始位置
|
||||
self.current_direction = 1 # 当前移动方向: 1或-1
|
||||
self.current_distance = 0.0 # 当前移动距离
|
||||
self.is_moving = True # 是否正在移动
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("移动脚本启动!")
|
||||
self.log(f"移动参数: 距离={self.move_distance}, 速度={self.move_speed}, 轴={self.move_axis}")
|
||||
|
||||
# 记录起始位置
|
||||
self.start_position = self.gameObject.getPos()
|
||||
self.log(f"起始位置: {self.start_position}")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_moving or self.start_position is None:
|
||||
return
|
||||
|
||||
# 计算移动增量
|
||||
move_delta = self.move_speed * dt * self.current_direction
|
||||
self.current_distance += abs(move_delta)
|
||||
|
||||
# 检查是否需要改变方向
|
||||
if self.current_distance >= self.move_distance:
|
||||
self.current_direction *= -1
|
||||
self.current_distance = 0.0
|
||||
|
||||
# 应用移动
|
||||
current_pos = self.gameObject.getPos()
|
||||
new_pos = [current_pos.getX(), current_pos.getY(), current_pos.getZ()]
|
||||
|
||||
if self.move_axis == "x":
|
||||
new_pos[0] += move_delta
|
||||
elif self.move_axis == "y":
|
||||
new_pos[1] += move_delta
|
||||
elif self.move_axis == "z":
|
||||
new_pos[2] += move_delta
|
||||
|
||||
self.gameObject.setPos(new_pos[0], new_pos[1], new_pos[2])
|
||||
|
||||
def set_move_parameters(self, distance=None, speed=None, axis=None):
|
||||
"""设置移动参数"""
|
||||
if distance is not None:
|
||||
self.move_distance = distance
|
||||
if speed is not None:
|
||||
self.move_speed = speed
|
||||
if axis is not None and axis in ["x", "y", "z"]:
|
||||
self.move_axis = axis
|
||||
|
||||
self.log(f"移动参数更新: 距离={self.move_distance}, 速度={self.move_speed}, 轴={self.move_axis}")
|
||||
|
||||
def toggle_movement(self):
|
||||
"""切换移动状态"""
|
||||
self.is_moving = not self.is_moving
|
||||
status = "恢复" if self.is_moving else "暂停"
|
||||
self.log(f"移动{status}")
|
||||
|
||||
def reset_position(self):
|
||||
"""重置到起始位置"""
|
||||
if self.start_position:
|
||||
self.gameObject.setPos(self.start_position)
|
||||
self.current_distance = 0.0
|
||||
self.current_direction = 1
|
||||
self.log("位置已重置到起始点")
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("移动脚本停止")
|
||||
133
build/.111_staging/assets/scripts/R_P.py
Normal file
133
build/.111_staging/assets/scripts/R_P.py
Normal file
@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
旋转脚本 - 让对象持续旋转
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
|
||||
class RotatorScript(ScriptBase):
|
||||
"""旋转脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.rotation_speed_y = 30.0 # Y轴旋转速度 (度/秒)
|
||||
self.max_angle = 30.0 # 最大旋转角度(相对于初始角度)
|
||||
self.direction = 1
|
||||
self.current_offset = 0.0 # 当前相对于初始角度的偏移
|
||||
self.initial_angle = None # 模型的初始角度
|
||||
self.is_rotating = True # 是否正在旋转
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("旋转脚本启动!")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"最大旋转角度: ±{self.max_angle}度")
|
||||
|
||||
# 记录模型的初始角度
|
||||
if self.gameObject:
|
||||
initial_hpr = self.gameObject.getHpr()
|
||||
self.initial_angle = initial_hpr.getZ() # 记录Z轴的初始角度
|
||||
self.log(f"模型初始角度: {self.initial_angle}度")
|
||||
self.log(f"旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
else:
|
||||
self.log("⚠️ 无法获取游戏对象,使用默认初始角度0")
|
||||
self.initial_angle = 0.0
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_rotating or self.initial_angle is None:
|
||||
return
|
||||
|
||||
# 计算角度变化量
|
||||
delta_angle = self.rotation_speed_y * dt * self.direction
|
||||
self.current_offset += delta_angle
|
||||
|
||||
# 如果超出角度范围,则反向并限制在边界
|
||||
if self.current_offset > self.max_angle:
|
||||
self.current_offset = self.max_angle
|
||||
self.direction *= -1
|
||||
elif self.current_offset < -self.max_angle:
|
||||
self.current_offset = -self.max_angle
|
||||
self.direction *= -1
|
||||
|
||||
# 计算最终角度(初始角度 + 偏移量)
|
||||
final_angle = self.initial_angle + self.current_offset
|
||||
|
||||
# 设置新的旋转(只改变Z轴,保持其他不变)
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), final_angle, current_hpr.getZ())
|
||||
|
||||
# if not self.is_rotating:
|
||||
# return
|
||||
#
|
||||
# # 获取当前旋转并应用增量
|
||||
# current_hpr = self.gameObject.getHpr()
|
||||
# new_r = current_hpr.getZ() + self.rotation_speed_y * dt
|
||||
# self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), new_r)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("旋转脚本停止")
|
||||
|
||||
# ==================== 控制方法 ====================
|
||||
|
||||
def set_max_angle(self, new_max_angle):
|
||||
"""
|
||||
设置新的最大旋转角度
|
||||
|
||||
Args:
|
||||
new_max_angle: 新的最大角度值
|
||||
"""
|
||||
self.max_angle = new_max_angle
|
||||
self.log(f"最大旋转角度已设置为: ±{self.max_angle}度")
|
||||
if self.initial_angle is not None:
|
||||
self.log(f"新的旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
|
||||
def set_rotation_speed(self, new_speed):
|
||||
"""
|
||||
设置新的旋转速度
|
||||
|
||||
Args:
|
||||
new_speed: 新的旋转速度(度/秒)
|
||||
"""
|
||||
self.rotation_speed_y = new_speed
|
||||
self.log(f"旋转速度已设置为: {self.rotation_speed_y}度/秒")
|
||||
|
||||
def pause_rotation(self):
|
||||
"""暂停旋转"""
|
||||
self.is_rotating = False
|
||||
self.log("旋转已暂停")
|
||||
|
||||
def resume_rotation(self):
|
||||
"""恢复旋转"""
|
||||
self.is_rotating = True
|
||||
self.log("旋转已恢复")
|
||||
|
||||
def reset_to_initial_angle(self):
|
||||
"""重置到初始角度"""
|
||||
if self.initial_angle is not None and self.gameObject:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), self.initial_angle)
|
||||
self.current_offset = 0.0
|
||||
self.direction = 1
|
||||
self.log(f"已重置到初始角度: {self.initial_angle}度")
|
||||
|
||||
def get_current_info(self):
|
||||
"""获取当前旋转信息"""
|
||||
if self.gameObject and self.initial_angle is not None:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
current_angle = current_hpr.getZ()
|
||||
self.log("=== 当前旋转信息 ===")
|
||||
self.log(f"初始角度: {self.initial_angle}度")
|
||||
self.log(f"当前角度: {current_angle}度")
|
||||
self.log(f"偏移量: {self.current_offset}度")
|
||||
self.log(f"最大角度: ±{self.max_angle}度")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"旋转方向: {'正向' if self.direction > 0 else '反向'}")
|
||||
self.log(f"旋转状态: {'运行中' if self.is_rotating else '已暂停'}")
|
||||
self.log("=== 信息结束 ===")
|
||||
else:
|
||||
self.log("无法获取旋转信息")
|
||||
133
build/.111_staging/assets/scripts/R_R.py
Normal file
133
build/.111_staging/assets/scripts/R_R.py
Normal file
@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
旋转脚本 - 让对象持续旋转
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
|
||||
class RotatorScript(ScriptBase):
|
||||
"""旋转脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.rotation_speed_y = 30.0 # Y轴旋转速度 (度/秒)
|
||||
self.max_angle = 30.0 # 最大旋转角度(相对于初始角度)
|
||||
self.direction = 1
|
||||
self.current_offset = 0.0 # 当前相对于初始角度的偏移
|
||||
self.initial_angle = None # 模型的初始角度
|
||||
self.is_rotating = True # 是否正在旋转
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("旋转脚本启动!")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"最大旋转角度: ±{self.max_angle}度")
|
||||
|
||||
# 记录模型的初始角度
|
||||
if self.gameObject:
|
||||
initial_hpr = self.gameObject.getHpr()
|
||||
self.initial_angle = initial_hpr.getZ() # 记录Z轴的初始角度
|
||||
self.log(f"模型初始角度: {self.initial_angle}度")
|
||||
self.log(f"旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
else:
|
||||
self.log("⚠️ 无法获取游戏对象,使用默认初始角度0")
|
||||
self.initial_angle = 0.0
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_rotating or self.initial_angle is None:
|
||||
return
|
||||
|
||||
# 计算角度变化量
|
||||
delta_angle = self.rotation_speed_y * dt * self.direction
|
||||
self.current_offset += delta_angle
|
||||
|
||||
# 如果超出角度范围,则反向并限制在边界
|
||||
if self.current_offset > self.max_angle:
|
||||
self.current_offset = self.max_angle
|
||||
self.direction *= -1
|
||||
elif self.current_offset < -self.max_angle:
|
||||
self.current_offset = -self.max_angle
|
||||
self.direction *= -1
|
||||
|
||||
# 计算最终角度(初始角度 + 偏移量)
|
||||
final_angle = self.initial_angle + self.current_offset
|
||||
|
||||
# 设置新的旋转(只改变Z轴,保持其他不变)
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), final_angle)
|
||||
|
||||
# if not self.is_rotating:
|
||||
# return
|
||||
#
|
||||
# # 获取当前旋转并应用增量
|
||||
# current_hpr = self.gameObject.getHpr()
|
||||
# new_r = current_hpr.getZ() + self.rotation_speed_y * dt
|
||||
# self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), new_r)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("旋转脚本停止")
|
||||
|
||||
# ==================== 控制方法 ====================
|
||||
|
||||
def set_max_angle(self, new_max_angle):
|
||||
"""
|
||||
设置新的最大旋转角度
|
||||
|
||||
Args:
|
||||
new_max_angle: 新的最大角度值
|
||||
"""
|
||||
self.max_angle = new_max_angle
|
||||
self.log(f"最大旋转角度已设置为: ±{self.max_angle}度")
|
||||
if self.initial_angle is not None:
|
||||
self.log(f"新的旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
|
||||
def set_rotation_speed(self, new_speed):
|
||||
"""
|
||||
设置新的旋转速度
|
||||
|
||||
Args:
|
||||
new_speed: 新的旋转速度(度/秒)
|
||||
"""
|
||||
self.rotation_speed_y = new_speed
|
||||
self.log(f"旋转速度已设置为: {self.rotation_speed_y}度/秒")
|
||||
|
||||
def pause_rotation(self):
|
||||
"""暂停旋转"""
|
||||
self.is_rotating = False
|
||||
self.log("旋转已暂停")
|
||||
|
||||
def resume_rotation(self):
|
||||
"""恢复旋转"""
|
||||
self.is_rotating = True
|
||||
self.log("旋转已恢复")
|
||||
|
||||
def reset_to_initial_angle(self):
|
||||
"""重置到初始角度"""
|
||||
if self.initial_angle is not None and self.gameObject:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), self.initial_angle)
|
||||
self.current_offset = 0.0
|
||||
self.direction = 1
|
||||
self.log(f"已重置到初始角度: {self.initial_angle}度")
|
||||
|
||||
def get_current_info(self):
|
||||
"""获取当前旋转信息"""
|
||||
if self.gameObject and self.initial_angle is not None:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
current_angle = current_hpr.getZ()
|
||||
self.log("=== 当前旋转信息 ===")
|
||||
self.log(f"初始角度: {self.initial_angle}度")
|
||||
self.log(f"当前角度: {current_angle}度")
|
||||
self.log(f"偏移量: {self.current_offset}度")
|
||||
self.log(f"最大角度: ±{self.max_angle}度")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"旋转方向: {'正向' if self.direction > 0 else '反向'}")
|
||||
self.log(f"旋转状态: {'运行中' if self.is_rotating else '已暂停'}")
|
||||
self.log("=== 信息结束 ===")
|
||||
else:
|
||||
self.log("无法获取旋转信息")
|
||||
215
build/.111_staging/assets/scripts/Rotate_H_Script.py
Normal file
215
build/.111_staging/assets/scripts/Rotate_H_Script.py
Normal file
@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
旋转脚本 - 让对象持续旋转
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
|
||||
class RotatorScript(ScriptBase):
|
||||
"""旋转脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.rotation_speed_y = 30.0 # Y轴旋转速度 (度/秒)
|
||||
self.max_angle = 30.0 # 最大旋转角度(相对于初始角度)
|
||||
self.direction = 1
|
||||
self.current_offset = 0.0 # 当前相对于初始角度的偏移
|
||||
self.initial_angle = None # 模型的初始角度
|
||||
self.is_rotating = True # 是否正在旋转
|
||||
|
||||
# 机器人式停顿参数
|
||||
self.pause_duration = 0.5 # 停顿时间(秒)
|
||||
self.current_pause_time = 0.0 # 当前停顿计时
|
||||
self.is_paused = False # 是否正在停顿
|
||||
self.robot_mode = True # 是否启用机器人模式
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("机器人旋转脚本启动!")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"最大旋转角度: ±{self.max_angle}度")
|
||||
self.log(f"机器人模式: {'开启' if self.robot_mode else '关闭'}")
|
||||
if self.robot_mode:
|
||||
self.log(f"停顿时间: {self.pause_duration}秒")
|
||||
|
||||
# 记录模型的初始角度
|
||||
if self.gameObject:
|
||||
initial_hpr = self.gameObject.getHpr()
|
||||
self.initial_angle = initial_hpr.getY() # 记录Y轴的初始角度(Pitch)
|
||||
self.log(f"模型初始角度: {self.initial_angle}度")
|
||||
self.log(f"旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
else:
|
||||
self.log("⚠️ 无法获取游戏对象,使用默认初始角度0")
|
||||
self.initial_angle = 0.0
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新 - 机器人式旋转"""
|
||||
if not self.is_rotating or self.initial_angle is None:
|
||||
return
|
||||
|
||||
# 如果正在停顿中
|
||||
if self.is_paused:
|
||||
self.current_pause_time += dt
|
||||
if self.current_pause_time >= self.pause_duration:
|
||||
# 停顿结束,继续旋转
|
||||
self.is_paused = False
|
||||
self.current_pause_time = 0.0
|
||||
self.log(f"停顿结束,继续旋转,方向: {'正向' if self.direction > 0 else '反向'}")
|
||||
return
|
||||
|
||||
# 计算角度变化量
|
||||
delta_angle = self.rotation_speed_y * dt * self.direction
|
||||
self.current_offset += delta_angle
|
||||
|
||||
# 检查是否到达边界
|
||||
reached_boundary = False
|
||||
if self.current_offset > self.max_angle:
|
||||
self.current_offset = self.max_angle
|
||||
self.direction *= -1
|
||||
reached_boundary = True
|
||||
elif self.current_offset < -self.max_angle:
|
||||
self.current_offset = -self.max_angle
|
||||
self.direction *= -1
|
||||
reached_boundary = True
|
||||
|
||||
# 如果到达边界且启用机器人模式,开始停顿
|
||||
if reached_boundary and self.robot_mode:
|
||||
self.is_paused = True
|
||||
self.current_pause_time = 0.0
|
||||
self.log(f"到达边界 ({self.current_offset}°),开始停顿 {self.pause_duration}秒")
|
||||
|
||||
# 计算最终角度(初始角度 + 偏移量)
|
||||
final_angle = self.initial_angle + self.current_offset
|
||||
|
||||
# 设置新的旋转(只改变Y轴,保持其他不变)
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(final_angle, current_hpr.getY(), current_hpr.getZ())
|
||||
|
||||
# if not self.is_rotating:
|
||||
# return
|
||||
#
|
||||
# # 获取当前旋转并应用增量
|
||||
# current_hpr = self.gameObject.getHpr()
|
||||
# new_r = current_hpr.getZ() + self.rotation_speed_y * dt
|
||||
# self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), new_r)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("机器人旋转脚本停止")
|
||||
|
||||
# ==================== 机器人模式控制方法 ====================
|
||||
|
||||
def set_robot_mode(self, enabled=True):
|
||||
"""
|
||||
启用或禁用机器人模式
|
||||
|
||||
Args:
|
||||
enabled: 是否启用机器人模式
|
||||
"""
|
||||
self.robot_mode = enabled
|
||||
self.log(f"机器人模式: {'开启' if enabled else '关闭'}")
|
||||
if not enabled:
|
||||
self.is_paused = False # 如果禁用机器人模式,立即结束停顿
|
||||
|
||||
def set_pause_duration(self, duration):
|
||||
"""
|
||||
设置停顿时间
|
||||
|
||||
Args:
|
||||
duration: 停顿时间(秒)
|
||||
"""
|
||||
self.pause_duration = max(0.1, duration) # 最小0.1秒
|
||||
self.log(f"停顿时间已设置为: {self.pause_duration}秒")
|
||||
|
||||
def set_max_angle(self, new_max_angle):
|
||||
"""
|
||||
设置新的最大旋转角度
|
||||
|
||||
Args:
|
||||
new_max_angle: 新的最大角度值
|
||||
"""
|
||||
self.max_angle = new_max_angle
|
||||
self.log(f"最大旋转角度已设置为: ±{self.max_angle}度")
|
||||
if self.initial_angle is not None:
|
||||
self.log(f"新的旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
|
||||
def set_rotation_speed(self, new_speed):
|
||||
"""
|
||||
设置新的旋转速度
|
||||
|
||||
Args:
|
||||
new_speed: 新的旋转速度(度/秒)
|
||||
"""
|
||||
self.rotation_speed_y = new_speed
|
||||
self.log(f"旋转速度已设置为: {self.rotation_speed_y}度/秒")
|
||||
|
||||
def pause_rotation(self):
|
||||
"""暂停旋转"""
|
||||
self.is_rotating = False
|
||||
self.log("旋转已暂停")
|
||||
|
||||
def resume_rotation(self):
|
||||
"""恢复旋转"""
|
||||
self.is_rotating = True
|
||||
self.is_paused = False # 同时结束停顿状态
|
||||
self.log("旋转已恢复")
|
||||
|
||||
def reset_to_initial_angle(self):
|
||||
"""重置到初始角度"""
|
||||
if self.initial_angle is not None and self.gameObject:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), self.initial_angle, current_hpr.getZ())
|
||||
self.current_offset = 0.0
|
||||
self.direction = 1
|
||||
self.is_paused = False
|
||||
self.current_pause_time = 0.0
|
||||
self.log(f"已重置到初始角度: {self.initial_angle}度")
|
||||
|
||||
def get_current_info(self):
|
||||
"""获取当前旋转信息"""
|
||||
if self.gameObject and self.initial_angle is not None:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
current_angle = current_hpr.getY()
|
||||
self.log("=== 机器人旋转信息 ===")
|
||||
self.log(f"初始角度: {self.initial_angle}度")
|
||||
self.log(f"当前角度: {current_angle}度")
|
||||
self.log(f"偏移量: {self.current_offset}度")
|
||||
self.log(f"最大角度: ±{self.max_angle}度")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"旋转方向: {'正向' if self.direction > 0 else '反向'}")
|
||||
self.log(f"旋转状态: {'运行中' if self.is_rotating else '已暂停'}")
|
||||
self.log(f"机器人模式: {'开启' if self.robot_mode else '关闭'}")
|
||||
if self.robot_mode:
|
||||
self.log(f"停顿时间: {self.pause_duration}秒")
|
||||
self.log(f"当前状态: {'停顿中' if self.is_paused else '旋转中'}")
|
||||
if self.is_paused:
|
||||
remaining_time = self.pause_duration - self.current_pause_time
|
||||
self.log(f"剩余停顿时间: {remaining_time:.1f}秒")
|
||||
self.log("=== 信息结束 ===")
|
||||
else:
|
||||
self.log("无法获取旋转信息")
|
||||
|
||||
# ==================== 预设配置方法 ====================
|
||||
|
||||
def set_slow_robot_mode(self):
|
||||
"""预设:慢速机器人模式"""
|
||||
self.set_rotation_speed(15.0)
|
||||
self.set_pause_duration(1.0)
|
||||
self.set_robot_mode(True)
|
||||
self.log("已设置为慢速机器人模式")
|
||||
|
||||
def set_fast_robot_mode(self):
|
||||
"""预设:快速机器人模式"""
|
||||
self.set_rotation_speed(45.0)
|
||||
self.set_pause_duration(0.3)
|
||||
self.set_robot_mode(True)
|
||||
self.log("已设置为快速机器人模式")
|
||||
|
||||
def set_smooth_mode(self):
|
||||
"""预设:平滑模式(非机器人)"""
|
||||
self.set_robot_mode(False)
|
||||
self.set_rotation_speed(30.0)
|
||||
self.log("已设置为平滑旋转模式")
|
||||
215
build/.111_staging/assets/scripts/Rotate_P_Script.py
Normal file
215
build/.111_staging/assets/scripts/Rotate_P_Script.py
Normal file
@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
旋转脚本 - 让对象持续旋转
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
|
||||
class RotatorScript(ScriptBase):
|
||||
"""旋转脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.rotation_speed_y = 30.0 # Y轴旋转速度 (度/秒)
|
||||
self.max_angle = 25.0 # 最大旋转角度(相对于初始角度)
|
||||
self.direction = 1
|
||||
self.current_offset = 0.0 # 当前相对于初始角度的偏移
|
||||
self.initial_angle = None # 模型的初始角度
|
||||
self.is_rotating = True # 是否正在旋转
|
||||
|
||||
# 机器人式停顿参数
|
||||
self.pause_duration = 0.5 # 停顿时间(秒)
|
||||
self.current_pause_time = 0.0 # 当前停顿计时
|
||||
self.is_paused = False # 是否正在停顿
|
||||
self.robot_mode = True # 是否启用机器人模式
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("机器人旋转脚本启动!")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"最大旋转角度: ±{self.max_angle}度")
|
||||
self.log(f"机器人模式: {'开启' if self.robot_mode else '关闭'}")
|
||||
if self.robot_mode:
|
||||
self.log(f"停顿时间: {self.pause_duration}秒")
|
||||
|
||||
# 记录模型的初始角度
|
||||
if self.gameObject:
|
||||
initial_hpr = self.gameObject.getHpr()
|
||||
self.initial_angle = initial_hpr.getY() # 记录Y轴的初始角度(Pitch)
|
||||
self.log(f"模型初始角度: {self.initial_angle}度")
|
||||
self.log(f"旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
else:
|
||||
self.log("⚠️ 无法获取游戏对象,使用默认初始角度0")
|
||||
self.initial_angle = 0.0
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新 - 机器人式旋转"""
|
||||
if not self.is_rotating or self.initial_angle is None:
|
||||
return
|
||||
|
||||
# 如果正在停顿中
|
||||
if self.is_paused:
|
||||
self.current_pause_time += dt
|
||||
if self.current_pause_time >= self.pause_duration:
|
||||
# 停顿结束,继续旋转
|
||||
self.is_paused = False
|
||||
self.current_pause_time = 0.0
|
||||
self.log(f"停顿结束,继续旋转,方向: {'正向' if self.direction > 0 else '反向'}")
|
||||
return
|
||||
|
||||
# 计算角度变化量
|
||||
delta_angle = self.rotation_speed_y * dt * self.direction
|
||||
self.current_offset += delta_angle
|
||||
|
||||
# 检查是否到达边界
|
||||
reached_boundary = False
|
||||
if self.current_offset > self.max_angle:
|
||||
self.current_offset = self.max_angle
|
||||
self.direction *= -1
|
||||
reached_boundary = True
|
||||
elif self.current_offset < -self.max_angle:
|
||||
self.current_offset = -self.max_angle
|
||||
self.direction *= -1
|
||||
reached_boundary = True
|
||||
|
||||
# 如果到达边界且启用机器人模式,开始停顿
|
||||
if reached_boundary and self.robot_mode:
|
||||
self.is_paused = True
|
||||
self.current_pause_time = 0.0
|
||||
self.log(f"到达边界 ({self.current_offset}°),开始停顿 {self.pause_duration}秒")
|
||||
|
||||
# 计算最终角度(初始角度 + 偏移量)
|
||||
final_angle = self.initial_angle + self.current_offset
|
||||
|
||||
# 设置新的旋转(只改变Y轴,保持其他不变)
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), final_angle, current_hpr.getZ())
|
||||
|
||||
# if not self.is_rotating:
|
||||
# return
|
||||
#
|
||||
# # 获取当前旋转并应用增量
|
||||
# current_hpr = self.gameObject.getHpr()
|
||||
# new_r = current_hpr.getZ() + self.rotation_speed_y * dt
|
||||
# self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), new_r)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("机器人旋转脚本停止")
|
||||
|
||||
# ==================== 机器人模式控制方法 ====================
|
||||
|
||||
def set_robot_mode(self, enabled=True):
|
||||
"""
|
||||
启用或禁用机器人模式
|
||||
|
||||
Args:
|
||||
enabled: 是否启用机器人模式
|
||||
"""
|
||||
self.robot_mode = enabled
|
||||
self.log(f"机器人模式: {'开启' if enabled else '关闭'}")
|
||||
if not enabled:
|
||||
self.is_paused = False # 如果禁用机器人模式,立即结束停顿
|
||||
|
||||
def set_pause_duration(self, duration):
|
||||
"""
|
||||
设置停顿时间
|
||||
|
||||
Args:
|
||||
duration: 停顿时间(秒)
|
||||
"""
|
||||
self.pause_duration = max(0.1, duration) # 最小0.1秒
|
||||
self.log(f"停顿时间已设置为: {self.pause_duration}秒")
|
||||
|
||||
def set_max_angle(self, new_max_angle):
|
||||
"""
|
||||
设置新的最大旋转角度
|
||||
|
||||
Args:
|
||||
new_max_angle: 新的最大角度值
|
||||
"""
|
||||
self.max_angle = new_max_angle
|
||||
self.log(f"最大旋转角度已设置为: ±{self.max_angle}度")
|
||||
if self.initial_angle is not None:
|
||||
self.log(f"新的旋转范围: {self.initial_angle - self.max_angle}° 到 {self.initial_angle + self.max_angle}°")
|
||||
|
||||
def set_rotation_speed(self, new_speed):
|
||||
"""
|
||||
设置新的旋转速度
|
||||
|
||||
Args:
|
||||
new_speed: 新的旋转速度(度/秒)
|
||||
"""
|
||||
self.rotation_speed_y = new_speed
|
||||
self.log(f"旋转速度已设置为: {self.rotation_speed_y}度/秒")
|
||||
|
||||
def pause_rotation(self):
|
||||
"""暂停旋转"""
|
||||
self.is_rotating = False
|
||||
self.log("旋转已暂停")
|
||||
|
||||
def resume_rotation(self):
|
||||
"""恢复旋转"""
|
||||
self.is_rotating = True
|
||||
self.is_paused = False # 同时结束停顿状态
|
||||
self.log("旋转已恢复")
|
||||
|
||||
def reset_to_initial_angle(self):
|
||||
"""重置到初始角度"""
|
||||
if self.initial_angle is not None and self.gameObject:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
self.gameObject.setHpr(current_hpr.getX(), self.initial_angle, current_hpr.getZ())
|
||||
self.current_offset = 0.0
|
||||
self.direction = 1
|
||||
self.is_paused = False
|
||||
self.current_pause_time = 0.0
|
||||
self.log(f"已重置到初始角度: {self.initial_angle}度")
|
||||
|
||||
def get_current_info(self):
|
||||
"""获取当前旋转信息"""
|
||||
if self.gameObject and self.initial_angle is not None:
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
current_angle = current_hpr.getY()
|
||||
self.log("=== 机器人旋转信息 ===")
|
||||
self.log(f"初始角度: {self.initial_angle}度")
|
||||
self.log(f"当前角度: {current_angle}度")
|
||||
self.log(f"偏移量: {self.current_offset}度")
|
||||
self.log(f"最大角度: ±{self.max_angle}度")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
self.log(f"旋转方向: {'正向' if self.direction > 0 else '反向'}")
|
||||
self.log(f"旋转状态: {'运行中' if self.is_rotating else '已暂停'}")
|
||||
self.log(f"机器人模式: {'开启' if self.robot_mode else '关闭'}")
|
||||
if self.robot_mode:
|
||||
self.log(f"停顿时间: {self.pause_duration}秒")
|
||||
self.log(f"当前状态: {'停顿中' if self.is_paused else '旋转中'}")
|
||||
if self.is_paused:
|
||||
remaining_time = self.pause_duration - self.current_pause_time
|
||||
self.log(f"剩余停顿时间: {remaining_time:.1f}秒")
|
||||
self.log("=== 信息结束 ===")
|
||||
else:
|
||||
self.log("无法获取旋转信息")
|
||||
|
||||
# ==================== 预设配置方法 ====================
|
||||
|
||||
def set_slow_robot_mode(self):
|
||||
"""预设:慢速机器人模式"""
|
||||
self.set_rotation_speed(15.0)
|
||||
self.set_pause_duration(1.0)
|
||||
self.set_robot_mode(True)
|
||||
self.log("已设置为慢速机器人模式")
|
||||
|
||||
def set_fast_robot_mode(self):
|
||||
"""预设:快速机器人模式"""
|
||||
self.set_rotation_speed(45.0)
|
||||
self.set_pause_duration(0.3)
|
||||
self.set_robot_mode(True)
|
||||
self.log("已设置为快速机器人模式")
|
||||
|
||||
def set_smooth_mode(self):
|
||||
"""预设:平滑模式(非机器人)"""
|
||||
self.set_robot_mode(False)
|
||||
self.set_rotation_speed(30.0)
|
||||
self.log("已设置为平滑旋转模式")
|
||||
56
build/.111_staging/assets/scripts/Rotate_R_Script.py
Normal file
56
build/.111_staging/assets/scripts/Rotate_R_Script.py
Normal file
@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
旋转脚本 - 让对象持续旋转
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
|
||||
class RotatorScript(ScriptBase):
|
||||
"""旋转脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.rotation_speed_y = 30.0 # Y轴旋转速度 (度/秒)
|
||||
self.max_angle = 15.0
|
||||
self.direction = 1
|
||||
self.current_angle = 0.0
|
||||
self.is_rotating = True # 是否正在旋转
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("旋转脚本启动!")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
|
||||
delta_angle = self.rotation_speed_y * dt * self.direction
|
||||
self.current_angle += delta_angle
|
||||
|
||||
# 如果超出角度范围,则反向
|
||||
if self.current_angle > self.max_angle:
|
||||
self.current_angle = self.max_angle
|
||||
self.direction *= -1
|
||||
elif self.current_angle < -self.max_angle:
|
||||
self.current_angle = -self.max_angle
|
||||
self.direction *= -1
|
||||
|
||||
# 设置新的旋转(只改变Z轴,保持其他不变)
|
||||
base_hpr = self.gameObject.getHpr()
|
||||
new_r = self.current_angle
|
||||
self.gameObject.setHpr(base_hpr.getX(), base_hpr.getY(), new_r)
|
||||
|
||||
# if not self.is_rotating:
|
||||
# return
|
||||
#
|
||||
# # 获取当前旋转并应用增量
|
||||
# current_hpr = self.gameObject.getHpr()
|
||||
# new_r = current_hpr.getZ() + self.rotation_speed_y * dt
|
||||
# self.gameObject.setHpr(current_hpr.getX(), current_hpr.getY(), new_r)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("旋转脚本停止")
|
||||
39
build/.111_staging/assets/scripts/RotatorScript.py
Normal file
39
build/.111_staging/assets/scripts/RotatorScript.py
Normal file
@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
旋转脚本 - 让对象持续旋转
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class RotatorScript(ScriptBase):
|
||||
"""旋转脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.rotation_speed_y = 30.0 # Y轴旋转速度 (度/秒)
|
||||
self.is_rotating = True # 是否正在旋转
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("旋转脚本启动!")
|
||||
self.log(f"旋转速度: {self.rotation_speed_y}度/秒")
|
||||
|
||||
def update(self, dt):
|
||||
# 检查 gameObject 是否存在且不为空
|
||||
if not self.gameObject or self.gameObject.isEmpty():
|
||||
print("RotatorScript: gameObject is empty or None, skipping update")
|
||||
return
|
||||
"""每帧更新"""
|
||||
if not self.is_rotating:
|
||||
return
|
||||
|
||||
# 获取当前旋转并应用增量
|
||||
current_hpr = self.gameObject.getHpr()
|
||||
new_h = current_hpr.getX() + self.rotation_speed_y * dt
|
||||
self.gameObject.setHpr(new_h, current_hpr.getY(), current_hpr.getZ())
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("旋转脚本停止")
|
||||
91
build/.111_staging/assets/scripts/ScalerScript.py
Normal file
91
build/.111_staging/assets/scripts/ScalerScript.py
Normal file
@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
缩放脚本 - 让对象产生呼吸般的缩放效果
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
import math
|
||||
|
||||
class ScalerScript(ScriptBase):
|
||||
"""缩放脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# 缩放参数
|
||||
self.base_scale = 1.0 # 基础缩放
|
||||
self.scale_amplitude = 0.3 # 缩放幅度
|
||||
self.scale_speed = 2.0 # 缩放速度 (周期/秒)
|
||||
self.uniform_scale = True # 是否统一缩放(所有轴)
|
||||
|
||||
# 内部变量
|
||||
self.time_accumulator = 0.0 # 时间累积器
|
||||
self.original_scale = None # 原始缩放
|
||||
self.is_scaling = True # 是否正在缩放
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("缩放脚本启动!")
|
||||
self.log(f"缩放参数: 基础={self.base_scale}, 幅度={self.scale_amplitude}, 速度={self.scale_speed}")
|
||||
|
||||
# 记录原始缩放
|
||||
self.original_scale = self.gameObject.getScale()
|
||||
self.log(f"原始缩放: {self.original_scale}")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if not self.is_scaling:
|
||||
return
|
||||
|
||||
# 累积时间
|
||||
self.time_accumulator += dt
|
||||
|
||||
# 计算正弦波缩放值
|
||||
sine_value = math.sin(self.time_accumulator * self.scale_speed * 2 * math.pi)
|
||||
scale_factor = self.base_scale + (self.scale_amplitude * sine_value)
|
||||
|
||||
# 应用缩放
|
||||
if self.uniform_scale:
|
||||
# 统一缩放
|
||||
self.gameObject.setScale(scale_factor)
|
||||
else:
|
||||
# 非统一缩放(仅Z轴)
|
||||
current_scale = self.gameObject.getScale()
|
||||
self.gameObject.setScale(current_scale.getX(), current_scale.getY(), scale_factor)
|
||||
|
||||
def set_scale_parameters(self, base=None, amplitude=None, speed=None, uniform=None):
|
||||
"""设置缩放参数"""
|
||||
if base is not None:
|
||||
self.base_scale = base
|
||||
if amplitude is not None:
|
||||
self.scale_amplitude = amplitude
|
||||
if speed is not None:
|
||||
self.scale_speed = speed
|
||||
if uniform is not None:
|
||||
self.uniform_scale = uniform
|
||||
|
||||
self.log(f"缩放参数更新: 基础={self.base_scale}, 幅度={self.scale_amplitude}, 速度={self.scale_speed}")
|
||||
|
||||
def toggle_scaling(self):
|
||||
"""切换缩放状态"""
|
||||
self.is_scaling = not self.is_scaling
|
||||
status = "恢复" if self.is_scaling else "暂停"
|
||||
self.log(f"缩放{status}")
|
||||
|
||||
def reset_scale(self):
|
||||
"""重置到原始缩放"""
|
||||
if self.original_scale:
|
||||
self.gameObject.setScale(self.original_scale)
|
||||
self.time_accumulator = 0.0
|
||||
self.log("缩放已重置到原始值")
|
||||
|
||||
def pulse_once(self):
|
||||
"""执行一次脉冲缩放"""
|
||||
self.time_accumulator = 0.0
|
||||
self.log("执行脉冲缩放")
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("缩放脚本停止")
|
||||
41
build/.111_staging/assets/scripts/TestMover.py
Normal file
41
build/.111_staging/assets/scripts/TestMover.py
Normal file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
TestMover - 移动脚本
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class Testmover(ScriptBase):
|
||||
"""移动脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.speed = 5.0 # 移动速度
|
||||
self.direction = [1, 0, 0] # 移动方向
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("移动脚本开始运行!")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
if self.transform:
|
||||
# 计算移动偏移
|
||||
offset_x = self.direction[0] * self.speed * dt
|
||||
offset_y = self.direction[1] * self.speed * dt
|
||||
offset_z = self.direction[2] * self.speed * dt
|
||||
|
||||
# 更新位置
|
||||
current_pos = self.transform.getPos()
|
||||
new_pos = (
|
||||
current_pos.x + offset_x,
|
||||
current_pos.y + offset_y,
|
||||
current_pos.z + offset_z
|
||||
)
|
||||
self.transform.setPos(*new_pos)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("移动脚本被销毁")
|
||||
28
build/.111_staging/assets/scripts/TestRotator.py
Normal file
28
build/.111_staging/assets/scripts/TestRotator.py
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
TestRotator - 自定义脚本
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class Testrotator(ScriptBase):
|
||||
"""自定义脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
# 在这里初始化您的变量
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("脚本开始运行!")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
# 在这里编写更新逻辑
|
||||
pass
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("脚本被销毁")
|
||||
28
build/.111_staging/assets/scripts/TestScaler.py
Normal file
28
build/.111_staging/assets/scripts/TestScaler.py
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
TestScaler - 自定义脚本
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class Testscaler(ScriptBase):
|
||||
"""自定义脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
# 在这里初始化您的变量
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("脚本开始运行!")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
# 在这里编写更新逻辑
|
||||
pass
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("脚本被销毁")
|
||||
28
build/.111_staging/assets/scripts/a.py
Normal file
28
build/.111_staging/assets/scripts/a.py
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
a - 自定义脚本
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class A(ScriptBase):
|
||||
"""自定义脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
# 在这里初始化您的变量
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("脚本开始运行!")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
# 在这里编写更新逻辑
|
||||
pass
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("脚本被销毁")
|
||||
47
build/.111_staging/assets/scripts/example_script.py
Normal file
47
build/.111_staging/assets/scripts/example_script.py
Normal file
@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
示例脚本 - 演示如何编写脚本
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class ExampleScript(ScriptBase):
|
||||
"""示例脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.counter = 0
|
||||
self.rotation_speed = 30.0 # 度/秒
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("示例脚本开始运行!")
|
||||
self.log(f"挂载到对象: {self.gameObject.getName()}")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
self.counter += 1
|
||||
|
||||
# 每60帧输出一次信息
|
||||
if self.counter % 60 == 0:
|
||||
self.log(f"运行了 {self.counter} 帧")
|
||||
|
||||
# 让对象旋转
|
||||
if self.transform:
|
||||
current_h = self.transform.getH()
|
||||
new_h = current_h + self.rotation_speed * dt
|
||||
self.transform.setH(new_h)
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("示例脚本被销毁")
|
||||
|
||||
def on_enable(self):
|
||||
"""脚本启用时调用"""
|
||||
self.log("示例脚本被启用")
|
||||
|
||||
def on_disable(self):
|
||||
"""脚本禁用时调用"""
|
||||
self.log("示例脚本被禁用")
|
||||
28
build/.111_staging/assets/scripts/test_quick_script.py
Normal file
28
build/.111_staging/assets/scripts/test_quick_script.py
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
test_quick_script - 自定义脚本
|
||||
"""
|
||||
|
||||
from core.script_system import ScriptBase
|
||||
|
||||
class TestQuickScript(ScriptBase):
|
||||
"""自定义脚本类"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
# 在这里初始化您的变量
|
||||
|
||||
def start(self):
|
||||
"""脚本开始时调用"""
|
||||
self.log("脚本开始运行!")
|
||||
|
||||
def update(self, dt):
|
||||
"""每帧更新"""
|
||||
# 在这里编写更新逻辑
|
||||
pass
|
||||
|
||||
def on_destroy(self):
|
||||
"""脚本销毁时调用"""
|
||||
self.log("脚本被销毁")
|
||||
534
build/.111_staging/source/main.py
Normal file
534
build/.111_staging/source/main.py
Normal file
@ -0,0 +1,534 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""EG packaged project runtime template."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from direct.actor.Actor import Actor
|
||||
from direct.showbase.ShowBase import ShowBase
|
||||
from panda3d.core import (
|
||||
CardMaker,
|
||||
Filename,
|
||||
MovieTexture,
|
||||
Point3,
|
||||
TextNode,
|
||||
Texture,
|
||||
TransparencyAttrib,
|
||||
Vec3,
|
||||
load_prc_file_data,
|
||||
)
|
||||
|
||||
PROJECT_NAME = "111"
|
||||
|
||||
|
||||
def _bootstrap_paths():
|
||||
if getattr(sys, "frozen", False):
|
||||
project_root = os.path.dirname(sys.executable)
|
||||
else:
|
||||
project_root = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
os.chdir(project_root)
|
||||
|
||||
search_paths = [
|
||||
project_root,
|
||||
os.path.join(project_root, "third_party"),
|
||||
os.path.join(project_root, "RenderPipelineFile"),
|
||||
]
|
||||
for path in search_paths:
|
||||
if os.path.isdir(path) and path not in sys.path:
|
||||
sys.path.insert(0, path)
|
||||
|
||||
return project_root
|
||||
|
||||
|
||||
PROJECT_ROOT = _bootstrap_paths()
|
||||
|
||||
|
||||
class MainApp(ShowBase):
|
||||
def __init__(self):
|
||||
self.project_path = PROJECT_ROOT
|
||||
self.gui_elements = []
|
||||
self.chinese_font = None
|
||||
self.script_manager = None
|
||||
self.render_pipeline = None
|
||||
|
||||
load_prc_file_data(
|
||||
"",
|
||||
f"""
|
||||
win-size 1380 750
|
||||
window-title {PROJECT_NAME}
|
||||
sync-video false
|
||||
show-frame-rate-meter false
|
||||
support-threads false
|
||||
""",
|
||||
)
|
||||
|
||||
from rpcore import RenderPipeline
|
||||
|
||||
self.render_pipeline = RenderPipeline()
|
||||
self.render_pipeline.pre_showbase_init()
|
||||
ShowBase.__init__(self)
|
||||
self.render_pipeline.create(self)
|
||||
self.render_pipeline._showbase.camera = self.render_pipeline._showbase.cam
|
||||
self.disableMouse()
|
||||
|
||||
self._load_font()
|
||||
self._init_script_manager()
|
||||
self.load_full_scene()
|
||||
self.load_gui_from_json()
|
||||
|
||||
def _init_script_manager(self):
|
||||
script_module = importlib.import_module("core.script_system")
|
||||
self.script_manager = script_module.ScriptManager(self)
|
||||
self.script_manager.hot_reload_enabled = False
|
||||
|
||||
scripts_dir = self.get_resource_path("scripts")
|
||||
if hasattr(self.script_manager, "set_scripts_directory"):
|
||||
self.script_manager.set_scripts_directory(
|
||||
scripts_dir,
|
||||
create=False,
|
||||
reload_scripts=False,
|
||||
)
|
||||
|
||||
self.script_manager.start_system()
|
||||
self.script_manager.set_hot_reload_enabled(False)
|
||||
|
||||
def _load_font(self):
|
||||
font_candidates = [
|
||||
"C:/Windows/Fonts/msyh.ttc",
|
||||
"C:/Windows/Fonts/simhei.ttf",
|
||||
]
|
||||
for font_path in font_candidates:
|
||||
if os.path.exists(font_path):
|
||||
try:
|
||||
self.chinese_font = self.loader.loadFont(font_path)
|
||||
if self.chinese_font:
|
||||
print(f"✓ 中文字体加载成功: {font_path}")
|
||||
return
|
||||
except Exception:
|
||||
continue
|
||||
print("⚠ 未找到可用中文字体,继续使用默认字体")
|
||||
|
||||
def get_chinese_font(self):
|
||||
return self.chinese_font
|
||||
|
||||
def get_resource_path(self, relative_path):
|
||||
return os.path.normpath(os.path.join(PROJECT_ROOT, relative_path))
|
||||
|
||||
def _resolve_media_path(self, relative_path):
|
||||
if not relative_path:
|
||||
return ""
|
||||
if os.path.isabs(relative_path):
|
||||
return relative_path
|
||||
return self.get_resource_path(relative_path.replace("/", os.sep))
|
||||
|
||||
def load_full_scene(self):
|
||||
scene_file = self.get_resource_path("scene.bam")
|
||||
if not os.path.exists(scene_file):
|
||||
print(f"⚠ 未找到场景文件: {scene_file}")
|
||||
return
|
||||
|
||||
scene = self.loader.loadModel(Filename.fromOsSpecific(scene_file))
|
||||
if not scene:
|
||||
print("⚠ 场景文件加载失败")
|
||||
return
|
||||
|
||||
scene.reparentTo(self.render)
|
||||
self.render_pipeline.prepare_scene(scene)
|
||||
self.process_scene_elements(scene)
|
||||
print("✓ 场景加载完成")
|
||||
|
||||
def process_scene_elements(self, root_node):
|
||||
processed_lights = set()
|
||||
|
||||
def walk(node_path):
|
||||
self._apply_user_visibility(node_path)
|
||||
|
||||
if node_path.hasTag("scripts_info"):
|
||||
try:
|
||||
scripts_info = json.loads(node_path.getTag("scripts_info"))
|
||||
self.process_scripts(node_path, scripts_info)
|
||||
except Exception as e:
|
||||
print(f"处理节点脚本失败 {node_path.getName()}: {e}")
|
||||
|
||||
if node_path.hasTag("light_type") and node_path not in processed_lights:
|
||||
if node_path.hasTag("is_auxiliary_light") and node_path.getTag("is_auxiliary_light").lower() == "true":
|
||||
return
|
||||
|
||||
light_type = node_path.getTag("light_type")
|
||||
if light_type == "spot_light":
|
||||
self._recreate_spot_light(node_path)
|
||||
elif light_type == "point_light":
|
||||
self._recreate_point_light(node_path)
|
||||
processed_lights.add(node_path)
|
||||
|
||||
for child in node_path.getChildren():
|
||||
walk(child)
|
||||
|
||||
walk(root_node)
|
||||
|
||||
def _apply_user_visibility(self, node_path):
|
||||
if not node_path.hasTag("user_visible"):
|
||||
return
|
||||
|
||||
user_visible = node_path.getTag("user_visible").lower() == "true"
|
||||
node_path.setPythonTag("user_visible", user_visible)
|
||||
if user_visible:
|
||||
node_path.show()
|
||||
else:
|
||||
node_path.hide()
|
||||
|
||||
def _recreate_spot_light(self, light_node):
|
||||
try:
|
||||
from rpcore import SpotLight
|
||||
|
||||
light = SpotLight()
|
||||
light.direction = Vec3(0, 0, -1)
|
||||
light.fov = float(light_node.getTag("light_fov")) if light_node.hasTag("light_fov") else 70.0
|
||||
light.energy = float(light_node.getTag("light_energy")) if light_node.hasTag("light_energy") else 5000.0
|
||||
light.radius = float(light_node.getTag("light_radius")) if light_node.hasTag("light_radius") else 1000.0
|
||||
light.casts_shadows = True
|
||||
light.shadow_map_resolution = 256
|
||||
light.setPos(light_node.getPos())
|
||||
self.render_pipeline.add_light(light)
|
||||
except Exception as e:
|
||||
print(f"创建聚光灯失败 {light_node.getName()}: {e}")
|
||||
|
||||
def _recreate_point_light(self, light_node):
|
||||
try:
|
||||
from rpcore import PointLight
|
||||
|
||||
light = PointLight()
|
||||
light.energy = float(light_node.getTag("light_energy")) if light_node.hasTag("light_energy") else 5000.0
|
||||
light.radius = float(light_node.getTag("light_radius")) if light_node.hasTag("light_radius") else 1000.0
|
||||
light.inner_radius = 0.4
|
||||
light.casts_shadows = True
|
||||
light.shadow_map_resolution = 256
|
||||
light.setPos(light_node.getPos())
|
||||
self.render_pipeline.add_light(light)
|
||||
except Exception as e:
|
||||
print(f"创建点光源失败 {light_node.getName()}: {e}")
|
||||
|
||||
def process_scripts(self, node_path, script_info_list):
|
||||
if not self.script_manager:
|
||||
return
|
||||
|
||||
for script_info in script_info_list or []:
|
||||
script_name = str(script_info.get("name", "") or "").strip()
|
||||
if not script_name:
|
||||
continue
|
||||
|
||||
try:
|
||||
if script_name not in self.script_manager.loader.script_classes:
|
||||
script_path = ""
|
||||
if hasattr(self.script_manager, "resolve_script_path"):
|
||||
script_path = self.script_manager.resolve_script_path(script_info)
|
||||
if script_path:
|
||||
self.script_manager.load_script_from_file(script_path)
|
||||
|
||||
script_component = self.script_manager.add_script_to_object(node_path, script_name)
|
||||
if script_component:
|
||||
print(f"✓ 脚本 {script_name} 已挂载到 {node_path.getName()}")
|
||||
else:
|
||||
print(f"⚠ 脚本 {script_name} 挂载失败")
|
||||
except Exception as e:
|
||||
print(f"挂载脚本失败 {script_name}: {e}")
|
||||
|
||||
def load_gui_from_json(self):
|
||||
gui_json_path = self.get_resource_path(os.path.join("gui", "gui_elements.json"))
|
||||
if not os.path.exists(gui_json_path):
|
||||
return
|
||||
|
||||
with open(gui_json_path, "r", encoding="utf-8") as f:
|
||||
content = f.read().strip()
|
||||
if not content:
|
||||
return
|
||||
|
||||
gui_data = json.loads(content)
|
||||
self.create_gui_elements(gui_data)
|
||||
|
||||
def create_gui_elements(self, element_data):
|
||||
processed_names = set()
|
||||
element_original_data = {}
|
||||
|
||||
for index, gui_info in enumerate(element_data or []):
|
||||
name = gui_info.get("name", f"gui_element_{index}")
|
||||
element_original_data[name] = {
|
||||
"scale": gui_info.get("scale", [1, 1, 1]),
|
||||
"position": gui_info.get("position", [0, 0, 0]),
|
||||
"parent_name": gui_info.get("parent_name"),
|
||||
}
|
||||
|
||||
for index, gui_info in enumerate(element_data or []):
|
||||
try:
|
||||
gui_type = gui_info.get("type", "unknown")
|
||||
name = gui_info.get("name", f"gui_element_{index}")
|
||||
if name in processed_names:
|
||||
continue
|
||||
processed_names.add(name)
|
||||
|
||||
position = list(gui_info.get("position", [0, 0, 0]))
|
||||
scale = list(gui_info.get("scale", [1, 1, 1]))
|
||||
parent_name = gui_info.get("parent_name")
|
||||
|
||||
if parent_name and parent_name in element_original_data:
|
||||
parent_scale = element_original_data[parent_name]["scale"]
|
||||
for i in range(min(len(position), len(parent_scale))):
|
||||
position[i] *= parent_scale[i]
|
||||
for i in range(min(len(scale), len(parent_scale))):
|
||||
scale[i] *= parent_scale[i]
|
||||
|
||||
text = gui_info.get("text", "")
|
||||
image_path = self._resolve_media_path(gui_info.get("image_path", ""))
|
||||
video_path = self._resolve_media_path(gui_info.get("video_path", ""))
|
||||
|
||||
new_element = None
|
||||
if gui_type == "3d_text":
|
||||
new_element = self.create_gui_3d_text(tuple(position), text, scale[0] if scale else 1.0)
|
||||
elif gui_type == "3d_image":
|
||||
new_element = self.create_gui_3d_image(tuple(position), image_path, scale)
|
||||
elif gui_type == "button":
|
||||
new_element = self.create_gui_button(tuple(position), text, scale[0] if scale else 1.0)
|
||||
elif gui_type == "label":
|
||||
new_element = self.create_gui_label(tuple(position), text, scale[0] if scale else 1.0)
|
||||
elif gui_type == "entry":
|
||||
new_element = self.create_gui_entry(tuple(position), text, scale[0] if scale else 1.0)
|
||||
elif gui_type == "2d_image":
|
||||
new_element = self.create_gui_2d_image(tuple(position), image_path, scale)
|
||||
elif gui_type == "video_screen":
|
||||
new_element = self.create_gui_video_screen(tuple(position), scale, video_path)
|
||||
elif gui_type == "2d_video_screen":
|
||||
new_element = self.create_gui_2d_video_screen(tuple(position), scale, video_path)
|
||||
|
||||
if not new_element:
|
||||
continue
|
||||
|
||||
self._apply_gui_metadata(new_element, gui_info, gui_type, text, image_path, video_path)
|
||||
self.gui_elements.append(new_element)
|
||||
|
||||
if gui_info.get("scripts"):
|
||||
self.process_scripts(new_element, gui_info["scripts"])
|
||||
except Exception as e:
|
||||
print(f"重建 GUI 元素失败: {e}")
|
||||
traceback.print_exc()
|
||||
|
||||
def _apply_gui_metadata(self, node, gui_info, gui_type, text, image_path, video_path):
|
||||
try:
|
||||
name = gui_info.get("name")
|
||||
if name and hasattr(node, "setName"):
|
||||
node.setName(name)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if hasattr(node, "setTag"):
|
||||
node.setTag("gui_type", gui_type)
|
||||
node.setTag("is_gui_element", "true")
|
||||
if text:
|
||||
node.setTag("gui_text", str(text))
|
||||
if image_path:
|
||||
node.setTag("gui_image_path", str(image_path))
|
||||
if video_path:
|
||||
node.setTag("video_path", str(video_path))
|
||||
for key, value in (gui_info.get("tags") or {}).items():
|
||||
try:
|
||||
node.setTag(str(key), str(value))
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
user_visible = bool(gui_info.get("user_visible", True))
|
||||
if hasattr(node, "setPythonTag"):
|
||||
node.setPythonTag("user_visible", user_visible)
|
||||
if hasattr(node, "show") and hasattr(node, "hide"):
|
||||
if user_visible:
|
||||
node.show()
|
||||
else:
|
||||
node.hide()
|
||||
|
||||
def create_gui_button(self, pos=(0, 0, 0), text="按钮", size=0.1):
|
||||
from direct.gui.DirectGui import DirectButton
|
||||
|
||||
return DirectButton(
|
||||
text=text,
|
||||
pos=(pos[0], pos[1], pos[2]),
|
||||
scale=size,
|
||||
frameColor=(0.2, 0.6, 0.8, 1),
|
||||
text_font=self.get_chinese_font() or None,
|
||||
rolloverSound=None,
|
||||
clickSound=None,
|
||||
parent=self.aspect2d,
|
||||
command=None,
|
||||
)
|
||||
|
||||
def create_gui_label(self, pos=(0, 0, 0), text="标签", size=0.08):
|
||||
from direct.gui.DirectGui import DirectLabel
|
||||
|
||||
return DirectLabel(
|
||||
text=text,
|
||||
pos=(pos[0], pos[1], pos[2]),
|
||||
scale=size,
|
||||
frameColor=(0, 0, 0, 0),
|
||||
text_fg=(1, 1, 1, 1),
|
||||
text_font=self.get_chinese_font() or None,
|
||||
text_align=TextNode.ACenter,
|
||||
text_mayChange=True,
|
||||
parent=self.aspect2d,
|
||||
)
|
||||
|
||||
def create_gui_entry(self, pos=(0, 0, 0), placeholder="输入文本...", size=0.08):
|
||||
from direct.gui.DirectGui import DirectEntry
|
||||
|
||||
return DirectEntry(
|
||||
text="",
|
||||
pos=(pos[0], pos[1], pos[2]),
|
||||
scale=size,
|
||||
command=self.on_gui_entry_submit,
|
||||
initialText=placeholder,
|
||||
numLines=1,
|
||||
width=12,
|
||||
focus=0,
|
||||
frameColor=(0, 0, 0, 0),
|
||||
text_fg=(1, 1, 1, 1),
|
||||
text_font=self.get_chinese_font() or None,
|
||||
text_align=TextNode.ACenter,
|
||||
text_mayChange=True,
|
||||
parent=self.aspect2d,
|
||||
rolloverSound=None,
|
||||
clickSound=None,
|
||||
suppressKeys=True,
|
||||
suppressMouse=True,
|
||||
)
|
||||
|
||||
def on_gui_entry_submit(self, text, *_args):
|
||||
print(f"GUI 输入框提交: {text}")
|
||||
|
||||
def create_gui_2d_image(self, pos=(0, 0, 0), image_path="", size=(1, 1, 1)):
|
||||
if isinstance(size, (list, tuple)) and len(size) >= 3:
|
||||
width_scale = float(size[0]) * 0.2
|
||||
height_scale = float(size[2]) * 0.2
|
||||
else:
|
||||
scalar = float(size) if isinstance(size, (int, float)) else 0.2
|
||||
width_scale = scalar * 0.1
|
||||
height_scale = width_scale
|
||||
|
||||
cm = CardMaker("gui_2d_image")
|
||||
cm.setFrame(-width_scale, width_scale, -height_scale, height_scale)
|
||||
image_node = self.aspect2d.attachNewNode(cm.generate())
|
||||
image_node.setPos(pos)
|
||||
image_node.setBin("fixed", 0)
|
||||
image_node.setDepthWrite(False)
|
||||
image_node.setDepthTest(False)
|
||||
image_node.setTransparency(TransparencyAttrib.MAlpha)
|
||||
if image_path:
|
||||
texture = self.loader.loadTexture(image_path)
|
||||
if texture:
|
||||
image_node.setTexture(texture, 1)
|
||||
return image_node
|
||||
|
||||
def create_gui_3d_text(self, pos=(0, 0, 0), text="3D文本", size=0.5):
|
||||
text_node = TextNode("gui_3d_text")
|
||||
text_node.setText(text)
|
||||
text_node.setAlign(TextNode.ACenter)
|
||||
if self.get_chinese_font():
|
||||
text_node.setFont(self.get_chinese_font())
|
||||
|
||||
text_np = self.render.attachNewNode(text_node)
|
||||
text_np.setPos(Vec3(pos[0], pos[1], pos[2]))
|
||||
text_np.setScale(size)
|
||||
text_np.setBin("fixed", 40)
|
||||
text_np.setDepthWrite(False)
|
||||
return text_np
|
||||
|
||||
def create_gui_3d_image(self, pos=(0, 0, 0), image_path="", size=(1, 1, 1)):
|
||||
if isinstance(size, (list, tuple)) and len(size) >= 3:
|
||||
width_scale = float(size[0])
|
||||
height_scale = float(size[2])
|
||||
else:
|
||||
width_scale = float(size) if isinstance(size, (int, float)) else 1.0
|
||||
height_scale = width_scale
|
||||
|
||||
cm = CardMaker("gui_3d_image")
|
||||
cm.setFrame(-width_scale, width_scale, -height_scale, height_scale)
|
||||
image_node = self.render.attachNewNode(cm.generate())
|
||||
image_node.setPos(pos)
|
||||
image_node.setTransparency(TransparencyAttrib.MAlpha)
|
||||
if image_path:
|
||||
texture = self.loader.loadTexture(image_path)
|
||||
if texture:
|
||||
image_node.setTexture(texture, 1)
|
||||
return image_node
|
||||
|
||||
def _load_movie_texture(self, name, video_path):
|
||||
if not video_path:
|
||||
return None
|
||||
movie_texture = MovieTexture(name)
|
||||
if not movie_texture.read(Filename.fromOsSpecific(video_path)):
|
||||
print(f"⚠ 无法加载视频: {video_path}")
|
||||
return None
|
||||
movie_texture.play()
|
||||
return movie_texture
|
||||
|
||||
def create_gui_video_screen(self, pos=(0, 0, 0), size=(1, 1, 1), video_path=""):
|
||||
if isinstance(size, (list, tuple)) and len(size) >= 3:
|
||||
width_scale = float(size[0])
|
||||
height_scale = float(size[2])
|
||||
else:
|
||||
width_scale = float(size) if isinstance(size, (int, float)) else 1.0
|
||||
height_scale = width_scale
|
||||
|
||||
cm = CardMaker("gui_video_screen")
|
||||
cm.setFrame(-width_scale, width_scale, -height_scale, height_scale)
|
||||
video_node = self.render.attachNewNode(cm.generate())
|
||||
video_node.setPos(pos)
|
||||
video_node.setTransparency(TransparencyAttrib.MAlpha)
|
||||
|
||||
movie_texture = self._load_movie_texture("gui_video_texture_3d", video_path)
|
||||
if movie_texture:
|
||||
video_node.setTexture(movie_texture, 1)
|
||||
return video_node
|
||||
|
||||
def create_gui_2d_video_screen(self, pos=(0, 0, 0), size=(1, 1, 1), video_path=""):
|
||||
if isinstance(size, (list, tuple)) and len(size) >= 3:
|
||||
width_scale = float(size[0]) * 0.2
|
||||
height_scale = float(size[2]) * 0.2
|
||||
else:
|
||||
scalar = float(size) if isinstance(size, (int, float)) else 0.2
|
||||
width_scale = scalar * 0.1
|
||||
height_scale = width_scale
|
||||
|
||||
cm = CardMaker("gui_2d_video_screen")
|
||||
cm.setFrame(-width_scale, width_scale, -height_scale, height_scale)
|
||||
video_node = self.aspect2d.attachNewNode(cm.generate())
|
||||
video_node.setPos(pos)
|
||||
video_node.setTransparency(TransparencyAttrib.MAlpha)
|
||||
video_node.setDepthWrite(False)
|
||||
video_node.setDepthTest(False)
|
||||
|
||||
movie_texture = self._load_movie_texture("gui_video_texture_2d", video_path)
|
||||
if movie_texture:
|
||||
video_node.setTexture(movie_texture, 1)
|
||||
return video_node
|
||||
|
||||
def play_model_animation(self):
|
||||
actors = self.render.findAllMatches("**/+ActorNode")
|
||||
for actor_np in actors:
|
||||
actor_node = actor_np.node()
|
||||
if isinstance(actor_node, Actor):
|
||||
anim_names = actor_node.getAnimNames()
|
||||
if anim_names:
|
||||
actor_node.loop(anim_names[0])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
app = MainApp()
|
||||
app.run()
|
||||
except Exception as e:
|
||||
print(f"应用程序启动失败: {e}")
|
||||
traceback.print_exc()
|
||||
@ -1,26 +1,40 @@
|
||||
"""
|
||||
Core package - 核心功能模块
|
||||
|
||||
包含引擎的核心功能:
|
||||
- world.py: 基础世界功能(相机、光照、地板等)
|
||||
- selection.py: 选择和变换系统
|
||||
- event_handler.py: 事件处理系统
|
||||
- tool_manager.py: 工具管理系统
|
||||
- script_system.py: 脚本系统
|
||||
"""
|
||||
|
||||
from .world import CoreWorld
|
||||
from .selection import SelectionSystem
|
||||
from .event_handler import EventHandler
|
||||
from .tool_manager import ToolManager
|
||||
from .script_system import ScriptManager, ScriptBase, ScriptComponent
|
||||
|
||||
__all__ = [
|
||||
'CoreWorld',
|
||||
'SelectionSystem',
|
||||
'EventHandler',
|
||||
'ToolManager',
|
||||
'ScriptManager',
|
||||
'ScriptBase',
|
||||
'ScriptComponent'
|
||||
]
|
||||
"""
|
||||
Core package - 核心功能模块
|
||||
|
||||
Keep package imports lazy so lightweight runtime contexts can import
|
||||
`core.script_system` without eagerly pulling in the editor stack.
|
||||
"""
|
||||
|
||||
from importlib import import_module
|
||||
|
||||
__all__ = [
|
||||
"CoreWorld",
|
||||
"SelectionSystem",
|
||||
"EventHandler",
|
||||
"ToolManager",
|
||||
"ScriptManager",
|
||||
"ScriptBase",
|
||||
"ScriptComponent",
|
||||
]
|
||||
|
||||
_LAZY_IMPORTS = {
|
||||
"CoreWorld": ("core.world", "CoreWorld"),
|
||||
"SelectionSystem": ("core.selection", "SelectionSystem"),
|
||||
"EventHandler": ("core.event_handler", "EventHandler"),
|
||||
"ToolManager": ("core.tool_manager", "ToolManager"),
|
||||
"ScriptManager": ("core.script_system", "ScriptManager"),
|
||||
"ScriptBase": ("core.script_system", "ScriptBase"),
|
||||
"ScriptComponent": ("core.script_system", "ScriptComponent"),
|
||||
}
|
||||
|
||||
|
||||
def __getattr__(name):
|
||||
if name not in _LAZY_IMPORTS:
|
||||
raise AttributeError(f"module 'core' has no attribute {name!r}")
|
||||
|
||||
module_name, attr_name = _LAZY_IMPORTS[name]
|
||||
module = import_module(module_name)
|
||||
value = getattr(module, attr_name)
|
||||
globals()[name] = value
|
||||
return value
|
||||
|
||||
|
||||
@ -266,6 +266,24 @@ class ScriptLoader:
|
||||
del self.script_classes[script_name]
|
||||
|
||||
print(f"✓ 脚本已卸载: {script_name}")
|
||||
|
||||
def clear(self, unload_components: bool = False):
|
||||
"""清空当前加载的脚本缓存。"""
|
||||
if unload_components:
|
||||
for script_name in list(self.loaded_modules.keys()):
|
||||
try:
|
||||
self.unload_script(script_name)
|
||||
except Exception as e:
|
||||
print(f"卸载脚本失败 {script_name}: {e}")
|
||||
else:
|
||||
for module in list(self.loaded_modules.values()):
|
||||
module_name = getattr(module, "__name__", "")
|
||||
if module_name and module_name in sys.modules:
|
||||
del sys.modules[module_name]
|
||||
|
||||
self.loaded_modules.clear()
|
||||
self.script_classes.clear()
|
||||
self.file_mtimes.clear()
|
||||
|
||||
def reload_script(self, script_path: str) -> Optional[type]:
|
||||
"""重新加载脚本(热重载)"""
|
||||
@ -313,7 +331,7 @@ class ScriptLoader:
|
||||
scripts_dir = self.script_manager.scripts_directory
|
||||
if os.path.exists(scripts_dir):
|
||||
for file_name in os.listdir(scripts_dir):
|
||||
if file_name.endswith('.py'):
|
||||
if file_name.endswith(('.py', '.pyc')):
|
||||
base_name = os.path.splitext(file_name)[0]
|
||||
if base_name == script_name:
|
||||
return os.path.join(scripts_dir, file_name)
|
||||
@ -418,7 +436,7 @@ class ScriptManager:
|
||||
self.script_templates: Dict[str, type] = {} # 脚本名 -> 脚本类
|
||||
|
||||
# 脚本目录
|
||||
self.scripts_directory = "scripts"
|
||||
self.scripts_directory = self._normalize_scripts_directory("scripts")
|
||||
self._ensure_scripts_directory()
|
||||
|
||||
# 热重载监控
|
||||
@ -426,6 +444,137 @@ class ScriptManager:
|
||||
self.hot_reload_task = None
|
||||
|
||||
print("✓ 脚本管理系统初始化完成")
|
||||
|
||||
def _normalize_scripts_directory(self, directory: str) -> str:
|
||||
directory = directory or "scripts"
|
||||
return os.path.normpath(os.path.abspath(directory))
|
||||
|
||||
def get_project_path(self) -> Optional[str]:
|
||||
project_manager = getattr(self.world, "project_manager", None)
|
||||
project_path = getattr(project_manager, "current_project_path", None)
|
||||
if project_path:
|
||||
return os.path.normpath(project_path)
|
||||
|
||||
project_path = getattr(self.world, "project_path", None)
|
||||
if project_path:
|
||||
return os.path.normpath(project_path)
|
||||
|
||||
return None
|
||||
|
||||
def get_project_scripts_directory(self, project_path: Optional[str] = None) -> Optional[str]:
|
||||
project_path = project_path or self.get_project_path()
|
||||
if not project_path:
|
||||
return None
|
||||
return os.path.normpath(os.path.join(project_path, "scripts"))
|
||||
|
||||
def get_script_relative_path(self, script_path: str) -> str:
|
||||
if not script_path:
|
||||
return ""
|
||||
|
||||
script_path = os.path.normpath(os.path.abspath(script_path))
|
||||
project_path = self.get_project_path()
|
||||
if not project_path:
|
||||
return ""
|
||||
|
||||
try:
|
||||
relative_path = os.path.relpath(script_path, project_path)
|
||||
except ValueError:
|
||||
return ""
|
||||
|
||||
if relative_path.startswith(".."):
|
||||
return ""
|
||||
|
||||
return relative_path.replace("\\", "/")
|
||||
|
||||
def resolve_script_path(self, script_info: Dict[str, Any]) -> str:
|
||||
if not isinstance(script_info, dict):
|
||||
return ""
|
||||
|
||||
project_path = self.get_project_path()
|
||||
candidates = []
|
||||
|
||||
for key in ("project_relative_path", "relative_path", "path", "file"):
|
||||
raw_value = str(script_info.get(key, "") or "").strip()
|
||||
if not raw_value:
|
||||
continue
|
||||
|
||||
normalized_value = raw_value.replace("/", os.sep)
|
||||
if os.path.isabs(normalized_value):
|
||||
candidates.append(os.path.normpath(normalized_value))
|
||||
continue
|
||||
|
||||
if project_path:
|
||||
candidates.append(os.path.normpath(os.path.join(project_path, normalized_value)))
|
||||
|
||||
candidates.append(os.path.normpath(os.path.join(self.scripts_directory, normalized_value)))
|
||||
|
||||
lower_value = normalized_value.lower()
|
||||
if not lower_value.endswith((".py", ".pyc")):
|
||||
candidates.append(os.path.normpath(os.path.join(self.scripts_directory, f"{normalized_value}.py")))
|
||||
candidates.append(os.path.normpath(os.path.join(self.scripts_directory, f"{normalized_value}.pyc")))
|
||||
elif lower_value.endswith(".py"):
|
||||
candidates.append(os.path.normpath(os.path.join(self.scripts_directory, f"{os.path.splitext(normalized_value)[0]}.pyc")))
|
||||
elif lower_value.endswith(".pyc"):
|
||||
candidates.append(os.path.normpath(os.path.join(self.scripts_directory, f"{os.path.splitext(normalized_value)[0]}.py")))
|
||||
|
||||
script_name = str(script_info.get("name", "") or "").strip()
|
||||
if script_name:
|
||||
candidates.append(os.path.normpath(os.path.join(self.scripts_directory, f"{script_name}.py")))
|
||||
candidates.append(os.path.normpath(os.path.join(self.scripts_directory, f"{script_name}.pyc")))
|
||||
|
||||
seen = set()
|
||||
for candidate in candidates:
|
||||
if not candidate or candidate in seen:
|
||||
continue
|
||||
seen.add(candidate)
|
||||
if os.path.exists(candidate):
|
||||
return candidate
|
||||
|
||||
if script_name:
|
||||
return self.loader.find_script_file(script_name) or ""
|
||||
|
||||
return ""
|
||||
|
||||
def build_script_reference(self, script_name: str, script_file: str = "") -> Dict[str, Any]:
|
||||
reference = {"name": script_name}
|
||||
|
||||
resolved_script_path = script_file or self.loader.find_script_file(script_name) or ""
|
||||
if resolved_script_path:
|
||||
resolved_script_path = os.path.normpath(os.path.abspath(resolved_script_path))
|
||||
relative_path = self.get_script_relative_path(resolved_script_path)
|
||||
if relative_path:
|
||||
reference["project_relative_path"] = relative_path
|
||||
reference["file"] = relative_path
|
||||
else:
|
||||
reference["file"] = resolved_script_path
|
||||
|
||||
return reference
|
||||
|
||||
def set_scripts_directory(
|
||||
self,
|
||||
directory: str,
|
||||
*,
|
||||
create: bool = True,
|
||||
reload_scripts: bool = True,
|
||||
) -> str:
|
||||
normalized_directory = self._normalize_scripts_directory(directory)
|
||||
if normalized_directory == self.scripts_directory and (
|
||||
os.path.exists(normalized_directory) or not create
|
||||
):
|
||||
return self.scripts_directory
|
||||
|
||||
self.scripts_directory = normalized_directory
|
||||
if create:
|
||||
self._ensure_scripts_directory()
|
||||
|
||||
self.loader.clear(unload_components=False)
|
||||
self.script_templates.clear()
|
||||
|
||||
if reload_scripts and os.path.exists(self.scripts_directory):
|
||||
self.load_all_scripts_from_directory()
|
||||
|
||||
print(f"✓ 当前脚本目录已切换到: {self.scripts_directory}")
|
||||
return self.scripts_directory
|
||||
|
||||
def _ensure_scripts_directory(self):
|
||||
"""确保脚本目录存在"""
|
||||
@ -550,6 +699,9 @@ class ExampleScript(ScriptBase):
|
||||
"""创建新的脚本文件"""
|
||||
script_base_name = os.path.splitext(script_name.strip())[0]
|
||||
script_path = os.path.join(self.scripts_directory, f"{script_base_name}.py")
|
||||
|
||||
if not os.path.exists(self.scripts_directory):
|
||||
os.makedirs(self.scripts_directory)
|
||||
|
||||
if os.path.exists(script_path):
|
||||
print(f"脚本文件已存在: {script_path}")
|
||||
@ -670,19 +822,32 @@ class {class_name}(ScriptBase):
|
||||
"""从目录加载所有脚本"""
|
||||
if directory is None:
|
||||
directory = self.scripts_directory
|
||||
else:
|
||||
directory = self._normalize_scripts_directory(directory)
|
||||
|
||||
if not os.path.exists(directory):
|
||||
print(f"脚本目录不存在: {directory}")
|
||||
return []
|
||||
|
||||
loaded_scripts = []
|
||||
for filename in os.listdir(directory):
|
||||
if filename.endswith('.py') and not filename.startswith('__'):
|
||||
script_path = os.path.join(directory, filename)
|
||||
script_class = self.load_script_from_file(script_path)
|
||||
if script_class:
|
||||
script_name = os.path.splitext(filename)[0]
|
||||
loaded_scripts.append(script_name)
|
||||
seen_script_names = set()
|
||||
for filename in sorted(os.listdir(directory)):
|
||||
if filename.startswith('__') or not filename.endswith(('.py', '.pyc')):
|
||||
continue
|
||||
|
||||
script_name = os.path.splitext(filename)[0]
|
||||
if script_name in seen_script_names:
|
||||
continue
|
||||
|
||||
preferred_path = os.path.join(directory, f"{script_name}.py")
|
||||
script_path = preferred_path if os.path.exists(preferred_path) else os.path.join(directory, filename)
|
||||
if not os.path.exists(script_path):
|
||||
continue
|
||||
|
||||
script_class = self.load_script_from_file(script_path)
|
||||
if script_class:
|
||||
loaded_scripts.append(script_name)
|
||||
seen_script_names.add(script_name)
|
||||
|
||||
print(f"✓ 从目录 {directory} 加载了 {len(loaded_scripts)} 个脚本")
|
||||
return loaded_scripts
|
||||
@ -773,13 +938,8 @@ class {class_name}(ScriptBase):
|
||||
script_info_list = []
|
||||
for script_component in remaining_scripts:
|
||||
script_name = script_component.script_name
|
||||
script_class = script_component.script_instance.__class__
|
||||
script_file = self.loader.find_script_file(script_name) or ""
|
||||
|
||||
script_info_list.append({
|
||||
"name": script_name,
|
||||
"file": script_file
|
||||
})
|
||||
script_info_list.append(self.build_script_reference(script_name, script_file))
|
||||
|
||||
import json
|
||||
game_object.setTag("has_scripts", "true")
|
||||
|
||||
36
imgui.ini
36
imgui.ini
@ -31,19 +31,19 @@ DockId=0x0000000D,0
|
||||
|
||||
[Window][场景树]
|
||||
Pos=0,20
|
||||
Size=274,1012
|
||||
Size=274,1084
|
||||
Collapsed=0
|
||||
DockId=0x00000007,0
|
||||
|
||||
[Window][属性面板]
|
||||
Pos=1527,20
|
||||
Size=393,1012
|
||||
Pos=1655,20
|
||||
Size=393,1084
|
||||
Collapsed=0
|
||||
DockId=0x00000002,0
|
||||
|
||||
[Window][控制台]
|
||||
Pos=276,632
|
||||
Size=1249,400
|
||||
Pos=276,704
|
||||
Size=1377,400
|
||||
Collapsed=0
|
||||
DockId=0x00000006,1
|
||||
|
||||
@ -60,7 +60,7 @@ Collapsed=0
|
||||
|
||||
[Window][WindowOverViewport_11111111]
|
||||
Pos=0,20
|
||||
Size=1920,1012
|
||||
Size=2048,1084
|
||||
Collapsed=0
|
||||
|
||||
[Window][测试窗口1]
|
||||
@ -84,12 +84,12 @@ Size=400,300
|
||||
Collapsed=0
|
||||
|
||||
[Window][选择路径]
|
||||
Pos=660,254
|
||||
Pos=724,302
|
||||
Size=600,500
|
||||
Collapsed=0
|
||||
|
||||
[Window][打开项目]
|
||||
Pos=710,304
|
||||
Pos=774,352
|
||||
Size=500,400
|
||||
Collapsed=0
|
||||
|
||||
@ -99,8 +99,8 @@ Size=600,500
|
||||
Collapsed=0
|
||||
|
||||
[Window][资源管理器]
|
||||
Pos=276,632
|
||||
Size=1249,400
|
||||
Pos=276,704
|
||||
Size=1377,400
|
||||
Collapsed=0
|
||||
DockId=0x00000006,0
|
||||
|
||||
@ -150,10 +150,9 @@ Size=101,226
|
||||
Collapsed=0
|
||||
|
||||
[Window][LUI编辑器]
|
||||
Pos=1690,20
|
||||
Size=358,748
|
||||
Pos=1675,295
|
||||
Size=358,569
|
||||
Collapsed=0
|
||||
DockId=0x00000005,2
|
||||
|
||||
[Window][LUI测试控制面板]
|
||||
Pos=6,10
|
||||
@ -207,18 +206,23 @@ Collapsed=0
|
||||
DockId=0x00000005,2
|
||||
|
||||
[Window][项目另存为]
|
||||
Pos=794,432
|
||||
Pos=1050,555
|
||||
Size=460,240
|
||||
Collapsed=0
|
||||
|
||||
[Window][打包项目]
|
||||
Pos=784,442
|
||||
Size=480,220
|
||||
Collapsed=0
|
||||
|
||||
[Docking][Data]
|
||||
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,20 Size=1920,1012 Split=X
|
||||
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,20 Size=2048,1084 Split=X
|
||||
DockNode ID=0x00000001 Parent=0x08BD597D SizeRef=1525,1012 Split=X
|
||||
DockNode ID=0x00000007 Parent=0x00000001 SizeRef=274,1084 Selected=0xE0015051
|
||||
DockNode ID=0x00000008 Parent=0x00000001 SizeRef=1249,1084 Split=Y
|
||||
DockNode ID=0x00000005 Parent=0x00000008 SizeRef=2048,610 Split=Y
|
||||
DockNode ID=0x0000000D Parent=0x00000005 SizeRef=1318,383 HiddenTabBar=1 Selected=0x43A39006
|
||||
DockNode ID=0x0000000E Parent=0x00000005 SizeRef=1318,363 CentralNode=1 Selected=0xE0015051
|
||||
DockNode ID=0x00000006 Parent=0x00000008 SizeRef=2048,400 Selected=0x3A2E05C3
|
||||
DockNode ID=0x00000006 Parent=0x00000008 SizeRef=2048,400 Selected=0x5428E753
|
||||
DockNode ID=0x00000002 Parent=0x08BD597D SizeRef=393,1012 Selected=0x5DB6FF37
|
||||
|
||||
|
||||
1
index_name.txt
Normal file
1
index_name.txt
Normal file
@ -0,0 +1 @@
|
||||
index-b2d982.boo
|
||||
3
main.py
3
main.py
@ -383,9 +383,11 @@ class MyWorld(PanelDelegates, CoreWorld):
|
||||
self.show_new_project_dialog = False
|
||||
self.show_open_project_dialog = False
|
||||
self.show_save_as_dialog = False
|
||||
self.show_build_project_dialog = False
|
||||
self.show_about_dialog = False
|
||||
self.save_as_project_name = ""
|
||||
self.save_as_project_path = ""
|
||||
self.build_output_path = ""
|
||||
|
||||
# 路径选择对话框状态
|
||||
self.show_path_browser = False
|
||||
@ -1003,6 +1005,7 @@ class MyWorld(PanelDelegates, CoreWorld):
|
||||
self._draw_new_project_dialog()
|
||||
self._draw_open_project_dialog()
|
||||
self._draw_save_as_project_dialog()
|
||||
self._draw_build_project_dialog()
|
||||
self._draw_path_browser()
|
||||
self._draw_import_dialog()
|
||||
|
||||
|
||||
@ -4,6 +4,8 @@ import json
|
||||
import datetime
|
||||
import subprocess
|
||||
import shutil
|
||||
import importlib.util
|
||||
import py_compile
|
||||
|
||||
class ProjectManager:
|
||||
|
||||
@ -13,6 +15,58 @@ class ProjectManager:
|
||||
self.project_config = None
|
||||
|
||||
print("✓ 项目管理系统初始化完成")
|
||||
|
||||
def _get_repo_root(self):
|
||||
return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
def get_project_scripts_dir(self, project_path=None):
|
||||
project_path = os.path.normpath(project_path or self.current_project_path or "")
|
||||
if not project_path:
|
||||
return ""
|
||||
return os.path.join(project_path, "scripts")
|
||||
|
||||
def _ensure_project_scripts_dir(self, project_path):
|
||||
scripts_dir = self.get_project_scripts_dir(project_path)
|
||||
if scripts_dir:
|
||||
os.makedirs(scripts_dir, exist_ok=True)
|
||||
return scripts_dir
|
||||
|
||||
def _sync_project_script_manager(self, project_path, reload_scripts=True):
|
||||
script_manager = getattr(self.world, "script_manager", None)
|
||||
if not script_manager:
|
||||
return ""
|
||||
|
||||
scripts_dir = self._ensure_project_scripts_dir(project_path)
|
||||
script_manager.set_scripts_directory(
|
||||
scripts_dir,
|
||||
create=True,
|
||||
reload_scripts=reload_scripts,
|
||||
)
|
||||
return scripts_dir
|
||||
|
||||
def _restore_project_context(self, project_path, project_config, reload_scripts=True):
|
||||
normalized_project_path = os.path.normpath(project_path) if project_path else None
|
||||
self.current_project_path = normalized_project_path
|
||||
self.project_config = project_config
|
||||
|
||||
script_manager = getattr(self.world, "script_manager", None)
|
||||
if not script_manager:
|
||||
return
|
||||
|
||||
if normalized_project_path:
|
||||
self._sync_project_script_manager(normalized_project_path, reload_scripts=reload_scripts)
|
||||
else:
|
||||
script_manager.set_scripts_directory(
|
||||
"scripts",
|
||||
create=True,
|
||||
reload_scripts=reload_scripts,
|
||||
)
|
||||
|
||||
def _sanitize_build_name(self, project_name):
|
||||
invalid_chars = '<>:"/\\|?*'
|
||||
safe_name = "".join("_" if char in invalid_chars else char for char in str(project_name or "").strip())
|
||||
safe_name = safe_name.rstrip(". ")
|
||||
return safe_name or "EGProject"
|
||||
|
||||
# ==================== 项目生命周期管理 ====================
|
||||
|
||||
@ -41,6 +95,7 @@ class ProjectManager:
|
||||
os.makedirs(os.path.join(full_project_path, "textures")) # 贴图文件夹
|
||||
scenes_path = os.path.join(full_project_path, "scenes") # 场景文件夹
|
||||
os.makedirs(scenes_path)
|
||||
self._ensure_project_scripts_dir(full_project_path)
|
||||
|
||||
# 创建项目配置文件
|
||||
project_config = {
|
||||
@ -61,9 +116,14 @@ class ProjectManager:
|
||||
# 清空当前场景
|
||||
self._clearCurrentScene()
|
||||
|
||||
# 更新项目状态,确保后续保存脚本元数据时能拿到项目路径
|
||||
self.current_project_path = full_project_path
|
||||
self.project_config = project_config
|
||||
self._sync_project_script_manager(full_project_path, reload_scripts=True)
|
||||
|
||||
# 自动保存初始场景
|
||||
scene_file = os.path.join(scenes_path, "scene.bam")
|
||||
if self.world.scene_manager.saveScene(scene_file, project_path):
|
||||
if self.world.scene_manager.saveScene(scene_file, full_project_path):
|
||||
# 更新配置文件中的场景路径
|
||||
project_config["scene_file"] = os.path.relpath(scene_file, full_project_path)
|
||||
with open(config_file, "w", encoding="utf-8") as f:
|
||||
@ -71,10 +131,6 @@ class ProjectManager:
|
||||
print(f"初始场景已保存到: {scene_file}")
|
||||
else:
|
||||
print("初始场景保存失败")
|
||||
|
||||
# 更新项目状态
|
||||
self.current_project_path = full_project_path
|
||||
self.project_config = project_config
|
||||
|
||||
print(f"项目 '{project_name}' 创建成功!")
|
||||
return True
|
||||
@ -113,6 +169,13 @@ class ProjectManager:
|
||||
project_config = json.load(f)
|
||||
# print(f"[DEBUG] 项目配置读取成功: {project_config.get('name', 'Unknown')}")
|
||||
|
||||
previous_project_path = self.current_project_path
|
||||
previous_project_config = self.project_config
|
||||
|
||||
self.current_project_path = os.path.normpath(project_path)
|
||||
self.project_config = project_config
|
||||
self._sync_project_script_manager(self.current_project_path, reload_scripts=True)
|
||||
|
||||
# 检查场景文件
|
||||
scene_file = os.path.join(project_path, "scenes", "scene.bam")
|
||||
# print(f"[DEBUG] 场景文件路径: {scene_file}")
|
||||
@ -129,10 +192,20 @@ class ProjectManager:
|
||||
# 检查world的基本状态
|
||||
if not hasattr(self.world, 'render') or self.world.render is None:
|
||||
# print(f"[DEBUG] 错误: world.render不存在或为None")
|
||||
self._restore_project_context(
|
||||
previous_project_path,
|
||||
previous_project_config,
|
||||
reload_scripts=True,
|
||||
)
|
||||
return False
|
||||
|
||||
if not hasattr(self.world, 'loader') or self.world.loader is None:
|
||||
# print(f"[DEBUG] 错误: world.loader不存在或为None")
|
||||
self._restore_project_context(
|
||||
previous_project_path,
|
||||
previous_project_config,
|
||||
reload_scripts=True,
|
||||
)
|
||||
return False
|
||||
|
||||
# 清理可能的残留状态
|
||||
@ -154,17 +227,32 @@ class ProjectManager:
|
||||
# print(f"[DEBUG] 验证BAM文件完整性...")
|
||||
if os.path.getsize(scene_file) == 0:
|
||||
# print(f"[DEBUG] 错误: BAM文件为空")
|
||||
self._restore_project_context(
|
||||
previous_project_path,
|
||||
previous_project_config,
|
||||
reload_scripts=True,
|
||||
)
|
||||
return False
|
||||
|
||||
# 检查文件权限
|
||||
if not os.access(scene_file, os.R_OK):
|
||||
# print(f"[DEBUG] 错误: BAM文件不可读")
|
||||
self._restore_project_context(
|
||||
previous_project_path,
|
||||
previous_project_config,
|
||||
reload_scripts=True,
|
||||
)
|
||||
return False
|
||||
|
||||
# print(f"[DEBUG] BAM文件验证通过")
|
||||
|
||||
except Exception as e:
|
||||
# print(f"[DEBUG] 清理状态时发生异常: {e}")
|
||||
self._restore_project_context(
|
||||
previous_project_path,
|
||||
previous_project_config,
|
||||
reload_scripts=True,
|
||||
)
|
||||
return False
|
||||
|
||||
if self.world.scene_manager.loadScene(scene_file):
|
||||
@ -173,6 +261,11 @@ class ProjectManager:
|
||||
project_config["scene_file"] = os.path.relpath(scene_file, project_path)
|
||||
else:
|
||||
# print(f"[DEBUG] 场景加载失败")
|
||||
self._restore_project_context(
|
||||
previous_project_path,
|
||||
previous_project_config,
|
||||
reload_scripts=True,
|
||||
)
|
||||
return False
|
||||
else:
|
||||
# print(f"[DEBUG] 场景文件不存在,跳过场景加载")
|
||||
@ -183,7 +276,7 @@ class ProjectManager:
|
||||
json.dump(project_config, f, ensure_ascii=False, indent=4)
|
||||
|
||||
# 更新项目状态
|
||||
self.current_project_path = project_path
|
||||
self.current_project_path = os.path.normpath(project_path)
|
||||
self.project_config = project_config
|
||||
|
||||
# print(f"[DEBUG] ===== 项目打开成功: {project_path} =====")
|
||||
@ -191,6 +284,11 @@ class ProjectManager:
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self._restore_project_context(
|
||||
locals().get("previous_project_path"),
|
||||
locals().get("previous_project_config"),
|
||||
reload_scripts=True,
|
||||
)
|
||||
# print(f"[DEBUG] ===== 项目打开失败 =====")
|
||||
print(f"加载项目时发生错误:{str(e)}")
|
||||
import traceback
|
||||
@ -209,6 +307,10 @@ class ProjectManager:
|
||||
try:
|
||||
if not project_path:
|
||||
return False
|
||||
|
||||
previous_project_path = self.current_project_path
|
||||
previous_project_config = self.project_config
|
||||
|
||||
# 检查是否是有效的项目文件夹
|
||||
config_file = os.path.join(project_path, "project.json")
|
||||
if not os.path.exists(config_file):
|
||||
@ -219,6 +321,10 @@ class ProjectManager:
|
||||
with open(config_file, "r", encoding="utf-8") as f:
|
||||
project_config = json.load(f)
|
||||
|
||||
self.current_project_path = os.path.normpath(project_path)
|
||||
self.project_config = project_config
|
||||
self._sync_project_script_manager(self.current_project_path, reload_scripts=True)
|
||||
|
||||
# 检查场景文件
|
||||
scene_file = os.path.join(project_path, "scenes", "scene.bam")
|
||||
if os.path.exists(scene_file):
|
||||
@ -226,19 +332,31 @@ class ProjectManager:
|
||||
if self.world.scene_manager.loadScene(scene_file):
|
||||
# 更新项目配置
|
||||
project_config["scene_file"] = os.path.relpath(scene_file, project_path)
|
||||
else:
|
||||
self._restore_project_context(
|
||||
previous_project_path,
|
||||
previous_project_config,
|
||||
reload_scripts=True,
|
||||
)
|
||||
return False
|
||||
|
||||
project_config["last_modified"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
with open(config_file, "w", encoding="utf-8") as f:
|
||||
json.dump(project_config, f, ensure_ascii=False, indent=4)
|
||||
|
||||
# 更新项目状态
|
||||
self.current_project_path = project_path
|
||||
self.current_project_path = os.path.normpath(project_path)
|
||||
self.project_config = project_config
|
||||
|
||||
print(f"项目 '{project_path}' 加载成功!")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self._restore_project_context(
|
||||
locals().get("previous_project_path"),
|
||||
locals().get("previous_project_config"),
|
||||
reload_scripts=True,
|
||||
)
|
||||
error_msg = f"加载项目时发生错误:{str(e)}"
|
||||
print(error_msg)
|
||||
return False
|
||||
@ -331,104 +449,270 @@ class ProjectManager:
|
||||
# ==================== 项目打包功能 ====================
|
||||
|
||||
def buildPackage(self, build_dir):
|
||||
"""打包项目为可执行文件 - 按照Panda3D官方标准方法
|
||||
|
||||
Args:
|
||||
build_dir: 打包输出目录
|
||||
|
||||
Returns:
|
||||
bool: 打包是否成功
|
||||
"""
|
||||
"""将当前项目打包为最终运行程序。"""
|
||||
try:
|
||||
# 检查是否有当前项目路径
|
||||
if not self.current_project_path:
|
||||
print("错误: 请先创建或打开一个项目!")
|
||||
return False
|
||||
|
||||
project_path = self.current_project_path
|
||||
scenes_path = os.path.join(project_path, "scenes")
|
||||
scene_file = os.path.join(scenes_path, "scene.bam")
|
||||
|
||||
# 检查场景文件是否存在
|
||||
if not os.path.exists(scene_file):
|
||||
print("错误: 请先保存场景!")
|
||||
return False
|
||||
|
||||
if hasattr(self.world,'selection') and self.world.selection:
|
||||
self.world.selection.clearSelection()
|
||||
print("已取消场景中的物体选中状态")
|
||||
|
||||
if self.world.scene_manager.saveScene(scene_file, project_path):
|
||||
print("场景保存成功")
|
||||
config_file = os.path.join(project_path,"project.json")
|
||||
if os.path.exists(config_file):
|
||||
with open(config_file,"r",encoding="utf-8") as f:
|
||||
project_config = json.load(f)
|
||||
|
||||
project_config["last_modified"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
project_config["scene_file"] = os.path.relpath(scene_file,project_path)
|
||||
|
||||
with open(config_file,"w",encoding = "utf-8") as f:
|
||||
json.dump(project_config,f,ensure_ascii = False,indent=4)
|
||||
|
||||
self.project_config = project_config
|
||||
|
||||
project_name = os.path.basename(project_path)
|
||||
else:
|
||||
print("错误: 保存场景失败!")
|
||||
return False
|
||||
project_path = os.path.normpath(self.current_project_path)
|
||||
project_display_name = (
|
||||
(self.project_config or {}).get("name")
|
||||
or os.path.basename(project_path)
|
||||
or "EGProject"
|
||||
)
|
||||
project_name = self._sanitize_build_name(project_display_name)
|
||||
|
||||
if not build_dir:
|
||||
print("错误: 请指定打包输出目录!")
|
||||
return False
|
||||
|
||||
# 创建构建目录
|
||||
build_dir = os.path.join(build_dir, "build")
|
||||
|
||||
if not os.path.exists(build_dir):
|
||||
os.makedirs(build_dir)
|
||||
|
||||
# 创建标准的打包文件
|
||||
self._createStandardBuildFiles(build_dir, project_path, scene_file)
|
||||
|
||||
# 执行打包命令
|
||||
success = self._executeStandardBuild(build_dir)
|
||||
|
||||
if success:
|
||||
# 根据操作系统创建对应的启动脚本文件
|
||||
try:
|
||||
import stat
|
||||
# 检查操作系统类型
|
||||
if os.name == 'nt': # Windows系统
|
||||
run_bat_path = os.path.join(build_dir, "run.bat")
|
||||
with open(run_bat_path, "w") as f:
|
||||
f.write("@echo off\n")
|
||||
f.write("python Start_Run.py %*\n")
|
||||
else: # Unix-like系统 (Linux, macOS等)
|
||||
run_sh_path = os.path.join(build_dir, "run.sh")
|
||||
with open(run_sh_path, "w") as f:
|
||||
f.write("#!/bin/bash\n")
|
||||
f.write("python3.11 Start_Run.py \"$@\"\n")
|
||||
|
||||
# 为Unix-like系统添加执行权限
|
||||
st = os.stat(run_sh_path)
|
||||
os.chmod(run_sh_path, st.st_mode | stat.S_IEXEC)
|
||||
except Exception as e:
|
||||
print(f"创建启动脚本文件失败: {str(e)}")
|
||||
|
||||
print("打包完成!可执行文件在 build 目录中。")
|
||||
return True
|
||||
else:
|
||||
scene_file = os.path.join(project_path, "scenes", "scene.bam")
|
||||
if not os.path.exists(scene_file):
|
||||
print("错误: 请先保存场景!")
|
||||
return False
|
||||
|
||||
if hasattr(self.world, "selection") and self.world.selection:
|
||||
self.world.selection.clearSelection()
|
||||
print("已取消场景中的物体选中状态")
|
||||
|
||||
self._sync_project_script_manager(project_path, reload_scripts=True)
|
||||
|
||||
if not self.saveProject():
|
||||
print("错误: 保存场景失败!")
|
||||
return False
|
||||
|
||||
output_root = os.path.normpath(build_dir)
|
||||
staging_root = os.path.join(output_root, f".{project_name}_staging")
|
||||
source_root = os.path.join(staging_root, "source")
|
||||
assets_root = os.path.join(staging_root, "assets")
|
||||
dist_dir = os.path.join(output_root, project_name)
|
||||
|
||||
if os.path.exists(staging_root):
|
||||
shutil.rmtree(staging_root)
|
||||
os.makedirs(source_root, exist_ok=True)
|
||||
os.makedirs(assets_root, exist_ok=True)
|
||||
|
||||
if os.path.exists(dist_dir):
|
||||
shutil.rmtree(dist_dir)
|
||||
|
||||
shutil.copy2(scene_file, os.path.join(assets_root, "scene.bam"))
|
||||
self.copy_folder(os.path.join(project_path, "scenes", "resources"), assets_root)
|
||||
self._merge_folder_contents(
|
||||
os.path.join(project_path, "Resources"),
|
||||
os.path.join(assets_root, "resources"),
|
||||
)
|
||||
if not self._saveGUIElementsToJSON(assets_root, project_path):
|
||||
print("错误: 导出 GUI 数据失败!")
|
||||
return False
|
||||
self._saveCameraStateToJSON(assets_root)
|
||||
self._copyScriptsToBuild(assets_root, project_path)
|
||||
self._copyRenderPipelineRuntime(assets_root)
|
||||
|
||||
runtime_entry = self._createProjectRuntimeEntry(source_root, project_display_name)
|
||||
if not runtime_entry:
|
||||
print("错误: 生成项目运行时入口失败")
|
||||
return False
|
||||
|
||||
success = self._executeProjectBuild(
|
||||
source_root=source_root,
|
||||
assets_root=assets_root,
|
||||
build_root=output_root,
|
||||
project_name=project_name,
|
||||
)
|
||||
if not success:
|
||||
return False
|
||||
|
||||
if os.path.exists(staging_root):
|
||||
shutil.rmtree(staging_root, ignore_errors=True)
|
||||
|
||||
exe_path = os.path.join(dist_dir, f"{project_name}.exe")
|
||||
print(f"打包完成!项目运行程序: {exe_path}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"打包过程出错:{str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
def _merge_folder_contents(self, source_folder, destination_folder):
|
||||
"""将 source_folder 的内容合并到 destination_folder。"""
|
||||
if not source_folder or not os.path.exists(source_folder):
|
||||
return False
|
||||
|
||||
os.makedirs(destination_folder, exist_ok=True)
|
||||
for root, _, files in os.walk(source_folder):
|
||||
rel_root = os.path.relpath(root, source_folder)
|
||||
target_root = destination_folder if rel_root == "." else os.path.join(destination_folder, rel_root)
|
||||
os.makedirs(target_root, exist_ok=True)
|
||||
for file_name in files:
|
||||
source_file = os.path.join(root, file_name)
|
||||
target_file = os.path.join(target_root, file_name)
|
||||
shutil.copy2(source_file, target_file)
|
||||
return True
|
||||
|
||||
def _load_runtime_template(self):
|
||||
template_path = os.path.join(self._get_repo_root(), "templates", "main_template.py")
|
||||
with open(template_path, "r", encoding="utf-8") as f:
|
||||
return f.read()
|
||||
|
||||
def _createProjectRuntimeEntry(self, source_root, project_name):
|
||||
try:
|
||||
template_content = self._load_runtime_template()
|
||||
safe_project_name = project_name.replace("\\", "\\\\").replace('"', '\\"')
|
||||
runtime_source = template_content.replace("__EG_PROJECT_NAME__", safe_project_name)
|
||||
runtime_entry = os.path.join(source_root, "main.py")
|
||||
with open(runtime_entry, "w", encoding="utf-8") as f:
|
||||
f.write(runtime_source)
|
||||
return runtime_entry
|
||||
except Exception as e:
|
||||
print(f"创建项目运行时入口失败: {e}")
|
||||
return ""
|
||||
|
||||
def _executeProjectBuild(self, source_root, assets_root, build_root, project_name):
|
||||
repo_root = self._get_repo_root()
|
||||
work_root = os.path.join(build_root, f".{project_name}_work")
|
||||
spec_root = os.path.join(build_root, f".{project_name}_spec")
|
||||
|
||||
for directory in (work_root, spec_root):
|
||||
if os.path.exists(directory):
|
||||
shutil.rmtree(directory)
|
||||
os.makedirs(directory, exist_ok=True)
|
||||
|
||||
pyinstaller_runner = None
|
||||
pyinstaller_candidates = [
|
||||
[sys.executable, "-m", "PyInstaller"],
|
||||
[sys.executable, "-m", "pyinstaller"],
|
||||
["pyinstaller"],
|
||||
]
|
||||
for candidate in pyinstaller_candidates:
|
||||
pyinstaller_probe = subprocess.run(
|
||||
[*candidate, "--version"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
if pyinstaller_probe.returncode == 0:
|
||||
pyinstaller_runner = candidate
|
||||
break
|
||||
|
||||
if not pyinstaller_runner:
|
||||
print("错误: 当前环境未安装 PyInstaller,无法执行项目打包。")
|
||||
return False
|
||||
|
||||
sep = ";" if os.name == "nt" else ":"
|
||||
command = [
|
||||
*pyinstaller_runner,
|
||||
"--noconfirm",
|
||||
"--clean",
|
||||
"--windowed",
|
||||
"--name",
|
||||
project_name,
|
||||
"--distpath",
|
||||
build_root,
|
||||
"--workpath",
|
||||
work_root,
|
||||
"--specpath",
|
||||
spec_root,
|
||||
"--paths",
|
||||
source_root,
|
||||
"--paths",
|
||||
repo_root,
|
||||
"--paths",
|
||||
os.path.join(repo_root, "RenderPipelineFile"),
|
||||
"--exclude-module",
|
||||
"imgui_bundle",
|
||||
"--exclude-module",
|
||||
"p3dimgui",
|
||||
"--hidden-import",
|
||||
"core",
|
||||
"--hidden-import",
|
||||
"core.script_system",
|
||||
"--hidden-import",
|
||||
"core.CustomMouseController",
|
||||
"--hidden-import",
|
||||
"ssbo_component.runtime_importer",
|
||||
"--hidden-import",
|
||||
"ssbo_component.ssbo_controller",
|
||||
"--hidden-import",
|
||||
"rpcore",
|
||||
"--collect-submodules",
|
||||
"rpcore",
|
||||
"--collect-submodules",
|
||||
"rpplugins",
|
||||
"--collect-submodules",
|
||||
"rplibs",
|
||||
]
|
||||
|
||||
panda_binary_dir = self._get_panda3d_binary_dir()
|
||||
panda_display_binaries = [
|
||||
"libpandagl.dll",
|
||||
"libp3windisplay.dll",
|
||||
"libpandadx9.dll",
|
||||
"libp3tinydisplay.dll",
|
||||
"cgGL.dll",
|
||||
"cgD3D9.dll",
|
||||
"d3dx9_43.dll",
|
||||
]
|
||||
if panda_binary_dir:
|
||||
for binary_name in panda_display_binaries:
|
||||
binary_path = os.path.join(panda_binary_dir, binary_name)
|
||||
if os.path.exists(binary_path):
|
||||
command.extend(["--add-binary", f"{binary_path}{sep}."])
|
||||
|
||||
data_mappings = [
|
||||
(os.path.join(assets_root, "scene.bam"), "."),
|
||||
(os.path.join(assets_root, "camera_state.json"), "."),
|
||||
(os.path.join(assets_root, "gui"), "gui"),
|
||||
(os.path.join(assets_root, "resources"), "resources"),
|
||||
(os.path.join(assets_root, "scripts"), "scripts"),
|
||||
(os.path.join(assets_root, "RenderPipelineFile"), "RenderPipelineFile"),
|
||||
]
|
||||
|
||||
for source_path, target_path in data_mappings:
|
||||
if os.path.exists(source_path):
|
||||
command.extend(["--add-data", f"{source_path}{sep}{target_path}"])
|
||||
|
||||
command.append(os.path.join(source_root, "main.py"))
|
||||
|
||||
result = subprocess.run(
|
||||
command,
|
||||
cwd=source_root,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
print("项目打包失败。")
|
||||
output = (result.stdout or "") + "\n" + (result.stderr or "")
|
||||
print(output[-4000:])
|
||||
return False
|
||||
|
||||
for directory in (work_root, spec_root):
|
||||
if os.path.exists(directory):
|
||||
shutil.rmtree(directory, ignore_errors=True)
|
||||
|
||||
print(f"✓ 项目已打包到: {os.path.join(build_root, project_name)}")
|
||||
return True
|
||||
|
||||
def _get_panda3d_binary_dir(self):
|
||||
try:
|
||||
panda3d_spec = importlib.util.find_spec("panda3d.core")
|
||||
if panda3d_spec and panda3d_spec.origin:
|
||||
panda_package_dir = os.path.dirname(os.path.dirname(os.path.abspath(panda3d_spec.origin)))
|
||||
candidate_dirs = [
|
||||
os.path.join(panda_package_dir, "bin"),
|
||||
os.path.join(os.path.dirname(panda_package_dir), "bin"),
|
||||
]
|
||||
for candidate_dir in candidate_dirs:
|
||||
if os.path.isdir(candidate_dir):
|
||||
return candidate_dir
|
||||
except Exception as e:
|
||||
print(f"⚠️ 获取 Panda3D 二进制目录失败: {e}")
|
||||
return ""
|
||||
|
||||
def _createStandardBuildFiles(self, build_dir, project_path, scene_file):
|
||||
"""创建标准的Panda3D打包文件"""
|
||||
project_name = os.path.basename(project_path)
|
||||
|
||||
# 确保构建目录存在
|
||||
if not os.path.exists(build_dir):
|
||||
os.makedirs(build_dir)
|
||||
@ -472,38 +756,108 @@ class ProjectManager:
|
||||
self._createRequirementsFile(build_dir)
|
||||
|
||||
def _copyScriptsToBuild(self, build_dir, project_path):
|
||||
"""复制脚本文件到构建目录的scripts文件夹"""
|
||||
"""将项目脚本编译后复制到构建目录,避免直接暴露源码。"""
|
||||
try:
|
||||
# 创建目标scripts目录
|
||||
scripts_dest = os.path.join(build_dir, "scripts")
|
||||
|
||||
# 正确的源scripts目录路径
|
||||
scripts_src = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "scripts")
|
||||
|
||||
# 如果上面的路径不存在,尝试项目路径下的scripts目录
|
||||
if not os.path.exists(scripts_src):
|
||||
scripts_src = os.path.join(project_path, "scripts")
|
||||
scripts_src = self.get_project_scripts_dir(project_path)
|
||||
if os.path.exists(scripts_dest):
|
||||
shutil.rmtree(scripts_dest)
|
||||
os.makedirs(scripts_dest, exist_ok=True)
|
||||
|
||||
if os.path.exists(scripts_src):
|
||||
# 直接复制整个scripts目录
|
||||
if os.path.exists(scripts_dest):
|
||||
shutil.rmtree(scripts_dest)
|
||||
compiled_count = 0
|
||||
fallback_count = 0
|
||||
for root, _, files in os.walk(scripts_src):
|
||||
rel_root = os.path.relpath(root, scripts_src)
|
||||
target_root = scripts_dest if rel_root == "." else os.path.join(scripts_dest, rel_root)
|
||||
os.makedirs(target_root, exist_ok=True)
|
||||
|
||||
shutil.copytree(
|
||||
scripts_src,
|
||||
scripts_dest,
|
||||
ignore=shutil.ignore_patterns('__pycache__', '*.pyc', '.git', '.vscode', '*.log')
|
||||
)
|
||||
print("✓ Scripts目录已复制到build/scripts")
|
||||
for file_name in files:
|
||||
if file_name.startswith("__"):
|
||||
continue
|
||||
|
||||
source_file = os.path.join(root, file_name)
|
||||
if file_name.endswith(".py"):
|
||||
compiled_file = os.path.join(
|
||||
target_root,
|
||||
f"{os.path.splitext(file_name)[0]}.pyc",
|
||||
)
|
||||
try:
|
||||
py_compile.compile(source_file, cfile=compiled_file, doraise=True)
|
||||
compiled_count += 1
|
||||
except py_compile.PyCompileError as e:
|
||||
fallback_file = os.path.join(target_root, file_name)
|
||||
shutil.copy2(source_file, fallback_file)
|
||||
fallback_count += 1
|
||||
print(f"⚠️ 编译脚本失败,已回退复制源码: {source_file} -> {fallback_file} ({e})")
|
||||
elif not file_name.endswith((".pyc", ".pyo", ".log")):
|
||||
shutil.copy2(source_file, os.path.join(target_root, file_name))
|
||||
|
||||
print(f"✓ Scripts已导出到 build/scripts,编译 {compiled_count} 个脚本")
|
||||
if fallback_count:
|
||||
print(f"⚠️ {fallback_count} 个脚本因编译失败保留为 .py 源码")
|
||||
else:
|
||||
# 创建空的scripts目录
|
||||
if not os.path.exists(scripts_dest):
|
||||
os.makedirs(scripts_dest)
|
||||
print("⚠️ 项目中没有scripts目录")
|
||||
|
||||
except Exception as e:
|
||||
print(f"⚠️ 复制脚本文件时出错: {str(e)}")
|
||||
|
||||
def _copyRenderPipelineRuntime(self, build_dir):
|
||||
"""复制运行时需要的 RenderPipeline 资源,并将源码编译为 pyc。"""
|
||||
try:
|
||||
source_root = os.path.join(self._get_repo_root(), "RenderPipelineFile")
|
||||
target_root = os.path.join(build_dir, "RenderPipelineFile")
|
||||
|
||||
if os.path.exists(target_root):
|
||||
shutil.rmtree(target_root)
|
||||
|
||||
if not os.path.exists(source_root):
|
||||
print("⚠️ RenderPipelineFile 文件夹未找到")
|
||||
return False
|
||||
|
||||
blocked_dirs = {"__pycache__", ".git", ".vscode", "samples", "toolkit"}
|
||||
blocked_root_files = {"setup.py", "start_daytime_editor.py", "start_plugin_configurator.py"}
|
||||
blocked_relative_dirs = {
|
||||
os.path.normpath(os.path.join("rplibs", "yaml", "yaml_py2")),
|
||||
}
|
||||
|
||||
for root, dirs, files in os.walk(source_root):
|
||||
relative_root = os.path.relpath(root, source_root)
|
||||
normalized_relative_root = os.path.normpath(relative_root)
|
||||
dirs[:] = [
|
||||
name for name in dirs
|
||||
if name not in blocked_dirs
|
||||
and os.path.normpath(os.path.join(normalized_relative_root, name)) not in blocked_relative_dirs
|
||||
]
|
||||
target_dir = target_root if relative_root == "." else os.path.join(target_root, relative_root)
|
||||
os.makedirs(target_dir, exist_ok=True)
|
||||
|
||||
for file_name in files:
|
||||
if file_name.endswith((".pyc", ".pyo", ".log")):
|
||||
continue
|
||||
if relative_root == "." and file_name in blocked_root_files:
|
||||
continue
|
||||
|
||||
source_file = os.path.join(root, file_name)
|
||||
if file_name.endswith(".py"):
|
||||
compiled_file = os.path.join(
|
||||
target_dir,
|
||||
f"{os.path.splitext(file_name)[0]}.pyc",
|
||||
)
|
||||
try:
|
||||
py_compile.compile(source_file, cfile=compiled_file, doraise=True)
|
||||
except py_compile.PyCompileError as e:
|
||||
print(f"⚠️ RenderPipeline 脚本编译失败,保留源码: {source_file} ({e})")
|
||||
shutil.copy2(source_file, os.path.join(target_dir, file_name))
|
||||
else:
|
||||
shutil.copy2(source_file, os.path.join(target_dir, file_name))
|
||||
|
||||
print("✓ RenderPipeline 运行时资源已导出")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"⚠️ 导出 RenderPipeline 运行时资源失败: {e}")
|
||||
return False
|
||||
|
||||
def _copyScriptSystemToBuild(self,build_dir):
|
||||
core_files = [
|
||||
"script_system.py",
|
||||
@ -559,22 +913,90 @@ class ProjectManager:
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def _saveCameraStateToJSON(self, build_dir):
|
||||
"""保存当前主相机状态,供打包运行时恢复。"""
|
||||
try:
|
||||
camera = getattr(self.world, "camera", None) or getattr(self.world, "cam", None)
|
||||
if not camera or camera.isEmpty():
|
||||
return False
|
||||
|
||||
camera_state = {
|
||||
"position": list(camera.getPos()),
|
||||
"rotation": list(camera.getHpr()),
|
||||
"camera_control_enabled": bool(getattr(self.world, "camera_control_enabled", True)),
|
||||
}
|
||||
|
||||
camera_state_path = os.path.join(build_dir, "camera_state.json")
|
||||
with open(camera_state_path, "w", encoding="utf-8") as f:
|
||||
json.dump(camera_state, f, ensure_ascii=False, indent=4)
|
||||
|
||||
print(f"✓ 主相机状态已保存到 {camera_state_path}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"⚠️ 保存主相机状态失败: {e}")
|
||||
return False
|
||||
|
||||
def _updateResourcePaths(self,gui_info,project_path,build_dir):
|
||||
project_path = os.path.normpath(project_path)
|
||||
project_resources_dir = os.path.join(project_path, "Resources")
|
||||
scene_resources_dir = os.path.join(project_path, "scenes", "resources")
|
||||
|
||||
def normalize_resource_path(old_path):
|
||||
if not old_path:
|
||||
return old_path
|
||||
|
||||
if old_path.startswith(("http://","https://")):
|
||||
old_path = str(old_path).strip()
|
||||
if not old_path:
|
||||
return old_path
|
||||
|
||||
if os.path.isabs(old_path):
|
||||
try:
|
||||
rel_path = os.path.relpath(old_path,project_path)
|
||||
return os.path.join("resources",os.path.basename(rel_path)).replace("\\","/")
|
||||
except Exception:
|
||||
return os.path.join("resources",os.path.basename(old_path)).replace("\\","/")
|
||||
if old_path.startswith(("http://", "https://")):
|
||||
return old_path
|
||||
|
||||
normalized_path = os.path.normpath(old_path.replace("/", os.sep))
|
||||
if normalized_path == "resources" or normalized_path.startswith(f"resources{os.sep}"):
|
||||
return normalized_path.replace("\\", "/")
|
||||
|
||||
candidate_paths = []
|
||||
if os.path.isabs(normalized_path):
|
||||
candidate_paths.append(normalized_path)
|
||||
else:
|
||||
return os.path.join("resources",os.path.basename(old_path)).replace("\\","/")
|
||||
candidate_paths.extend(
|
||||
[
|
||||
os.path.join(project_resources_dir, normalized_path),
|
||||
os.path.join(scene_resources_dir, normalized_path),
|
||||
os.path.join(project_path, normalized_path),
|
||||
]
|
||||
)
|
||||
|
||||
resolved_path = ""
|
||||
for candidate in candidate_paths:
|
||||
if os.path.exists(candidate):
|
||||
resolved_path = os.path.normpath(candidate)
|
||||
break
|
||||
|
||||
if not resolved_path and os.path.isabs(normalized_path):
|
||||
resolved_path = normalized_path
|
||||
|
||||
if resolved_path:
|
||||
for base_dir in (project_resources_dir, scene_resources_dir):
|
||||
try:
|
||||
if os.path.exists(base_dir) and os.path.commonpath([resolved_path, base_dir]) == os.path.normpath(base_dir):
|
||||
relative_path = os.path.relpath(resolved_path, base_dir)
|
||||
return os.path.join("resources", relative_path).replace("\\", "/")
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
try:
|
||||
relative_path = os.path.relpath(resolved_path, project_path)
|
||||
if not relative_path.startswith(".."):
|
||||
return os.path.join("resources", relative_path).replace("\\", "/")
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
return os.path.join("resources", os.path.basename(resolved_path)).replace("\\", "/")
|
||||
|
||||
return os.path.join("resources", os.path.basename(normalized_path)).replace("\\", "/")
|
||||
|
||||
if "image_path" in gui_info and gui_info["image_path"]:
|
||||
gui_info["image_path"] = normalize_resource_path(gui_info["image_path"])
|
||||
if "video_path" in gui_info and gui_info["video_path"]:
|
||||
|
||||
@ -191,16 +191,12 @@ class SceneManagerIOMixin:
|
||||
for script_component in scripts:
|
||||
try:
|
||||
script_name = script_component.script_name
|
||||
# 获取脚本路径
|
||||
script_class = script_component.script_instance.__class__
|
||||
script_file = self._get_script_file_path(script_class, script_name)
|
||||
script_file = script_manager.loader.find_script_file(script_name) or ""
|
||||
script_reference = script_manager.build_script_reference(script_name, script_file)
|
||||
# 只有当脚本文件存在时才保存
|
||||
if script_file and os.path.exists(script_file):
|
||||
gui_info["scripts"].append({
|
||||
"name": script_name,
|
||||
"file": script_file
|
||||
})
|
||||
print(f"收集脚本信息: {script_name} from {script_file}")
|
||||
if script_reference.get("file") or script_reference.get("project_relative_path"):
|
||||
gui_info["scripts"].append(script_reference)
|
||||
print(f"收集脚本信息: {script_name} from {script_reference.get('file', '')}")
|
||||
else:
|
||||
print(f"警告: 脚本文件不存在: {script_file}")
|
||||
except Exception as e:
|
||||
@ -419,15 +415,10 @@ class SceneManagerIOMixin:
|
||||
for script_component in scripts:
|
||||
script_name = script_component.script_name
|
||||
print(f"保存脚本信息: {script_name}")
|
||||
|
||||
# 获取脚本类的文件路径
|
||||
script_class = script_component.script_instance.__class__
|
||||
script_file = self._get_script_file_path(script_class, script_name)
|
||||
|
||||
script_info_list.append({
|
||||
"name": script_name,
|
||||
"file": script_file
|
||||
})
|
||||
script_file = script_manager.loader.find_script_file(script_name) or ""
|
||||
script_info_list.append(
|
||||
script_manager.build_script_reference(script_name, script_file)
|
||||
)
|
||||
|
||||
# 将脚本信息保存为JSON字符串
|
||||
import json
|
||||
@ -955,7 +946,7 @@ class SceneManagerIOMixin:
|
||||
script_manager = self.world.script_manager
|
||||
for script_info in scripts_info:
|
||||
script_name = script_info["name"]
|
||||
script_file = script_info.get("file","")
|
||||
script_file = script_manager.resolve_script_path(script_info)
|
||||
|
||||
print(f"尝试重新挂载脚本{script_name}from {script_file}")
|
||||
|
||||
@ -1272,14 +1263,14 @@ class SceneManagerIOMixin:
|
||||
if os.path.exists(scripts_dir):
|
||||
# 首先精确匹配
|
||||
for file_name in os.listdir(scripts_dir):
|
||||
if file_name.endswith('.py'):
|
||||
if file_name.endswith(('.py', '.pyc')):
|
||||
base_name = os.path.splitext(file_name)[0]
|
||||
if base_name == script_name:
|
||||
return os.path.join(scripts_dir, file_name)
|
||||
|
||||
# 如果没有精确匹配,尝试模糊匹配
|
||||
for file_name in os.listdir(scripts_dir):
|
||||
if file_name.endswith('.py'):
|
||||
if file_name.endswith(('.py', '.pyc')):
|
||||
base_name = os.path.splitext(file_name)[0]
|
||||
if script_name.lower() in base_name.lower() or base_name.lower() in script_name.lower():
|
||||
return os.path.join(scripts_dir, file_name)
|
||||
|
||||
2
ssbo_component/__init__.py
Normal file
2
ssbo_component/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
"""SSBO runtime helpers and editor components."""
|
||||
|
||||
356
ssbo_component/runtime_importer.py
Normal file
356
ssbo_component/runtime_importer.py
Normal file
@ -0,0 +1,356 @@
|
||||
import os
|
||||
|
||||
from panda3d.core import Filename, GeomNode, Material, MaterialAttrib, NodePath
|
||||
|
||||
from .ssbo_controller import ObjectController
|
||||
|
||||
|
||||
class RuntimeSSBOSceneImporter:
|
||||
"""Minimal runtime-only SSBO scene importer without editor UI dependencies."""
|
||||
|
||||
def __init__(self, base_app):
|
||||
self.base = base_app
|
||||
self.controller = None
|
||||
self.model = None
|
||||
self.source_model = None
|
||||
self.source_model_root = None
|
||||
self.static_scene_root = None
|
||||
self.interactive_scene_root = None
|
||||
self.interactive_nodes = {}
|
||||
|
||||
def load_scene(self, scene_path, interactive_root_names=None):
|
||||
source_model = self._load_source_model_from_path(scene_path)
|
||||
self._clear_runtime_state()
|
||||
|
||||
source_root = self._ensure_source_model_root()
|
||||
imported_root = source_model.copyTo(source_root)
|
||||
self._set_node_name(imported_root, os.path.basename(scene_path) or "scene.bam")
|
||||
self.source_model = imported_root
|
||||
interactive_root_names = {str(name).strip() for name in (interactive_root_names or []) if str(name).strip()}
|
||||
|
||||
top_level_children = self._get_scene_top_level_children(imported_root)
|
||||
if interactive_root_names and top_level_children:
|
||||
self._build_release_split_scene(top_level_children, interactive_root_names)
|
||||
return self.interactive_scene_root or self.static_scene_root
|
||||
|
||||
working_holder = NodePath("ssbo_source_scene_work")
|
||||
working_root = source_root.copyTo(working_holder)
|
||||
|
||||
self.controller = ObjectController()
|
||||
self.controller.bake_ids_and_collect(working_root)
|
||||
self.model = self.controller.model
|
||||
self.model.reparentTo(self.base.render)
|
||||
|
||||
try:
|
||||
if not working_holder.isEmpty():
|
||||
working_holder.removeNode()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return self.model
|
||||
|
||||
def _clear_runtime_state(self):
|
||||
for node in (self.model, self.static_scene_root, self.interactive_scene_root, self.source_model_root):
|
||||
try:
|
||||
if node and not node.isEmpty():
|
||||
node.removeNode()
|
||||
except Exception:
|
||||
continue
|
||||
self.controller = None
|
||||
self.model = None
|
||||
self.source_model = None
|
||||
self.source_model_root = None
|
||||
self.static_scene_root = None
|
||||
self.interactive_scene_root = None
|
||||
self.interactive_nodes = {}
|
||||
|
||||
def get_runtime_node_for_name(self, node_name):
|
||||
return self.interactive_nodes.get(str(node_name or "").strip())
|
||||
|
||||
def _get_scene_top_level_children(self, imported_root):
|
||||
children = []
|
||||
try:
|
||||
for child in imported_root.getChildren():
|
||||
if child and not child.isEmpty():
|
||||
children.append(child)
|
||||
except Exception:
|
||||
children = []
|
||||
|
||||
if children:
|
||||
return children
|
||||
return [imported_root] if imported_root and not imported_root.isEmpty() else []
|
||||
|
||||
def _build_release_split_scene(self, top_level_children, interactive_root_names):
|
||||
static_holder = NodePath("runtime_static_scene")
|
||||
interactive_holder = NodePath("runtime_interactive_scene")
|
||||
interactive_count = 0
|
||||
static_count = 0
|
||||
|
||||
for child in top_level_children:
|
||||
child_name = self._get_node_name(child, "")
|
||||
if child_name in interactive_root_names:
|
||||
runtime_child = child.copyTo(interactive_holder)
|
||||
self._set_node_name(runtime_child, child_name)
|
||||
self.interactive_nodes[child_name] = runtime_child
|
||||
interactive_count += 1
|
||||
else:
|
||||
child.copyTo(static_holder)
|
||||
static_count += 1
|
||||
|
||||
if static_count:
|
||||
self.static_scene_root = static_holder
|
||||
self.static_scene_root.reparentTo(self.base.render)
|
||||
try:
|
||||
self.static_scene_root.flattenStrong()
|
||||
except Exception as e:
|
||||
print(f"静态场景合批失败,继续使用未合批结果: {e}")
|
||||
else:
|
||||
try:
|
||||
if not static_holder.isEmpty():
|
||||
static_holder.removeNode()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if interactive_count:
|
||||
self.interactive_scene_root = interactive_holder
|
||||
self.interactive_scene_root.reparentTo(self.base.render)
|
||||
else:
|
||||
try:
|
||||
if not interactive_holder.isEmpty():
|
||||
interactive_holder.removeNode()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
print(f"[RuntimeSSBO] 运行时分层导入完成: 交互对象 {interactive_count} 个, 静态合批对象 {static_count} 个")
|
||||
|
||||
def _load_source_model_from_path(self, model_path):
|
||||
source_model = None
|
||||
last_error = None
|
||||
for fn in self._build_filename_candidates(model_path):
|
||||
try:
|
||||
source_model = self.base.loader.loadModel(fn)
|
||||
if source_model and not source_model.isEmpty():
|
||||
break
|
||||
except Exception as e:
|
||||
last_error = e
|
||||
source_model = None
|
||||
|
||||
if not source_model or source_model.isEmpty():
|
||||
if last_error:
|
||||
raise RuntimeError(f"Failed to load model '{model_path}': {last_error}")
|
||||
raise RuntimeError(f"Failed to load model '{model_path}'")
|
||||
|
||||
self._fix_black_materials(source_model)
|
||||
self._repair_missing_textures(source_model, model_path)
|
||||
return source_model
|
||||
|
||||
def _build_filename_candidates(self, path_text):
|
||||
candidates = []
|
||||
seen = set()
|
||||
for ctor_name in ("fromOsSpecificW", "from_os_specific_w", "fromOsSpecific", "from_os_specific"):
|
||||
ctor = getattr(Filename, ctor_name, None)
|
||||
if not ctor:
|
||||
continue
|
||||
try:
|
||||
fn = ctor(path_text)
|
||||
key = fn.getFullpath() if hasattr(fn, "getFullpath") else fn.get_fullpath()
|
||||
if key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
candidates.append(fn)
|
||||
except Exception:
|
||||
continue
|
||||
if not candidates:
|
||||
try:
|
||||
candidates.append(Filename(path_text))
|
||||
except Exception:
|
||||
pass
|
||||
return candidates
|
||||
|
||||
def _ensure_source_model_root(self):
|
||||
root = self.source_model_root
|
||||
if root and not root.isEmpty():
|
||||
return root
|
||||
self.source_model_root = NodePath("ssbo_source_scene_root")
|
||||
return self.source_model_root
|
||||
|
||||
def _set_node_name(self, node, name):
|
||||
if not node:
|
||||
return
|
||||
try:
|
||||
node.set_name(name)
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
node.setName(name)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _get_node_name(self, node, default_name=None):
|
||||
if not node:
|
||||
return default_name
|
||||
try:
|
||||
return node.get_name()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
return node.getName()
|
||||
except Exception:
|
||||
return default_name
|
||||
|
||||
def _fix_black_materials(self, model):
|
||||
try:
|
||||
for geom_path in model.findAllMatches("**/+GeomNode"):
|
||||
geom_node = geom_path.node()
|
||||
node_state = geom_path.getState()
|
||||
if node_state.hasAttrib(MaterialAttrib.getClassType()):
|
||||
mat_attrib = node_state.getAttrib(MaterialAttrib.getClassType())
|
||||
mat = mat_attrib.getMaterial()
|
||||
if mat and self._is_dark_material(mat):
|
||||
new_mat = Material(mat)
|
||||
new_mat.setBaseColor((0.8, 0.8, 0.8, 1.0))
|
||||
new_mat.setDiffuse((0.8, 0.8, 0.8, 1.0))
|
||||
geom_path.setState(node_state.setAttrib(MaterialAttrib.make(new_mat)))
|
||||
|
||||
for i in range(geom_node.getNumGeoms()):
|
||||
geom_state = geom_node.getGeomState(i)
|
||||
if geom_state.hasAttrib(MaterialAttrib.getClassType()):
|
||||
mat_attrib = geom_state.getAttrib(MaterialAttrib.getClassType())
|
||||
mat = mat_attrib.getMaterial()
|
||||
if mat and self._is_dark_material(mat):
|
||||
new_mat = Material(mat)
|
||||
new_mat.setBaseColor((0.8, 0.8, 0.8, 1.0))
|
||||
new_mat.setDiffuse((0.8, 0.8, 0.8, 1.0))
|
||||
geom_node.setGeomState(i, geom_state.setAttrib(MaterialAttrib.make(new_mat)))
|
||||
else:
|
||||
new_mat = Material()
|
||||
new_mat.setBaseColor((0.8, 0.8, 0.8, 1.0))
|
||||
new_mat.setDiffuse((0.8, 0.8, 0.8, 1.0))
|
||||
new_mat.setSpecular((0.2, 0.2, 0.2, 1.0))
|
||||
new_mat.setRoughness(0.8)
|
||||
geom_node.setGeomState(i, geom_state.addAttrib(MaterialAttrib.make(new_mat)))
|
||||
model.clearColor()
|
||||
except Exception as e:
|
||||
print(f"修复黑色模型材质时出错: {e}")
|
||||
|
||||
def _is_dark_material(self, material):
|
||||
try:
|
||||
if material.hasBaseColor():
|
||||
c = material.getBaseColor()
|
||||
elif material.hasDiffuse():
|
||||
c = material.getDiffuse()
|
||||
else:
|
||||
return True
|
||||
return c.x <= 0.05 and c.y <= 0.05 and c.z <= 0.05
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def _repair_missing_textures(self, model_np, model_path):
|
||||
if not model_np or model_np.isEmpty():
|
||||
return
|
||||
|
||||
search_dirs = self._build_texture_search_dirs(model_path)
|
||||
texture_index = self._index_texture_files(search_dirs)
|
||||
|
||||
for node in [model_np] + list(model_np.findAllMatches("**")):
|
||||
if not node or node.isEmpty():
|
||||
continue
|
||||
try:
|
||||
stages = node.findAllTextureStages()
|
||||
stage_count = stages.getNumTextureStages()
|
||||
stage_at = stages.getTextureStage
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
for i in range(stage_count):
|
||||
stage = stage_at(i)
|
||||
if not stage:
|
||||
continue
|
||||
try:
|
||||
tex = node.getTexture(stage)
|
||||
except Exception:
|
||||
tex = None
|
||||
if not tex or self._texture_is_valid(tex):
|
||||
continue
|
||||
|
||||
basename = self._extract_texture_basename(tex)
|
||||
if not basename:
|
||||
continue
|
||||
|
||||
replacement = texture_index.get(basename.lower())
|
||||
if replacement:
|
||||
new_tex = self._load_texture_from_path(replacement)
|
||||
if new_tex:
|
||||
try:
|
||||
node.setTexture(stage, new_tex, 1)
|
||||
continue
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
node.clearTexture(stage)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _build_texture_search_dirs(self, model_path):
|
||||
dirs = []
|
||||
model_dir = os.path.dirname(os.path.abspath(model_path))
|
||||
project_root = getattr(self.base, "project_path", "") or os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
def add_dir(path):
|
||||
if path and os.path.isdir(path):
|
||||
normalized = os.path.normpath(path)
|
||||
if normalized not in dirs:
|
||||
dirs.append(normalized)
|
||||
|
||||
add_dir(model_dir)
|
||||
for sub in ("textures", "texture", "tex", "assets", "materials"):
|
||||
add_dir(os.path.join(model_dir, sub))
|
||||
add_dir(os.path.join(project_root, "resources", sub))
|
||||
add_dir(os.path.join(project_root, "resources"))
|
||||
return dirs
|
||||
|
||||
def _index_texture_files(self, dirs, limit=30000):
|
||||
texture_exts = {".png", ".jpg", ".jpeg", ".tga", ".bmp", ".dds", ".ktx", ".ktx2", ".webp"}
|
||||
index = {}
|
||||
scanned = 0
|
||||
for root_dir in dirs:
|
||||
try:
|
||||
for root, _, files in os.walk(root_dir):
|
||||
for filename in files:
|
||||
if os.path.splitext(filename)[1].lower() not in texture_exts:
|
||||
continue
|
||||
index.setdefault(filename.lower(), os.path.join(root, filename))
|
||||
scanned += 1
|
||||
if scanned >= limit:
|
||||
return index
|
||||
except Exception:
|
||||
continue
|
||||
return index
|
||||
|
||||
def _load_texture_from_path(self, texture_path):
|
||||
for fn in self._build_filename_candidates(texture_path):
|
||||
try:
|
||||
tex = self.base.loader.loadTexture(fn)
|
||||
if tex:
|
||||
return tex
|
||||
except Exception:
|
||||
continue
|
||||
return None
|
||||
|
||||
def _texture_is_valid(self, texture):
|
||||
try:
|
||||
x_size = texture.getXSize()
|
||||
y_size = texture.getYSize()
|
||||
return bool(x_size and y_size)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def _extract_texture_basename(self, texture):
|
||||
try:
|
||||
path = texture.getFilename().toOsSpecific()
|
||||
except Exception:
|
||||
path = ""
|
||||
if not path:
|
||||
return ""
|
||||
return os.path.basename(path)
|
||||
File diff suppressed because it is too large
Load Diff
@ -270,6 +270,38 @@ class AppActions:
|
||||
self.add_info_message("打开另存为项目对话框")
|
||||
self.show_save_as_dialog = True
|
||||
|
||||
def _on_build_project(self):
|
||||
"""处理打包项目菜单项。"""
|
||||
current_project_path = getattr(getattr(self, "project_manager", None), "current_project_path", None)
|
||||
if current_project_path:
|
||||
self.build_output_path = os.path.dirname(current_project_path)
|
||||
else:
|
||||
self.build_output_path = os.getcwd()
|
||||
self.add_info_message("打开打包项目对话框")
|
||||
self.show_build_project_dialog = True
|
||||
|
||||
def _build_project_impl(self, output_path):
|
||||
"""执行项目打包。"""
|
||||
if not hasattr(self, "project_manager") or not self.project_manager:
|
||||
self.add_error_message("项目管理器未初始化")
|
||||
return False
|
||||
|
||||
if not output_path or not output_path.strip():
|
||||
self.add_warning_message("请选择打包输出目录")
|
||||
return False
|
||||
|
||||
try:
|
||||
build_success = self.project_manager.buildPackage(output_path.strip())
|
||||
if build_success:
|
||||
self.add_success_message("项目打包成功")
|
||||
return True
|
||||
|
||||
self.add_error_message("项目打包失败")
|
||||
return False
|
||||
except Exception as e:
|
||||
self.add_error_message(f"项目打包失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def _show_about_dialog(self):
|
||||
"""显示关于对话框。"""
|
||||
@ -1033,71 +1065,16 @@ class AppActions:
|
||||
|
||||
def _open_project_impl(self, project_path):
|
||||
"""打开项目的具体实现(不依赖Qt)"""
|
||||
import json
|
||||
import datetime
|
||||
|
||||
try:
|
||||
# 检查项目管理器是否已初始化
|
||||
if not hasattr(self, 'project_manager') or not self.project_manager:
|
||||
print("✗ 项目管理器未初始化")
|
||||
self.add_error_message("项目管理器未初始化")
|
||||
return False
|
||||
|
||||
# 检查场景管理器是否已初始化
|
||||
if not hasattr(self, 'scene_manager') or not self.scene_manager:
|
||||
print("✗ 场景管理器未初始化")
|
||||
self.add_error_message("场景管理器未初始化")
|
||||
return False
|
||||
|
||||
# 检查是否是有效的项目文件夹
|
||||
config_file = os.path.join(project_path, "project.json")
|
||||
if not os.path.exists(config_file):
|
||||
print(f"⚠ 选择的不是有效的项目文件夹: {project_path}")
|
||||
self.add_warning_message(f"选择的不是有效的项目文件夹: {project_path}")
|
||||
|
||||
if not self.project_manager.openProject(project_path):
|
||||
self.add_error_message(f"项目打开失败: {project_path}")
|
||||
return False
|
||||
|
||||
# 读取项目配置
|
||||
try:
|
||||
with open(config_file, "r", encoding="utf-8") as f:
|
||||
project_config = json.load(f)
|
||||
except Exception as e:
|
||||
print(f"✗ 读取项目配置文件失败: {e}")
|
||||
self.add_error_message(f"读取项目配置文件失败: {e}")
|
||||
return False
|
||||
|
||||
# 检查场景文件
|
||||
scene_file = os.path.join(project_path, "scenes", "scene.bam")
|
||||
if os.path.exists(scene_file):
|
||||
if getattr(self, "use_ssbo_mouse_picking", False) and callable(getattr(self, "_import_model_for_runtime", None)):
|
||||
self.use_ssbo_scene_import = True
|
||||
# 加载场景
|
||||
try:
|
||||
if self.scene_manager.loadScene(scene_file):
|
||||
# 更新项目配置
|
||||
project_config["scene_file"] = os.path.relpath(scene_file, project_path)
|
||||
print(f"✓ 场景加载成功: {scene_file}")
|
||||
else:
|
||||
print(f"⚠ 场景加载失败: {scene_file}")
|
||||
self.add_warning_message(f"场景加载失败: {scene_file}")
|
||||
except Exception as e:
|
||||
print(f"✗ 加载场景时发生错误: {e}")
|
||||
self.add_error_message(f"加载场景时发生错误: {e}")
|
||||
# 继续执行,不阻止项目打开
|
||||
|
||||
# 更新项目配置
|
||||
project_config["last_modified"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
try:
|
||||
with open(config_file, "w", encoding="utf-8") as f:
|
||||
json.dump(project_config, f, ensure_ascii=False, indent=4)
|
||||
except Exception as e:
|
||||
print(f"✗ 保存项目配置失败: {e}")
|
||||
self.add_error_message(f"保存项目配置失败: {e}")
|
||||
|
||||
# 更新项目状态
|
||||
self.project_manager.current_project_path = project_path
|
||||
self.project_manager.project_config = project_config
|
||||
|
||||
# 更新窗口标题
|
||||
project_name = os.path.basename(project_path)
|
||||
self._update_window_title(project_name)
|
||||
|
||||
@ -1113,45 +1090,12 @@ class AppActions:
|
||||
|
||||
def _create_new_project_impl(self, name, path):
|
||||
"""创建新项目的具体实现(不依赖Qt)"""
|
||||
full_project_path = os.path.normpath(os.path.join(path, name))
|
||||
print(f"创建项目路径: {full_project_path}")
|
||||
|
||||
try:
|
||||
# 创建项目文件夹结构
|
||||
os.makedirs(full_project_path)
|
||||
os.makedirs(os.path.join(full_project_path, "models")) # 模型文件夹
|
||||
os.makedirs(os.path.join(full_project_path, "textures")) # 贴图文件夹
|
||||
scenes_path = os.path.join(full_project_path, "scenes") # 场景文件夹
|
||||
os.makedirs(scenes_path)
|
||||
|
||||
# 创建项目配置文件
|
||||
project_config = {
|
||||
"name": name,
|
||||
"path": full_project_path,
|
||||
"created": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"last_modified": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"version": "1.0",
|
||||
"scene_file": "scenes/scene.bam"
|
||||
}
|
||||
|
||||
# 保存项目配置
|
||||
config_file = os.path.join(full_project_path, "project.json")
|
||||
with open(config_file, "w", encoding="utf-8") as f:
|
||||
json.dump(project_config, f, ensure_ascii=False, indent=4)
|
||||
|
||||
# 保存初始场景
|
||||
scene_file = os.path.join(scenes_path, "scene.bam")
|
||||
self.scene_manager.saveScene(scene_file, full_project_path)
|
||||
|
||||
# 更新项目管理器状态
|
||||
self.project_manager.current_project_path = full_project_path
|
||||
self.project_manager.project_config = project_config
|
||||
|
||||
# 更新窗口标题
|
||||
if not self.project_manager.createNewProject(path, name):
|
||||
return False
|
||||
|
||||
self._update_window_title(name)
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"创建项目失败: {e}")
|
||||
return False
|
||||
@ -1192,9 +1136,11 @@ class AppActions:
|
||||
os.makedirs(os.path.join(full_project_path, "models"), exist_ok=True)
|
||||
os.makedirs(os.path.join(full_project_path, "textures"), exist_ok=True)
|
||||
os.makedirs(os.path.join(full_project_path, "scenes"), exist_ok=True)
|
||||
os.makedirs(os.path.join(full_project_path, "scripts"), exist_ok=True)
|
||||
|
||||
previous_project_path = self.project_manager.current_project_path
|
||||
previous_project_config = dict(self.project_manager.project_config or {})
|
||||
previous_scripts_dir = getattr(getattr(self, "script_manager", None), "scripts_directory", "")
|
||||
|
||||
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
project_config = dict(previous_project_config)
|
||||
@ -1217,12 +1163,25 @@ class AppActions:
|
||||
with open(config_file, "w", encoding="utf-8") as f:
|
||||
json.dump(project_config, f, ensure_ascii=False, indent=4)
|
||||
|
||||
source_scripts_dir = ""
|
||||
if previous_project_path:
|
||||
source_scripts_dir = self.project_manager.get_project_scripts_dir(previous_project_path)
|
||||
if not source_scripts_dir:
|
||||
source_scripts_dir = previous_scripts_dir
|
||||
|
||||
target_scripts_dir = self.project_manager.get_project_scripts_dir(full_project_path)
|
||||
if source_scripts_dir and os.path.exists(source_scripts_dir):
|
||||
self._copy_directory_contents(source_scripts_dir, target_scripts_dir)
|
||||
|
||||
self.project_manager.current_project_path = full_project_path
|
||||
self.project_manager.project_config = project_config
|
||||
self.project_manager._sync_project_script_manager(full_project_path, reload_scripts=True)
|
||||
|
||||
if not self.project_manager.saveProject():
|
||||
self.project_manager.current_project_path = previous_project_path
|
||||
self.project_manager.project_config = previous_project_config
|
||||
if previous_project_path:
|
||||
self.project_manager._sync_project_script_manager(previous_project_path, reload_scripts=True)
|
||||
self._update_window_title(os.path.basename(previous_project_path) if previous_project_path else "未命名项目")
|
||||
self.add_error_message("项目另存为失败")
|
||||
return False
|
||||
@ -1233,6 +1192,23 @@ class AppActions:
|
||||
except Exception as e:
|
||||
self.add_error_message(f"项目另存为失败: {e}")
|
||||
return False
|
||||
|
||||
def _copy_directory_contents(self, source_dir, target_dir):
|
||||
"""Copy a directory tree into target_dir, replacing existing files."""
|
||||
import shutil
|
||||
|
||||
if not source_dir or not os.path.exists(source_dir):
|
||||
return
|
||||
|
||||
os.makedirs(target_dir, exist_ok=True)
|
||||
for root, _, files in os.walk(source_dir):
|
||||
rel_root = os.path.relpath(root, source_dir)
|
||||
destination_root = target_dir if rel_root == "." else os.path.join(target_dir, rel_root)
|
||||
os.makedirs(destination_root, exist_ok=True)
|
||||
for file_name in files:
|
||||
source_file = os.path.join(root, file_name)
|
||||
target_file = os.path.join(destination_root, file_name)
|
||||
shutil.copy2(source_file, target_file)
|
||||
|
||||
|
||||
def _update_window_title(self, project_name):
|
||||
|
||||
@ -203,6 +203,51 @@ class DialogPanels:
|
||||
imgui.same_line()
|
||||
if imgui.button("取消"):
|
||||
self.show_save_as_dialog = False
|
||||
|
||||
def _draw_build_project_dialog(self):
|
||||
"""绘制项目打包对话框。"""
|
||||
if not getattr(self, "show_build_project_dialog", False):
|
||||
return
|
||||
|
||||
if not getattr(self, "build_output_path", "").strip():
|
||||
current_project_path = getattr(getattr(self, "project_manager", None), "current_project_path", None)
|
||||
self.build_output_path = os.path.dirname(current_project_path) if current_project_path else os.getcwd()
|
||||
|
||||
flags = (
|
||||
imgui.WindowFlags_.no_resize
|
||||
| imgui.WindowFlags_.no_collapse
|
||||
| imgui.WindowFlags_.modal
|
||||
)
|
||||
self.style_manager.prepare_centered_dialog(480, 220)
|
||||
|
||||
with imgui_ctx.begin("打包项目", True, flags) as window:
|
||||
if not window.opened:
|
||||
self.show_build_project_dialog = False
|
||||
return
|
||||
|
||||
imgui.text("生成当前项目的最终运行程序")
|
||||
imgui.separator()
|
||||
|
||||
changed, output_path = imgui.input_text("输出目录", self.build_output_path, 512)
|
||||
if changed:
|
||||
self.build_output_path = output_path
|
||||
|
||||
imgui.same_line()
|
||||
if imgui.button("浏览..."):
|
||||
self.path_browser_mode = "build_project"
|
||||
self.path_browser_current_path = self.build_output_path if self.build_output_path else os.getcwd()
|
||||
self.show_path_browser = True
|
||||
self._refresh_path_browser()
|
||||
|
||||
imgui.separator()
|
||||
|
||||
if imgui.button("开始打包"):
|
||||
if self._build_project_impl(self.build_output_path):
|
||||
self.show_build_project_dialog = False
|
||||
|
||||
imgui.same_line()
|
||||
if imgui.button("取消"):
|
||||
self.show_build_project_dialog = False
|
||||
|
||||
|
||||
def _draw_path_browser(self):
|
||||
@ -465,6 +510,9 @@ class DialogPanels:
|
||||
# 另存为项目模式:使用当前路径作为目标目录
|
||||
self.save_as_project_path = self.path_browser_current_path
|
||||
self.add_info_message(f"已选择保存位置: {self.save_as_project_path}")
|
||||
elif self.path_browser_mode == "build_project":
|
||||
self.build_output_path = self.path_browser_current_path
|
||||
self.add_info_message(f"已选择打包位置: {self.build_output_path}")
|
||||
elif self.path_browser_mode == "import_model":
|
||||
# 导入模型模式:使用选择的文件路径
|
||||
self.import_file_path = self.path_browser_selected_path
|
||||
|
||||
@ -187,6 +187,8 @@ class EditorPanelsTopMixin:
|
||||
self.app._on_save_project()
|
||||
if imgui.menu_item("另存为", "", False, True)[1]:
|
||||
self.app._on_save_as_project()
|
||||
if imgui.menu_item("打包项目", "", False, True)[1]:
|
||||
self.app._on_build_project()
|
||||
imgui.separator()
|
||||
if imgui.menu_item("退出", "Alt+F4", False, True)[1]:
|
||||
self.app._on_exit()
|
||||
|
||||
@ -459,6 +459,12 @@ class PanelDelegates:
|
||||
def _on_save_as_project(self, *args, **kwargs):
|
||||
return self.app_actions._on_save_as_project(*args, **kwargs)
|
||||
|
||||
def _on_build_project(self, *args, **kwargs):
|
||||
return self.app_actions._on_build_project(*args, **kwargs)
|
||||
|
||||
def _build_project_impl(self, *args, **kwargs):
|
||||
return self.app_actions._build_project_impl(*args, **kwargs)
|
||||
|
||||
def _show_about_dialog(self, *args, **kwargs):
|
||||
return self.app_actions._show_about_dialog(*args, **kwargs)
|
||||
|
||||
@ -588,6 +594,9 @@ class PanelDelegates:
|
||||
def _draw_save_as_project_dialog(self, *args, **kwargs):
|
||||
return self.dialog_panels._draw_save_as_project_dialog(*args, **kwargs)
|
||||
|
||||
def _draw_build_project_dialog(self, *args, **kwargs):
|
||||
return self.dialog_panels._draw_build_project_dialog(*args, **kwargs)
|
||||
|
||||
def _draw_path_browser(self, *args, **kwargs):
|
||||
return self.dialog_panels._draw_path_browser(*args, **kwargs)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user