Po dodaniu lub zmianie kolizji pozostaw zaznaczony główny obiekt. Tak by bez klikania w inne meshe można ponownie zmieni c rodzaj kolizji. Aktualnie, chyba, jest zaznaczone po zmienie dziecko.

bl_info = {
    "name": "AutoCollision",
    "blender": (4, 1, 0),
    "category": "Object",
    "author": "OshQRD Studio",
    "version": (1, 6),
    "description": "Creates collision objects as wireframe instances of the original.",
    "location": "View3D > Collisions",
    "warning": "",
    "doc_url": "",
    "tracker_url": "",
    "support": "COMMUNITY",
    "license": "Personal, Non-Commercial, No-Derivatives",
}

import bpy
from bpy.props import BoolProperty, StringProperty, EnumProperty, PointerProperty
from bpy.types import Operator, PropertyGroup, Panel
from mathutils import Vector

# Global queue for confirm dialogs
confirm_queue = []

# Properties
class CollisionGeneratorProperties(PropertyGroup):
    collision_suffix: EnumProperty(
        name="Suffix",
        description="Collision name suffix",
        items=[
            ('-col', "-col", "-col"),
            ('-colonly', "-colonly", "-colonly")
        ],
        default='-col'
    )

    collision_detail: EnumProperty(
        name="Collision Detail",
        description="Choose collision detail level",
        items=[
            ('BOUNDS', "Bounding Box", "Simple cube bounding box"),
            ('EXACT', "Exact Copy", "Copy of the mesh object")
        ],
        default='BOUNDS'
    )

# Confirm Replace Collision Operator
class OBJECT_OT_confirm_replace_collision(Operator):
    bl_idname = "object.confirm_replace_collision"
    bl_label = "Confirm Replace Collision"
    bl_options = {'INTERNAL'}

    obj_name: StringProperty()
    suffix: StringProperty()
    ok_for_all: BoolProperty(default=False)

    def execute(self, context):
        global confirm_queue
        obj = bpy.data.objects.get(self.obj_name)
        props = context.scene.collision_generator_props

        if not obj:
            self.report({'WARNING'}, "Object does not exist")
            return {'CANCELLED'}

        for sfx in ['-col', '-colonly']:
            collision_name = obj.name + sfx
            if collision_name in bpy.data.objects:
                bpy.data.objects.remove(bpy.data.objects[collision_name], do_unlink=True)

        new_obj = OBJECT_OT_generate_collision.create_collision_static(obj, self.suffix, props.collision_detail)

        if self.ok_for_all:
            while confirm_queue:
                next_obj_name, next_suffix = confirm_queue.pop(0)
                next_obj = bpy.data.objects.get(next_obj_name)
                if next_obj:
                    for sfx in ['-col', '-colonly']:
                        collision_name = next_obj.name + sfx
                        if collision_name in bpy.data.objects:
                            bpy.data.objects.remove(bpy.data.objects[collision_name], do_unlink=True)
                    OBJECT_OT_generate_collision.create_collision_static(next_obj, next_suffix, props.collision_detail)
        else:
            if confirm_queue:
                next_item = confirm_queue.pop(0)
                bpy.ops.object.confirm_replace_collision('INVOKE_DEFAULT',
                                                         obj_name=next_item[0],
                                                         suffix=next_item[1])

        self.report({'INFO'}, f"Replaced collision for {obj.name}")
        return {'FINISHED'}

    def invoke(self, context, event):
        return context.window_manager.invoke_props_dialog(self)

    def draw(self, context):
        layout = self.layout
        layout.label(text=f"Replace collision for: {self.obj_name}?")
        layout.prop(self, "ok_for_all", text="Ok for all remaining")

# Generate Collision Operator
class OBJECT_OT_generate_collision(Operator):
    bl_idname = "object.generate_collision"
    bl_label = "Generate Collision"
    bl_description = "Creates collision instances"
    bl_options = {'REGISTER', 'UNDO'}

    all_objects: BoolProperty(name="For all objects", default=False)

    def execute(self, context):
        global confirm_queue
        props = context.scene.collision_generator_props
        suffix = props.collision_suffix
        detail = props.collision_detail

        objects = [obj for obj in (context.selected_objects if not self.all_objects else context.scene.objects) if obj and obj.type == 'MESH']

        if not objects:
            self.report({'WARNING'}, "No selected objects")
            return {'CANCELLED'}

        count = 0
        for obj in objects:
            if obj.name.endswith('-col') or obj.name.endswith('-colonly'):
                continue

            existing = None
            existing_suffix = None
            for sfx in ['-col', '-colonly']:
                collision_name = obj.name + sfx
                if collision_name in bpy.data.objects:
                    existing = bpy.data.objects[collision_name]
                    existing_suffix = sfx
                    break

            if existing:
                if existing_suffix == suffix:
                    continue
                confirm_queue.append((obj.name, suffix))
                continue

            OBJECT_OT_generate_collision.create_collision_static(obj, suffix, detail)
            count += 1

        if confirm_queue:
            next_item = confirm_queue.pop(0)
            bpy.ops.object.confirm_replace_collision('INVOKE_DEFAULT', obj_name=next_item[0], suffix=next_item[1])

        self.report({'INFO'}, f"Generated {count} collisions")
        return {'FINISHED'}

    @staticmethod
    def create_collision_static(obj, suffix, detail='BOUNDS'):
        new_name = obj.name + suffix

        if detail == 'EXACT':
            new_obj = obj.copy()
            new_obj.data = obj.data
        else:
            bpy.ops.mesh.primitive_cube_add()
            new_obj = bpy.context.active_object
            bbox_corners = [obj.matrix_world @ Vector(corner) for corner in obj.bound_box]
            min_corner = Vector((min([v[i] for v in bbox_corners]) for i in range(3)))
            max_corner = Vector((max([v[i] for v in bbox_corners]) for i in range(3)))
            center = (min_corner + max_corner) / 2
            size = max_corner - min_corner
            new_obj.location = center
            new_obj.scale = size / 2

        new_obj.name = new_name
        new_obj["is_collision"] = True

        if obj.users_collection:
            for col in obj.users_collection:
                if new_obj.name not in col.objects:
                    col.objects.link(new_obj)
        else:
            bpy.context.collection.objects.link(new_obj)

        new_obj.parent = obj
        new_obj.matrix_parent_inverse = obj.matrix_world.inverted()

        new_obj.display_type = 'WIRE'
        new_obj.show_wire = True
        new_obj.show_all_edges = True
        new_obj.hide_render = True

        return new_obj

# Delete Collisions Operator
class OBJECT_OT_delete_collisions(Operator):
    bl_idname = "object.delete_collisions"
    bl_label = "Delete Collisions"
    bl_description = "Removes collision objects"
    bl_options = {'REGISTER', 'UNDO'}

    all_objects: BoolProperty(name="From all objects", default=False)

    def execute(self, context):
        suffixes = ['-col', '-colonly']
        to_check = context.selected_objects if not self.all_objects else list(context.scene.objects)
        deleted = 0

        for obj in list(to_check):
            try:
                if not obj or not obj.name:
                    continue
                if any(obj.name.endswith(sfx) for sfx in suffixes):
                    bpy.data.objects.remove(obj, do_unlink=True)
                    deleted += 1
                    continue

                for child in obj.children:
                    if any(child.name == obj.name + sfx for sfx in suffixes):
                        bpy.data.objects.remove(child, do_unlink=True)
                        deleted += 1
            except ReferenceError:
                continue

        self.report({'INFO'}, f"Deleted {deleted} collisions")
        return {'FINISHED'}

# UI Panel
class VIEW3D_PT_collision_generator(Panel):
    bl_label = "AutoCollision"
    bl_idname = "VIEW3D_PT_collision_generator"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "Collisions"

    def draw(self, context):
        props = context.scene.collision_generator_props
        layout = self.layout

        layout.prop(props, "collision_suffix", text="Suffix")
        layout.prop(props, "collision_detail", text="Detail Level")

        layout.operator("object.generate_collision", text="Collision for Selected").all_objects = False
        layout.operator("object.generate_collision", text="Collision for All").all_objects = True
        layout.separator()
        layout.operator("object.delete_collisions", text="Delete from Selected").all_objects = False
        layout.operator("object.delete_collisions", text="Delete from All").all_objects = True

# Registration
classes = (
    CollisionGeneratorProperties,
    OBJECT_OT_generate_collision,
    OBJECT_OT_delete_collisions,
    OBJECT_OT_confirm_replace_collision,
    VIEW3D_PT_collision_generator,
)

def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    bpy.types.Scene.collision_generator_props = PointerProperty(type=CollisionGeneratorProperties)

def unregister():
    for cls in reversed(classes):
        bpy.utils.unregister_class(cls)
    del bpy.types.Scene.collision_generator_props

if __name__ == "__main__":
    register()