Map-Loader entfernt: glTF ist das einzige 3D-Format
engine/map.rs + render/brush.rs raus, Welt kommt komplett aus .glb. Spawn via Empty mit role=spawn statt info_player_start; testscene.glb (Boden, Wände, Spawn) ersetzt test.map. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+33
-31
@@ -1,7 +1,6 @@
|
||||
use crate::engine::collision::CollisionWorld;
|
||||
use crate::engine::game::{Action, Game, ModeTarget};
|
||||
use crate::engine::ink::StoryState;
|
||||
use crate::engine::map::{self, Map};
|
||||
use crate::engine::player::{self, Player};
|
||||
use crate::engine::trigger::Triggers;
|
||||
use crate::engine::{kv, model, signals, story_ctrl};
|
||||
@@ -83,8 +82,8 @@ impl Session {
|
||||
Self {
|
||||
game,
|
||||
mode: Mode::Menu,
|
||||
// Default-Welt, bis `load_world` eine Map einspielt (die CLI
|
||||
// braucht keine — sie tickt nie).
|
||||
// Default-Spawn, bis ein Modell einen `role=spawn`-Empty
|
||||
// mitbringt (die CLI braucht keine Welt — sie tickt nie).
|
||||
player: Player::new([0.0, 1.0, 0.0]),
|
||||
collision: CollisionWorld::empty(),
|
||||
triggers: Triggers::new(),
|
||||
@@ -94,23 +93,21 @@ impl Session {
|
||||
}
|
||||
}
|
||||
|
||||
/// Welt-Geometrie aus der Map laden: Collision-Brushes bauen und den
|
||||
/// Spieler an `info_player_start` setzen. Einmal vom Fenster-Frontend beim
|
||||
/// Start gerufen.
|
||||
pub fn load_world(&mut self, map: &Map) {
|
||||
self.collision = CollisionWorld::build(map);
|
||||
self.triggers = Triggers::new();
|
||||
self.player = Player::new(player_spawn(map));
|
||||
}
|
||||
|
||||
/// Sim-Seite eines Blender-Modells in die bestehende Welt einfügen —
|
||||
/// 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).
|
||||
/// Sim-Seite eines Blender-Modells in die Welt einfügen — einmal pro
|
||||
/// Modell vom Fenster-Frontend beim Start gerufen: Collider (`collide`-
|
||||
/// Property → konvexe Hülle), Trigger (`signal`-Property → Klick-Ziele/
|
||||
/// Zonen) und der Spieler-Spawn (Empty mit `role = spawn`; bringen
|
||||
/// mehrere Modelle einen mit, gewinnt der zuletzt geladene). 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);
|
||||
for e in &model.empties {
|
||||
if e.props.get(model::ROLE_PROP).map(String::as_str) == Some(model::ROLE_SPAWN) {
|
||||
self.player = Player::new(e.pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Einen Simulationsschritt treiben — das kontinuierliche Gegenstück zu
|
||||
@@ -362,20 +359,6 @@ impl Session {
|
||||
}
|
||||
}
|
||||
|
||||
/// Spawn-Fußpunkt (Engine-Koords) aus `info_player_start`; sonst ein Default.
|
||||
fn player_spawn(map: &Map) -> [f32; 3] {
|
||||
for e in &map.entities {
|
||||
if e.classname() == Some("info_player_start")
|
||||
&& let Some(origin) = e.props.get("origin") {
|
||||
let v: Vec<f32> = origin.split_whitespace().filter_map(|s| s.parse().ok()).collect();
|
||||
if let [x, y, z] = v[..] {
|
||||
return map::to_engine([x, y, z]);
|
||||
}
|
||||
}
|
||||
}
|
||||
[0.0, 1.0, 0.0]
|
||||
}
|
||||
|
||||
fn help() -> Vec<String> {
|
||||
vec![
|
||||
" signal <s> Signal feuern oder Action direkt ausführen".into(),
|
||||
@@ -578,6 +561,25 @@ mod tests {
|
||||
assert_eq!(s.pick([5.5, 0.5, 0.0], [0.0, 0.0, 1.0], INTERACT_REACH), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spawn_empty_places_player() {
|
||||
let mut s = empty_session();
|
||||
let mut props = crate::engine::model::Props::new();
|
||||
props.insert("role".into(), "spawn".into());
|
||||
s.load_props(&crate::engine::model::Model {
|
||||
objects: Vec::new(),
|
||||
empties: vec![
|
||||
crate::engine::model::Empty { name: "start".into(), pos: [3.0, 0.5, -2.0], props },
|
||||
crate::engine::model::Empty {
|
||||
name: "deko".into(), pos: [9.0, 9.0, 9.0],
|
||||
props: crate::engine::model::Props::new(),
|
||||
},
|
||||
],
|
||||
materials: Vec::new(),
|
||||
});
|
||||
assert_eq!(s.player.pos, [3.0, 0.5, -2.0], "role=spawn setzt den Fußpunkt");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_command_reports_and_stays_free() {
|
||||
let mut s = empty_session();
|
||||
|
||||
Reference in New Issue
Block a user