Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Feb 1, 2026

Implements destructible physics bodies that split into box-shaped chunks when damaged. Chunks recursively split based on excess damage with staggered delays.

Core System

  • invariants::destructible: max_health, make_dynamic_below_area, disable_below_area, money_spawned_min/max
  • components::destructible: runtime health and texture_rect (0-1 UV space for chunk bounds)
  • destructible_sprited_body: new entity type with destructible components
  • destruction_system::apply_damages_and_split_fixtures: processes damage, splits entities when health ≤ 0

Splitting Algorithm

  • Always splits along longer edge to avoid thin pathological chunks
  • Split position clamped to ±10% deviation from edge center
  • Health scaled proportionally: new_health = root_max_health * new_texture_rect.area()
  • Excess damage queued as pending_destruction with staggered delays

Safe Entity Cloning

Introduced queue_clone_entity to prevent pool reallocation during iteration:

step.queue_clone_entity(subject.get_id(), [=](auto new_entity) {
    new_entity.template get<components::destructible>().texture_rect = new_split_rect;
    // ... position, reinfer, apply impulse
});
// Flushed after destruction_system completes

Physics Integration

  • calc_body_type: static → dynamic when area ≤ make_dynamic_below_area threshold
  • calc_filters: chunks below disable_below_area get LYING_ITEM filter
  • from_box_shape: scales fixture by texture_rect.{w,h}

Effects

  • standard_destruction_sound/particles on first split
  • lesser_destruction_sound on subsequent splits (prevents sound spam)
  • Pitch scales up for smaller chunks: 1.0 + 0.4 * (1.0 - area)
  • Particle scale decreases: 0.6 + 0.4 * area
  • default_coin_flavours in common_assets for money drops

Editor

  • "Destructible" checkbox with health, make_dynamic_below_area, disable_below_area, money_spawned_min/max
  • Only available for box-based shapes (no custom polygons)
  • Material editor exposes destruction sound/particle overrides
Original prompt

Basic box-based destructability

Have a new components::destructible added to plain_sprited_body.
In it hold:

real32 max_health = -1.0f;
real32 health = -1.0f;
xywh texture_rect = xywh(0,0,1.0f,1.0f); // in 0-1 space. if 0,0,1.0f,1.0f, was never split yet. (0,0) is top-left in UV space.

The texture_rect will be the overridden u/v coordinates of a given chunk.

In draw_entity.h you should take into consideration whether the drawn entity has a components::destrcutible and if so consider its overridden texture_rect.

Handle these damages in destruction_system::apply_damages_and_split_fixtures like process_damages_and_generate_health_events does.
if max_health == -1 then destructibility is disabled and you can skip damage to that entity in this function.

E.g. sentience system processes its damages in process_damages_and_generate_health_events.

Generating chunks

When health goes below zero we split the entity into two always:

  1. take the finishing damage's point of impact
  2. consider the rect: box's actual sprite size via handle.get_logical_size positioned with get_logic_transform().
  3. if the area is less than 100 pixels (world units), just delete that entity (but spawn destruction effects nonetheless)
  4. otherwise find the EDGE of the rectangle that is the closest to the point of impact (use some projection functions in vec2 - doesnt matter if point is outside or inside rectangle).
  5. limit the closesness to the corner: if closer than 5 pixels to the corner, move it away to the edge's center.
  6. however if corner-avoidance would be impossible because of the usable split region (edge length ≤ 10px), just split exactly in half.
  7. Split as if you drew a straight line from that point towards the corresponding point on the opposite edge. You will have a bigger and a smaller split now. This will still result in two boxes (plain rectangles), we're not doing any funny polygons here.
  8. The bigger split is the already existing entity. The smaller split will need to be created with just_clone_entity. If they're exactly half, doesnt matter which.
  9. Set the texture_rect of both splits appropriately.
  10. position the new split appropriately so it is visually exactly in the place where it would peel off. Note the old split also needs to be repositioned because its center will change.
  11. given: o = max_health of before split and oa = texture_rect of before split, reset the new splits' max_health and health to o / oa.area() * new_split.texture_rect.area(). This will calculate the root chunk's max_health (the first to ever exist before splitting) and properly scale it with the new split's area. set max_health = health in the new split. Check if oa.area() is zero before division, if it is just delete dont split, as if it was less than 100 px, but you will probably calculate it at the very beginning before splitting logic.
  12. Reinfer both splits after you're done with positioning etc. physics_world_cache.hpp should now take care to, when creating fixtures from_box_shape, properly consider the destructible component and set the size accordingly to texture_rect. It will also possilby change the body type through calc_body_type.
  13. Apply separating impact to both spawned chunks, proportionally to the final damage that made them split.

Highlights

Applying damage events to destructible bodies should spawn white pure color highlights, proportional to % of the destroyed health/max_health. If you destroyed 50% of max_health or more, make it 100% pure color highlight. If it's just (hypothetical) 0% health, make it a 10%, barely visibler pure color highlight. so highlight linearly strong with damage.

Destruction effect

Should depend on the physical material (physical_material.h).
Add equivalents of these:

sound_effect_input standard_damage_sound;
particle_effect_input standard_damage_particles;

So:
sound_effect_input standard_destruction_sound;
particle_effect_input standard_destruction_particles;

And if they are unset which they will be for now, in logic fall back to standard_damage_sound etc.
Make standard_destruction_sound etc editable in editor.

Transition static to dynamic body

If a plain sprited body is static, the splits might become dynamic upon destruction. If any split becomes <= 60% of the original (determined easily by texture_rect area), make it dynamic as well. Calculate it statelessly in calc_body_type and remember to reinfer both original and new chunk upon destruction event.

Editor

Make a tick "Destructible" and if its ticked then have another property "health". This prop will be written to max_health in the components::destructible.

However tick "Destructible" should be editable ONLY on resources that don't have a custom shape defined because this will obviosuly work only on box-based shapes only for now. We screw circles, polygons etc for now.

Details

Note for things to work correctly you have to consider components::destructible in find_aabb in spatial_properties_mixin.h. A...


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI changed the title [WIP] Add destructible component to plain_sprited_body Add basic box-based destructibility system Feb 1, 2026
Copilot AI requested a review from geneotech February 1, 2026 16:29
Copilot AI changed the title Add basic box-based destructibility system Improve destructibility: longer-edge splitting, recursive damage, configurable dynamic threshold Feb 1, 2026
Copilot AI changed the title Improve destructibility: longer-edge splitting, recursive damage, configurable dynamic threshold Basic box-based destructibility system with recursive splitting Feb 1, 2026
Copilot AI and others added 14 commits February 1, 2026 22:06
Co-authored-by: geneotech <3588717+geneotech@users.noreply.github.com>
Co-authored-by: geneotech <3588717+geneotech@users.noreply.github.com>
Co-authored-by: geneotech <3588717+geneotech@users.noreply.github.com>
Co-authored-by: geneotech <3588717+geneotech@users.noreply.github.com>
… longer edge splitting

Co-authored-by: geneotech <3588717+geneotech@users.noreply.github.com>
…port

Co-authored-by: geneotech <3588717+geneotech@users.noreply.github.com>
Co-authored-by: geneotech <3588717+geneotech@users.noreply.github.com>
…matting

Co-authored-by: geneotech <3588717+geneotech@users.noreply.github.com>
Co-authored-by: geneotech <3588717+geneotech@users.noreply.github.com>
Co-authored-by: geneotech <3588717+geneotech@users.noreply.github.com>
Co-authored-by: geneotech <3588717+geneotech@users.noreply.github.com>
@geneotech geneotech force-pushed the copilot/add-components-destructible branch from 9a8ef9b to d5eff6e Compare February 1, 2026 21:28
@geneotech
Copy link
Member

@copilot Trying to add destructible plain sprites support to the editor but i might be forgetting something because it hits me with
throw augs::json_deserialization_error("Invalid "type" property for node "%x".\nResource "%x" not found!", id, type);

[22:26:18] Invalid "type" property for node "crate".
Resource "crate" not found!

when i try to load shooting_range.json with a "crate" resource. I made CRATE destructible sprite now. Try to fix it for me.

Also remember in build_arena_from_editor_project.hpp when you're building a scene to use destructible_sprited_body instead of plain_sprited_body for destructible entities. otherwise there wont be auto destructible = agg.template findcomponents::destructible() inside the editor_rebuild_node.hpp.

Co-authored-by: geneotech <3588717+geneotech@users.noreply.github.com>
Co-authored-by: geneotech <3588717+geneotech@users.noreply.github.com>
Copilot AI changed the title Basic box-based destructibility system with recursive splitting Add box-based destructibility system with recursive splitting Feb 2, 2026
Co-authored-by: geneotech <3588717+geneotech@users.noreply.github.com>
Copilot AI changed the title Add box-based destructibility system with recursive splitting Basic box-based destructibility system with recursive splitting Feb 2, 2026
…ariants::destructible

Co-authored-by: geneotech <3588717+geneotech@users.noreply.github.com>
Copilot AI changed the title Basic box-based destructibility system with recursive splitting Add box-based destructibility system with recursive splitting Feb 2, 2026
Copilot AI and others added 2 commits February 2, 2026 01:04
Co-authored-by: geneotech <3588717+geneotech@users.noreply.github.com>
Co-authored-by: geneotech <3588717+geneotech@users.noreply.github.com>
Copilot AI changed the title Add box-based destructibility system with recursive splitting Basic box-based destructibility system with recursive splitting Feb 2, 2026
@geneotech
Copy link
Member

@copilot zaokraglaj mi w /gmud punkty do inta i pisz tam ktore ma kazdy miejsce np.

  1. nick punkty
  2. drugi nick punkty
    tylko wez pod uwage skracanie nickow jak rosnie liczba ktore miejsce

Copy link
Contributor Author

Copilot AI commented Feb 6, 2026

@copilot zaokraglaj mi w /gmud punkty do inta i pisz tam ktore ma kazdy miejsce np.

  1. nick punkty
  2. drugi nick punkty
    ...

The /gmud command doesn't appear to exist in this repository codebase. This comment may be intended for a different project or PR. If there's a specific file or feature in this repo you'd like me to modify, please let me know where to find it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants