Collider via collide-Property + Quickhull, OBJ-Pfad entfernt

col_*-Namenspräfix raus: Rollen steuern nur noch Custom Properties
(collide=1 sichtbar+Collider, "proxy" unsichtbar, signal wie gehabt).
Collider sind die konvexe Hülle der Vertices — konkave Meshes erlaubt.
glb ist der einzige Modell-Pfad; suzanne.obj → suzanne.glb.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-16 19:14:42 +02:00
parent f7bfdb4a0b
commit 9db3929750
12 changed files with 371 additions and 2497 deletions
+10 -10
View File
@@ -104,10 +104,10 @@ impl Session {
}
/// Sim-Seite eines Blender-Modells in die bestehende Welt einfügen —
/// nach `load_world` rufen, einmal pro Modell: Collision-Proxies
/// (`col_*`) und Trigger (`signal`-Property → Klick-Ziele/Zonen). Die
/// Sichtgeometrie desselben Modells ist Sache des Renderers
/// (render::props).
/// nach `load_world` rufen, einmal pro Modell: Collider (`collide`-
/// Property → konvexe Hülle) und Trigger (`signal`-Property →
/// Klick-Ziele/Zonen). Die Sichtgeometrie desselben Modells ist Sache
/// des Renderers (render::props).
pub fn load_props(&mut self, model: &model::Model) {
self.collision.add_model(model);
self.triggers.add_model(model);
@@ -526,9 +526,9 @@ mod tests {
crate::engine::model::Model {
objects: vec![
crate::engine::model::test_cube(
"Zone.001", [-0.5, 0.0, -3.0], Some("set zone_hit true")),
"Zone.001", [-0.5, 0.0, -3.0], None, Some("set zone_hit true")),
crate::engine::model::test_cube(
"col_Kiste", [5.0, 0.0, 5.0], Some("set kiste_geklickt true")),
"Kiste", [5.0, 0.0, 5.0], Some("1"), Some("set kiste_geklickt true")),
],
empties: Vec::new(),
materials: vec![String::new()],
@@ -558,8 +558,8 @@ mod tests {
let mut s = empty_session();
s.load_props(&trigger_model());
s.mode = Mode::FirstPerson;
// Klick-Ziel: feuert den Property-Wert, nicht signal_key("col_Kiste").
s.exec("use col_Kiste");
// Klick-Ziel: feuert den Property-Wert, nicht signal_key("Kiste").
s.exec("use Kiste");
assert!(s.game.kv["kiste_geklickt"].coerce_to_bool().unwrap());
// Ohne Property wie gehabt: Name (suffix-gestrippt) als Signal — hier
// unbekannt und ohne Table ein stilles No-Op, aber kein Fehler.
@@ -571,9 +571,9 @@ mod tests {
fn pick_hits_clickable_within_reach() {
let mut s = empty_session();
s.load_props(&trigger_model());
// col_Kiste bei [5..6, 0..1, 5..6]: Strahl von schräg oben davor.
// Kiste bei [5..6, 0..1, 5..6]: Strahl von schräg oben davor.
let hit = s.pick([5.5, 0.5, 3.0], [0.0, 0.0, 1.0], INTERACT_REACH);
assert_eq!(hit, Some("col_Kiste"));
assert_eq!(hit, Some("Kiste"));
// Außer Reichweite → nichts.
assert_eq!(s.pick([5.5, 0.5, 0.0], [0.0, 0.0, 1.0], INTERACT_REACH), None);
}