use glam::{DVec3, IVec3};
use roxlap_scene::{
CharacterBody, CharacterDef, GridTransform, MoveMode, Scene, Solidity, VoxColor, WalkInput,
};
const WATER: VoxColor = VoxColor::rgb(0x30, 0x60, 0xc8);
fn water_passes(c: VoxColor) -> bool {
c.rgb_part() == WATER.rgb_part()
}
fn build_world() -> Scene {
let mut scene = Scene::new();
let id = scene.add_grid(GridTransform::identity());
let g = scene.grid_mut(id).expect("grid");
g.set_rect(
IVec3::new(20, 20, 100),
IVec3::new(140, 140, 120),
Some(VoxColor::rgb(0x4d, 0x8a, 0x3a)),
);
g.set_rect(
IVec3::new(90, 20, 99),
IVec3::new(140, 140, 99),
Some(VoxColor::rgb(0x77, 0x66, 0x55)),
);
g.set_rect(
IVec3::new(60, 70, 60),
IVec3::new(62, 140, 99),
Some(VoxColor::rgb(0x88, 0x44, 0x44)),
);
g.set_rect(IVec3::new(40, 40, 80), IVec3::new(41, 60, 99), Some(WATER));
scene
}
fn main() {
let scene = build_world();
let mut body = CharacterBody::new(CharacterDef {
radius: 0.4, height: 1.8, eye_height: 1.62, step_up: 1.05, solidity: Solidity {
bedrock_blocks: false, passable: Some(water_passes),
},
..CharacterDef::default()
});
body.teleport(DVec3::new(50.0, 50.0, 95.0));
let dt = 1.0 / 60.0;
for frame in 0..480 {
let input = WalkInput {
wish: DVec3::new(1.0, 0.2, 0.0), jump: frame == 120, ..WalkInput::default() };
body.walk(&scene, dt, input);
}
let eye = body.eye_pos();
assert!(body.on_ground(), "settled after the hop");
assert!(body.pos().x > 90.0, "reached the ledge region");
assert!(
(body.pos().z - 99.0).abs() < 0.01,
"standing on the ledge, feet at {}",
body.pos().z
);
assert!(eye.z < body.pos().z, "the eye is above the feet (-z is up)");
body.set_mode(MoveMode::Fly);
body.walk(&scene, dt, WalkInput::default());
assert_eq!(body.vel(), DVec3::ZERO, "fly idles in place");
let wading = roxlap_scene::box_overlaps_solid(
&scene,
DVec3::new(40.2, 50.0, 90.0),
DVec3::new(40.8, 50.6, 91.8),
body.def().solidity,
);
assert!(!wading, "water is passable under the veto");
swim_demo();
println!("book_controller: all controller assertions hold");
}
fn swim_demo() {
let mut scene = Scene::new();
let id = scene.add_grid(GridTransform::identity());
let g = scene.grid_mut(id).expect("grid");
g.set_rect(
IVec3::new(20, 20, 120),
IVec3::new(140, 140, 130),
Some(VoxColor::rgb(0x50, 0x90, 0x50)),
);
g.add_water_volume(IVec3::new(20, 20, 100), IVec3::new(140, 140, 119));
let mut body = CharacterBody::new(CharacterDef::default());
body.teleport(DVec3::new(80.0, 80.0, 115.0)); for _ in 0..600 {
body.walk(&scene, 1.0 / 60.0, WalkInput::default());
}
assert!(body.is_swimming(), "floated to the surface bob");
assert!(!body.eye_in_water(&scene), "bobbing: the camera is dry");
for _ in 0..90 {
body.walk(
&scene,
1.0 / 60.0,
WalkInput {
sink: true,
..WalkInput::default()
},
);
}
assert!(body.eye_in_water(&scene), "diving: tint + muffle now");
}