316 lines
14 KiB
Python
316 lines
14 KiB
Python
from imgui_bundle import imgui, imgui_ctx
|
|
|
|
class EditorPanelsRightCollisionMixin:
|
|
"""Auto-split mixin from editor_panels_right.py."""
|
|
|
|
def _ensure_collision_edit_sessions(self):
|
|
if not hasattr(self, "_collision_edit_sessions"):
|
|
self._collision_edit_sessions = {}
|
|
return self._collision_edit_sessions
|
|
|
|
def _begin_collision_edit_session(self, node, session_key):
|
|
sessions = self._ensure_collision_edit_sessions()
|
|
sessions.setdefault(session_key, self.app._capture_collision_snapshot(node))
|
|
|
|
def _record_collision_snapshot_command(self, node, before_snapshot, after_snapshot):
|
|
if not hasattr(self.app, "command_manager") or not self.app.command_manager:
|
|
return
|
|
if self.app._collision_snapshots_equal(before_snapshot, after_snapshot):
|
|
return
|
|
try:
|
|
from core.Command_System import SnapshotStateCommand
|
|
|
|
self.app.command_manager.record_command(
|
|
SnapshotStateCommand(
|
|
lambda state, target_node=node: self.app._apply_collision_snapshot(target_node, state),
|
|
before_snapshot,
|
|
after_snapshot,
|
|
)
|
|
)
|
|
except Exception:
|
|
pass
|
|
|
|
def _finish_collision_edit_session(self, node, session_key):
|
|
if not imgui.is_item_deactivated_after_edit():
|
|
return
|
|
sessions = self._ensure_collision_edit_sessions()
|
|
before_snapshot = sessions.pop(session_key, None)
|
|
if before_snapshot is None:
|
|
return
|
|
after_snapshot = self.app._capture_collision_snapshot(node)
|
|
self._record_collision_snapshot_command(node, before_snapshot, after_snapshot)
|
|
|
|
def _apply_collision_change_with_history(self, node, apply_callback):
|
|
before_snapshot = self.app._capture_collision_snapshot(node)
|
|
apply_callback()
|
|
after_snapshot = self.app._capture_collision_snapshot(node)
|
|
self._record_collision_snapshot_command(node, before_snapshot, after_snapshot)
|
|
|
|
def _draw_collision_properties(self, node):
|
|
"""绘制碰撞检测属性"""
|
|
if not node or node.isEmpty():
|
|
return
|
|
|
|
try:
|
|
# 检查节点是否已有碰撞
|
|
has_collision = self._has_collision(node)
|
|
|
|
# 碰撞状态徽章
|
|
imgui.text("状态:")
|
|
imgui.same_line()
|
|
if has_collision:
|
|
imgui.text_colored((0.0, 0.8, 0.0, 1.0), "🟢 已启用")
|
|
else:
|
|
imgui.text_colored((0.8, 0.0, 0.0, 1.0), "🔴 未启用")
|
|
|
|
imgui.separator()
|
|
|
|
# 碰撞形状选择
|
|
imgui.text("碰撞形状:")
|
|
imgui.same_line()
|
|
|
|
# 碰撞形状选项
|
|
collision_shapes = ["球形 (Sphere)", "盒型 (Box)", "胶囊体 (Capsule)", "平面 (Plane)", "自动选择 (Auto)"]
|
|
|
|
# 获取当前形状
|
|
current_shape = self._get_current_collision_shape(node) if has_collision else getattr(self.app, '_selected_collision_shape', "球形 (Sphere)")
|
|
if has_collision: self.app._selected_collision_shape = current_shape
|
|
|
|
# 形状选择下拉框
|
|
current_index = collision_shapes.index(current_shape) if current_shape in collision_shapes else 0
|
|
changed, selected_index = imgui.combo("##collision_shape", current_index, collision_shapes)
|
|
if changed:
|
|
selected_shape = collision_shapes[selected_index]
|
|
if has_collision:
|
|
self._apply_collision_change_with_history(
|
|
node,
|
|
lambda: self._change_collision_shape(node, selected_shape),
|
|
)
|
|
else:
|
|
self.app._selected_collision_shape = selected_shape
|
|
|
|
imgui.separator()
|
|
|
|
# 位置偏移控件
|
|
imgui.text("位置偏移:")
|
|
|
|
# 获取当前位置偏移
|
|
pos_offset = self._get_collision_position_offset(node)
|
|
|
|
# X位置
|
|
changed, new_x = imgui.drag_float("X##collision_pos_x", pos_offset[0], 0.1, -100.0, 100.0, "%.2f")
|
|
if imgui.is_item_activated() and has_collision:
|
|
self._begin_collision_edit_session(node, "collision_position")
|
|
if changed and has_collision:
|
|
self._update_collision_position(node, 'x', new_x)
|
|
self._finish_collision_edit_session(node, "collision_position")
|
|
|
|
# Y位置
|
|
changed, new_y = imgui.drag_float("Y##collision_pos_y", pos_offset[1], 0.1, -100.0, 100.0, "%.2f")
|
|
if imgui.is_item_activated() and has_collision:
|
|
self._begin_collision_edit_session(node, "collision_position")
|
|
if changed and has_collision:
|
|
self._update_collision_position(node, 'y', new_y)
|
|
self._finish_collision_edit_session(node, "collision_position")
|
|
|
|
# Z位置
|
|
changed, new_z = imgui.drag_float("Z##collision_pos_z", pos_offset[2], 0.1, -100.0, 100.0, "%.2f")
|
|
if imgui.is_item_activated() and has_collision:
|
|
self._begin_collision_edit_session(node, "collision_position")
|
|
if changed and has_collision:
|
|
self._update_collision_position(node, 'z', new_z)
|
|
self._finish_collision_edit_session(node, "collision_position")
|
|
|
|
# 形状特定参数(始终显示,但根据状态启用/禁用)
|
|
shape_type = self._get_current_collision_shape_type(node)
|
|
self._draw_shape_specific_parameters(node, shape_type, has_collision)
|
|
|
|
imgui.separator()
|
|
|
|
# 操作按钮
|
|
if has_collision:
|
|
# 显示/隐藏碰撞体按钮
|
|
is_visible = self._is_collision_visible(node)
|
|
visibility_text = "隐藏碰撞体" if is_visible else "显示碰撞体"
|
|
if imgui.button(visibility_text):
|
|
self._apply_collision_change_with_history(node, lambda: self._toggle_collision_visibility(node))
|
|
|
|
imgui.same_line()
|
|
|
|
# 移除碰撞按钮
|
|
if imgui.button("移除碰撞"):
|
|
self._apply_collision_change_with_history(node, lambda: self._remove_collision_from_node(node))
|
|
else:
|
|
# 添加碰撞按钮
|
|
if imgui.button("添加碰撞"):
|
|
self._apply_collision_change_with_history(node, lambda: self._add_collision_to_node(node))
|
|
|
|
imgui.separator()
|
|
|
|
# 碰撞检测触发模式
|
|
imgui.text("触发模式:")
|
|
|
|
# 自动检测开关
|
|
auto_enabled = self.collision_manager.model_collision_enabled if hasattr(self, 'collision_manager') else False
|
|
changed, new_auto = imgui.checkbox("自动检测", auto_enabled)
|
|
if changed and hasattr(self, 'collision_manager'):
|
|
self.collision_manager.enableModelCollisionDetection(new_auto, 0.1, 0.5)
|
|
|
|
imgui.same_line()
|
|
|
|
# 手动检测按钮
|
|
if imgui.button("立即检测"):
|
|
if hasattr(self, 'collision_manager'):
|
|
self._manual_collision_detection()
|
|
|
|
except Exception as e:
|
|
print(f"绘制碰撞属性失败: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
|
|
def _change_collision_shape(self, node, selected_shape):
|
|
self.app._selected_collision_shape = selected_shape
|
|
offset = self._get_collision_position_offset(node)
|
|
visible = self._is_collision_visible(node)
|
|
self._remove_collision_from_node(node)
|
|
self._add_collision_to_node(node)
|
|
collision_node = self.app.property_helpers._get_collision_node(node)
|
|
if collision_node:
|
|
try:
|
|
collision_node.setPos(*offset)
|
|
except Exception:
|
|
pass
|
|
if visible:
|
|
collision_node.show()
|
|
else:
|
|
collision_node.hide()
|
|
|
|
def _draw_shape_specific_parameters(self, node, shape_type, has_collision=True):
|
|
"""绘制形状特定参数"""
|
|
try:
|
|
if shape_type == "sphere":
|
|
self._draw_sphere_parameters(node, has_collision)
|
|
elif shape_type == "box":
|
|
self._draw_box_parameters(node, has_collision)
|
|
elif shape_type == "capsule":
|
|
self._draw_capsule_parameters(node, has_collision)
|
|
elif shape_type == "plane":
|
|
self._draw_plane_parameters(node, has_collision)
|
|
except Exception as e:
|
|
print(f"绘制形状参数失败: {e}")
|
|
|
|
def _draw_sphere_parameters(self, node, has_collision=True):
|
|
"""绘制球形参数"""
|
|
try:
|
|
imgui.text("球形参数:")
|
|
imgui.same_line()
|
|
|
|
# 获取当前半径
|
|
radius = self._get_sphere_radius(node)
|
|
|
|
# 半径调整
|
|
changed, new_radius = imgui.drag_float("半径##sphere_radius", radius, 0.1, 0.1, 100.0, "%.2f")
|
|
if imgui.is_item_activated() and has_collision:
|
|
self._begin_collision_edit_session(node, "collision_sphere_radius")
|
|
if changed and has_collision:
|
|
self._update_sphere_radius(node, new_radius)
|
|
self._finish_collision_edit_session(node, "collision_sphere_radius")
|
|
|
|
except Exception as e:
|
|
print(f"绘制球形参数失败: {e}")
|
|
|
|
def _draw_box_parameters(self, node, has_collision=True):
|
|
"""绘制盒型参数"""
|
|
try:
|
|
imgui.text("盒型参数:")
|
|
|
|
# 获取当前尺寸
|
|
size = self._get_box_size(node)
|
|
|
|
# 尺寸调整
|
|
changed, new_x = imgui.drag_float("长度##box_length", size[0], 0.1, 0.1, 100.0, "%.2f")
|
|
if imgui.is_item_activated() and has_collision:
|
|
self._begin_collision_edit_session(node, "collision_box_size")
|
|
if changed and has_collision:
|
|
self._update_box_size(node, 'x', new_x)
|
|
self._finish_collision_edit_session(node, "collision_box_size")
|
|
|
|
changed, new_y = imgui.drag_float("宽度##box_width", size[1], 0.1, 0.1, 100.0, "%.2f")
|
|
if imgui.is_item_activated() and has_collision:
|
|
self._begin_collision_edit_session(node, "collision_box_size")
|
|
if changed and has_collision:
|
|
self._update_box_size(node, 'y', new_y)
|
|
self._finish_collision_edit_session(node, "collision_box_size")
|
|
|
|
changed, new_z = imgui.drag_float("高度##box_height", size[2], 0.1, 0.1, 100.0, "%.2f")
|
|
if imgui.is_item_activated() and has_collision:
|
|
self._begin_collision_edit_session(node, "collision_box_size")
|
|
if changed and has_collision:
|
|
self._update_box_size(node, 'z', new_z)
|
|
self._finish_collision_edit_session(node, "collision_box_size")
|
|
|
|
except Exception as e:
|
|
print(f"绘制盒型参数失败: {e}")
|
|
|
|
def _draw_capsule_parameters(self, node, has_collision=True):
|
|
"""绘制胶囊体参数"""
|
|
try:
|
|
imgui.text("胶囊体参数:")
|
|
|
|
# 获取当前参数
|
|
radius = self._get_capsule_radius(node)
|
|
height = self._get_capsule_height(node)
|
|
|
|
# 半径调整
|
|
changed, new_radius = imgui.drag_float("半径##capsule_radius", radius, 0.1, 0.1, 100.0, "%.2f")
|
|
if imgui.is_item_activated() and has_collision:
|
|
self._begin_collision_edit_session(node, "collision_capsule_radius")
|
|
if changed and has_collision:
|
|
self._update_capsule_radius(node, new_radius)
|
|
self._finish_collision_edit_session(node, "collision_capsule_radius")
|
|
|
|
# 高度调整
|
|
changed, new_height = imgui.drag_float("高度##capsule_height", height, 0.1, 0.1, 100.0, "%.2f")
|
|
if imgui.is_item_activated() and has_collision:
|
|
self._begin_collision_edit_session(node, "collision_capsule_height")
|
|
if changed and has_collision:
|
|
self._update_capsule_height(node, new_height)
|
|
self._finish_collision_edit_session(node, "collision_capsule_height")
|
|
|
|
except Exception as e:
|
|
print(f"绘制胶囊体参数失败: {e}")
|
|
|
|
def _draw_plane_parameters(self, node, has_collision=True):
|
|
"""绘制平面参数"""
|
|
try:
|
|
imgui.text("平面参数:")
|
|
|
|
# 获取当前法向量
|
|
normal = self._get_plane_normal(node)
|
|
|
|
# 法向量调整
|
|
changed, new_x = imgui.drag_float("法向量 X##plane_normal_x", normal[0], 0.1, -1.0, 1.0, "%.2f")
|
|
if imgui.is_item_activated() and has_collision:
|
|
self._begin_collision_edit_session(node, "collision_plane_normal")
|
|
if changed and has_collision:
|
|
self._update_plane_normal(node, 'x', new_x)
|
|
self._finish_collision_edit_session(node, "collision_plane_normal")
|
|
|
|
changed, new_y = imgui.drag_float("法向量 Y##plane_normal_y", normal[1], 0.1, -1.0, 1.0, "%.2f")
|
|
if imgui.is_item_activated() and has_collision:
|
|
self._begin_collision_edit_session(node, "collision_plane_normal")
|
|
if changed and has_collision:
|
|
self._update_plane_normal(node, 'y', new_y)
|
|
self._finish_collision_edit_session(node, "collision_plane_normal")
|
|
|
|
changed, new_z = imgui.drag_float("法向量 Z##plane_normal_z", normal[2], 0.1, -1.0, 1.0, "%.2f")
|
|
if imgui.is_item_activated() and has_collision:
|
|
self._begin_collision_edit_session(node, "collision_plane_normal")
|
|
if changed and has_collision:
|
|
self._update_plane_normal(node, 'z', new_z)
|
|
self._finish_collision_edit_session(node, "collision_plane_normal")
|
|
|
|
except Exception as e:
|
|
print(f"绘制平面参数失败: {e}")
|
|
|