Blender Combat Demo
App: apps/combat_blender_demo/
Demonstrates Blender-authored combat (engine PLM-198 / ADR 0069) end to end: CombatVolumes.blend
carries a Fighter armature with a sword hitbox and a body hurtbox authored in Blender —
bone-parented meshes placed in the Plume_Hitboxes / Plume_Hurtboxes collections (Passive + Animated
rigid bodies). No hitbox geometry lives in code.
The demo instantiates the Fighter twice, tells the engine who owns which boxes
(owner is game-side), and lunges one into the other. The engine turns each Blender volume into a
bone-attached Jolt sensor, Jolt reports the overlap, and Combat.onHit
fires. Health is the game’s — here the demo just tallies strikes.
Run from root
Section titled “Run from root”% ./plume3d combat_blender_demoThe attacker closes in and lands strikes; a GUI overlay shows the running hit count.
What it does
Section titled “What it does”- On
init, loadsCombatVolumes.blendand instantiates the Fighter twice (attacker + target). - Reads each character’s Blender-authored volumes off the tag maps —
character.hitboxesandcharacter.hurtboxes— and setsowneron every box (a hitbox never strikes its own owner). This is the whole “who is whose enemy” wiring; the shapes and bone attachment came from Blender. - Registers
Combat.onHit(scene) { |hit| … }and tallies each strike. What a hit costs would be the game’s business — there is no HP type in the engine. - In
update, lunges the attacker along +X until the authoredswordvolume overlaps the target’sbodyvolume, at which point the sensor firesonHit.
Key pattern
Section titled “Key pattern”import "engine" for Scene, Resource, Combat
var scene = Scene.new()var res = Resource.loadBlend("CombatVolumes.blend")var a = res.instantiate("Fighter", scene) // attacker — carries Blender-authored volumesvar b = res.instantiate("Fighter", scene) // target
// The GAME assigns identity; geometry + bone attachment came from Blender.for (hb in a.hitboxes.values) { hb.owner = 1 }for (hu in a.hurtboxes.values) { hu.owner = 1 }for (hb in b.hitboxes.values) { hb.owner = 2 }for (hu in b.hurtboxes.values) { hu.owner = 2 }
Combat.onHit(scene) { |hit| // engine detected the overlap; the game owns the consequence (damage/HP/death live here)}Authoring the volumes in Blender
Section titled “Authoring the volumes in Blender”The Plume3D Blender add-on ships a Combat Volumes
panel: select the mesh, click Mark Hitbox / Mark Hurtbox, and it sets a Passive + Animated
rigid body and moves the object into Plume_Hitboxes / Plume_Hurtboxes. The object name becomes the
tag (sword → hitboxes["sword"]). Bone-parent the mesh to the bone it should ride. That’s the whole
authoring contract — see Combat → Authoring volumes in Blender.
Verify headless
Section titled “Verify headless”% ./plume3d --test apps/combat_blender_demoAsserts the Blender-authored volumes surface on the instantiated character: hitboxes has the sword
key, hurtboxes has the body key, and setting owner on them does not crash. The hit mechanics
(sensor overlap, dedup, lifecycle) are covered by tests/unit/test_combat_hitbox.cpp and
test_combat_wren.cpp.