pub struct CharacterBody { /* private fields */ }Expand description
A walking body: feet-positioned collision box + velocity +
contact flags. Construct with CharacterBody::new, place with
teleport, then call
walk once per frame.
Implementations§
Source§impl CharacterBody
impl CharacterBody
Sourcepub fn new(def: CharacterDef) -> Self
pub fn new(def: CharacterDef) -> Self
A body at the world origin with zero velocity — call
teleport before the first walk.
Examples found in repository?
61fn main() {
62 let scene = build_world();
63
64 // ANCHOR: setup
65 // A walking body: a feet-positioned collision box, f64 world.
66 // Distances are voxels, times seconds; +z is DOWN, so gravity is
67 // positive and a jump impulse negative.
68 let mut body = CharacterBody::new(CharacterDef {
69 radius: 0.4, // xy half-extent of the box
70 height: 1.8, // feet → head (toward -z)
71 eye_height: 1.62, // feet → camera anchor
72 step_up: 1.05, // auto-step ledges up to 1 voxel
73 solidity: Solidity {
74 bedrock_blocks: false, // match your renderer's policy
75 passable: Some(water_passes),
76 },
77 ..CharacterDef::default()
78 });
79 body.teleport(DVec3::new(50.0, 50.0, 95.0)); // FEET position
80 // ANCHOR_END: setup
81
82 // ANCHOR: frame
83 // Per frame: build a wish direction from input (unit-length or
84 // zero — walk() clamps), call walk() EVERY frame (a zero wish is
85 // what stops the body), then anchor the camera at the eye.
86 let dt = 1.0 / 60.0;
87 for frame in 0..480 {
88 let input = WalkInput {
89 wish: DVec3::new(1.0, 0.2, 0.0), // toward the ledge
90 jump: frame == 120, // one hop on the way
91 };
92 body.walk(&scene, dt, input);
93 }
94 let eye = body.eye_pos(); // = Camera::from_yaw_pitch(eye.into(), yaw, pitch)
95 // ANCHOR_END: frame
96
97 // The trajectory the walk above promises, pinned:
98 assert!(body.on_ground(), "settled after the hop");
99 // It fell to the floor plane, then stepped up the 1-voxel ledge
100 // (surface z = 99) while walking +x.
101 assert!(body.pos().x > 90.0, "reached the ledge region");
102 assert!(
103 (body.pos().z - 99.0).abs() < 0.01,
104 "standing on the ledge, feet at {}",
105 body.pos().z
106 );
107 assert!(eye.z < body.pos().z, "the eye is above the feet (-z is up)");
108
109 // Fly mode is the demos' free camera: no gravity, full-3D wish,
110 // instant start/stop, still sliding along walls.
111 body.set_mode(MoveMode::Fly);
112 body.walk(&scene, dt, WalkInput::default());
113 assert_eq!(body.vel(), DVec3::ZERO, "fly idles in place");
114
115 // The water curtain from `build_world` is passable: probe the
116 // veto directly (the same query walk() uses).
117 let wading = roxlap_scene::box_overlaps_solid(
118 &scene,
119 DVec3::new(40.2, 50.0, 90.0),
120 DVec3::new(40.8, 50.6, 91.8),
121 body.def().solidity,
122 );
123 assert!(!wading, "water is passable under the veto");
124
125 println!("book_controller: all controller assertions hold");
126}Sourcepub fn set_mode(&mut self, mode: MoveMode)
pub fn set_mode(&mut self, mode: MoveMode)
Switch movement mode. Velocity is kept — dropping out of
Fly mid-air falls with whatever speed you had.
Examples found in repository?
61fn main() {
62 let scene = build_world();
63
64 // ANCHOR: setup
65 // A walking body: a feet-positioned collision box, f64 world.
66 // Distances are voxels, times seconds; +z is DOWN, so gravity is
67 // positive and a jump impulse negative.
68 let mut body = CharacterBody::new(CharacterDef {
69 radius: 0.4, // xy half-extent of the box
70 height: 1.8, // feet → head (toward -z)
71 eye_height: 1.62, // feet → camera anchor
72 step_up: 1.05, // auto-step ledges up to 1 voxel
73 solidity: Solidity {
74 bedrock_blocks: false, // match your renderer's policy
75 passable: Some(water_passes),
76 },
77 ..CharacterDef::default()
78 });
79 body.teleport(DVec3::new(50.0, 50.0, 95.0)); // FEET position
80 // ANCHOR_END: setup
81
82 // ANCHOR: frame
83 // Per frame: build a wish direction from input (unit-length or
84 // zero — walk() clamps), call walk() EVERY frame (a zero wish is
85 // what stops the body), then anchor the camera at the eye.
86 let dt = 1.0 / 60.0;
87 for frame in 0..480 {
88 let input = WalkInput {
89 wish: DVec3::new(1.0, 0.2, 0.0), // toward the ledge
90 jump: frame == 120, // one hop on the way
91 };
92 body.walk(&scene, dt, input);
93 }
94 let eye = body.eye_pos(); // = Camera::from_yaw_pitch(eye.into(), yaw, pitch)
95 // ANCHOR_END: frame
96
97 // The trajectory the walk above promises, pinned:
98 assert!(body.on_ground(), "settled after the hop");
99 // It fell to the floor plane, then stepped up the 1-voxel ledge
100 // (surface z = 99) while walking +x.
101 assert!(body.pos().x > 90.0, "reached the ledge region");
102 assert!(
103 (body.pos().z - 99.0).abs() < 0.01,
104 "standing on the ledge, feet at {}",
105 body.pos().z
106 );
107 assert!(eye.z < body.pos().z, "the eye is above the feet (-z is up)");
108
109 // Fly mode is the demos' free camera: no gravity, full-3D wish,
110 // instant start/stop, still sliding along walls.
111 body.set_mode(MoveMode::Fly);
112 body.walk(&scene, dt, WalkInput::default());
113 assert_eq!(body.vel(), DVec3::ZERO, "fly idles in place");
114
115 // The water curtain from `build_world` is passable: probe the
116 // veto directly (the same query walk() uses).
117 let wading = roxlap_scene::box_overlaps_solid(
118 &scene,
119 DVec3::new(40.2, 50.0, 90.0),
120 DVec3::new(40.8, 50.6, 91.8),
121 body.def().solidity,
122 );
123 assert!(!wading, "water is passable under the veto");
124
125 println!("book_controller: all controller assertions hold");
126}Sourcepub fn def(&self) -> &CharacterDef
pub fn def(&self) -> &CharacterDef
The construction parameters.
Examples found in repository?
61fn main() {
62 let scene = build_world();
63
64 // ANCHOR: setup
65 // A walking body: a feet-positioned collision box, f64 world.
66 // Distances are voxels, times seconds; +z is DOWN, so gravity is
67 // positive and a jump impulse negative.
68 let mut body = CharacterBody::new(CharacterDef {
69 radius: 0.4, // xy half-extent of the box
70 height: 1.8, // feet → head (toward -z)
71 eye_height: 1.62, // feet → camera anchor
72 step_up: 1.05, // auto-step ledges up to 1 voxel
73 solidity: Solidity {
74 bedrock_blocks: false, // match your renderer's policy
75 passable: Some(water_passes),
76 },
77 ..CharacterDef::default()
78 });
79 body.teleport(DVec3::new(50.0, 50.0, 95.0)); // FEET position
80 // ANCHOR_END: setup
81
82 // ANCHOR: frame
83 // Per frame: build a wish direction from input (unit-length or
84 // zero — walk() clamps), call walk() EVERY frame (a zero wish is
85 // what stops the body), then anchor the camera at the eye.
86 let dt = 1.0 / 60.0;
87 for frame in 0..480 {
88 let input = WalkInput {
89 wish: DVec3::new(1.0, 0.2, 0.0), // toward the ledge
90 jump: frame == 120, // one hop on the way
91 };
92 body.walk(&scene, dt, input);
93 }
94 let eye = body.eye_pos(); // = Camera::from_yaw_pitch(eye.into(), yaw, pitch)
95 // ANCHOR_END: frame
96
97 // The trajectory the walk above promises, pinned:
98 assert!(body.on_ground(), "settled after the hop");
99 // It fell to the floor plane, then stepped up the 1-voxel ledge
100 // (surface z = 99) while walking +x.
101 assert!(body.pos().x > 90.0, "reached the ledge region");
102 assert!(
103 (body.pos().z - 99.0).abs() < 0.01,
104 "standing on the ledge, feet at {}",
105 body.pos().z
106 );
107 assert!(eye.z < body.pos().z, "the eye is above the feet (-z is up)");
108
109 // Fly mode is the demos' free camera: no gravity, full-3D wish,
110 // instant start/stop, still sliding along walls.
111 body.set_mode(MoveMode::Fly);
112 body.walk(&scene, dt, WalkInput::default());
113 assert_eq!(body.vel(), DVec3::ZERO, "fly idles in place");
114
115 // The water curtain from `build_world` is passable: probe the
116 // veto directly (the same query walk() uses).
117 let wading = roxlap_scene::box_overlaps_solid(
118 &scene,
119 DVec3::new(40.2, 50.0, 90.0),
120 DVec3::new(40.8, 50.6, 91.8),
121 body.def().solidity,
122 );
123 assert!(!wading, "water is passable under the veto");
124
125 println!("book_controller: all controller assertions hold");
126}Sourcepub fn def_mut(&mut self) -> &mut CharacterDef
pub fn def_mut(&mut self) -> &mut CharacterDef
Tune parameters at runtime — sprint (walk_speed /
fly_speed), variable jump height, etc. Growing radius /
height while standing in a tight spot can leave the body
overlapping solid; the stuck-escape rule makes that
recoverable rather than a jam.
Sourcepub fn pos(&self) -> DVec3
pub fn pos(&self) -> DVec3
Feet position, world space.
Examples found in repository?
61fn main() {
62 let scene = build_world();
63
64 // ANCHOR: setup
65 // A walking body: a feet-positioned collision box, f64 world.
66 // Distances are voxels, times seconds; +z is DOWN, so gravity is
67 // positive and a jump impulse negative.
68 let mut body = CharacterBody::new(CharacterDef {
69 radius: 0.4, // xy half-extent of the box
70 height: 1.8, // feet → head (toward -z)
71 eye_height: 1.62, // feet → camera anchor
72 step_up: 1.05, // auto-step ledges up to 1 voxel
73 solidity: Solidity {
74 bedrock_blocks: false, // match your renderer's policy
75 passable: Some(water_passes),
76 },
77 ..CharacterDef::default()
78 });
79 body.teleport(DVec3::new(50.0, 50.0, 95.0)); // FEET position
80 // ANCHOR_END: setup
81
82 // ANCHOR: frame
83 // Per frame: build a wish direction from input (unit-length or
84 // zero — walk() clamps), call walk() EVERY frame (a zero wish is
85 // what stops the body), then anchor the camera at the eye.
86 let dt = 1.0 / 60.0;
87 for frame in 0..480 {
88 let input = WalkInput {
89 wish: DVec3::new(1.0, 0.2, 0.0), // toward the ledge
90 jump: frame == 120, // one hop on the way
91 };
92 body.walk(&scene, dt, input);
93 }
94 let eye = body.eye_pos(); // = Camera::from_yaw_pitch(eye.into(), yaw, pitch)
95 // ANCHOR_END: frame
96
97 // The trajectory the walk above promises, pinned:
98 assert!(body.on_ground(), "settled after the hop");
99 // It fell to the floor plane, then stepped up the 1-voxel ledge
100 // (surface z = 99) while walking +x.
101 assert!(body.pos().x > 90.0, "reached the ledge region");
102 assert!(
103 (body.pos().z - 99.0).abs() < 0.01,
104 "standing on the ledge, feet at {}",
105 body.pos().z
106 );
107 assert!(eye.z < body.pos().z, "the eye is above the feet (-z is up)");
108
109 // Fly mode is the demos' free camera: no gravity, full-3D wish,
110 // instant start/stop, still sliding along walls.
111 body.set_mode(MoveMode::Fly);
112 body.walk(&scene, dt, WalkInput::default());
113 assert_eq!(body.vel(), DVec3::ZERO, "fly idles in place");
114
115 // The water curtain from `build_world` is passable: probe the
116 // veto directly (the same query walk() uses).
117 let wading = roxlap_scene::box_overlaps_solid(
118 &scene,
119 DVec3::new(40.2, 50.0, 90.0),
120 DVec3::new(40.8, 50.6, 91.8),
121 body.def().solidity,
122 );
123 assert!(!wading, "water is passable under the veto");
124
125 println!("book_controller: all controller assertions hold");
126}Sourcepub fn eye_pos(&self) -> DVec3
pub fn eye_pos(&self) -> DVec3
Eye position — the camera anchor: eye_height above the
feet, i.e. toward −z.
Examples found in repository?
61fn main() {
62 let scene = build_world();
63
64 // ANCHOR: setup
65 // A walking body: a feet-positioned collision box, f64 world.
66 // Distances are voxels, times seconds; +z is DOWN, so gravity is
67 // positive and a jump impulse negative.
68 let mut body = CharacterBody::new(CharacterDef {
69 radius: 0.4, // xy half-extent of the box
70 height: 1.8, // feet → head (toward -z)
71 eye_height: 1.62, // feet → camera anchor
72 step_up: 1.05, // auto-step ledges up to 1 voxel
73 solidity: Solidity {
74 bedrock_blocks: false, // match your renderer's policy
75 passable: Some(water_passes),
76 },
77 ..CharacterDef::default()
78 });
79 body.teleport(DVec3::new(50.0, 50.0, 95.0)); // FEET position
80 // ANCHOR_END: setup
81
82 // ANCHOR: frame
83 // Per frame: build a wish direction from input (unit-length or
84 // zero — walk() clamps), call walk() EVERY frame (a zero wish is
85 // what stops the body), then anchor the camera at the eye.
86 let dt = 1.0 / 60.0;
87 for frame in 0..480 {
88 let input = WalkInput {
89 wish: DVec3::new(1.0, 0.2, 0.0), // toward the ledge
90 jump: frame == 120, // one hop on the way
91 };
92 body.walk(&scene, dt, input);
93 }
94 let eye = body.eye_pos(); // = Camera::from_yaw_pitch(eye.into(), yaw, pitch)
95 // ANCHOR_END: frame
96
97 // The trajectory the walk above promises, pinned:
98 assert!(body.on_ground(), "settled after the hop");
99 // It fell to the floor plane, then stepped up the 1-voxel ledge
100 // (surface z = 99) while walking +x.
101 assert!(body.pos().x > 90.0, "reached the ledge region");
102 assert!(
103 (body.pos().z - 99.0).abs() < 0.01,
104 "standing on the ledge, feet at {}",
105 body.pos().z
106 );
107 assert!(eye.z < body.pos().z, "the eye is above the feet (-z is up)");
108
109 // Fly mode is the demos' free camera: no gravity, full-3D wish,
110 // instant start/stop, still sliding along walls.
111 body.set_mode(MoveMode::Fly);
112 body.walk(&scene, dt, WalkInput::default());
113 assert_eq!(body.vel(), DVec3::ZERO, "fly idles in place");
114
115 // The water curtain from `build_world` is passable: probe the
116 // veto directly (the same query walk() uses).
117 let wading = roxlap_scene::box_overlaps_solid(
118 &scene,
119 DVec3::new(40.2, 50.0, 90.0),
120 DVec3::new(40.8, 50.6, 91.8),
121 body.def().solidity,
122 );
123 assert!(!wading, "water is passable under the veto");
124
125 println!("book_controller: all controller assertions hold");
126}Sourcepub fn vel(&self) -> DVec3
pub fn vel(&self) -> DVec3
Current velocity, world units per second.
Examples found in repository?
61fn main() {
62 let scene = build_world();
63
64 // ANCHOR: setup
65 // A walking body: a feet-positioned collision box, f64 world.
66 // Distances are voxels, times seconds; +z is DOWN, so gravity is
67 // positive and a jump impulse negative.
68 let mut body = CharacterBody::new(CharacterDef {
69 radius: 0.4, // xy half-extent of the box
70 height: 1.8, // feet → head (toward -z)
71 eye_height: 1.62, // feet → camera anchor
72 step_up: 1.05, // auto-step ledges up to 1 voxel
73 solidity: Solidity {
74 bedrock_blocks: false, // match your renderer's policy
75 passable: Some(water_passes),
76 },
77 ..CharacterDef::default()
78 });
79 body.teleport(DVec3::new(50.0, 50.0, 95.0)); // FEET position
80 // ANCHOR_END: setup
81
82 // ANCHOR: frame
83 // Per frame: build a wish direction from input (unit-length or
84 // zero — walk() clamps), call walk() EVERY frame (a zero wish is
85 // what stops the body), then anchor the camera at the eye.
86 let dt = 1.0 / 60.0;
87 for frame in 0..480 {
88 let input = WalkInput {
89 wish: DVec3::new(1.0, 0.2, 0.0), // toward the ledge
90 jump: frame == 120, // one hop on the way
91 };
92 body.walk(&scene, dt, input);
93 }
94 let eye = body.eye_pos(); // = Camera::from_yaw_pitch(eye.into(), yaw, pitch)
95 // ANCHOR_END: frame
96
97 // The trajectory the walk above promises, pinned:
98 assert!(body.on_ground(), "settled after the hop");
99 // It fell to the floor plane, then stepped up the 1-voxel ledge
100 // (surface z = 99) while walking +x.
101 assert!(body.pos().x > 90.0, "reached the ledge region");
102 assert!(
103 (body.pos().z - 99.0).abs() < 0.01,
104 "standing on the ledge, feet at {}",
105 body.pos().z
106 );
107 assert!(eye.z < body.pos().z, "the eye is above the feet (-z is up)");
108
109 // Fly mode is the demos' free camera: no gravity, full-3D wish,
110 // instant start/stop, still sliding along walls.
111 body.set_mode(MoveMode::Fly);
112 body.walk(&scene, dt, WalkInput::default());
113 assert_eq!(body.vel(), DVec3::ZERO, "fly idles in place");
114
115 // The water curtain from `build_world` is passable: probe the
116 // veto directly (the same query walk() uses).
117 let wading = roxlap_scene::box_overlaps_solid(
118 &scene,
119 DVec3::new(40.2, 50.0, 90.0),
120 DVec3::new(40.8, 50.6, 91.8),
121 body.def().solidity,
122 );
123 assert!(!wading, "water is passable under the veto");
124
125 println!("book_controller: all controller assertions hold");
126}Sourcepub fn set_vel(&mut self, vel: DVec3)
pub fn set_vel(&mut self, vel: DVec3)
Overwrite the velocity — knockback, launch pads, spawn state.
Sourcepub fn on_ground(&self) -> bool
pub fn on_ground(&self) -> bool
true while the feet rest on solid ground (skin probe below
the feet, updated by walk).
Examples found in repository?
61fn main() {
62 let scene = build_world();
63
64 // ANCHOR: setup
65 // A walking body: a feet-positioned collision box, f64 world.
66 // Distances are voxels, times seconds; +z is DOWN, so gravity is
67 // positive and a jump impulse negative.
68 let mut body = CharacterBody::new(CharacterDef {
69 radius: 0.4, // xy half-extent of the box
70 height: 1.8, // feet → head (toward -z)
71 eye_height: 1.62, // feet → camera anchor
72 step_up: 1.05, // auto-step ledges up to 1 voxel
73 solidity: Solidity {
74 bedrock_blocks: false, // match your renderer's policy
75 passable: Some(water_passes),
76 },
77 ..CharacterDef::default()
78 });
79 body.teleport(DVec3::new(50.0, 50.0, 95.0)); // FEET position
80 // ANCHOR_END: setup
81
82 // ANCHOR: frame
83 // Per frame: build a wish direction from input (unit-length or
84 // zero — walk() clamps), call walk() EVERY frame (a zero wish is
85 // what stops the body), then anchor the camera at the eye.
86 let dt = 1.0 / 60.0;
87 for frame in 0..480 {
88 let input = WalkInput {
89 wish: DVec3::new(1.0, 0.2, 0.0), // toward the ledge
90 jump: frame == 120, // one hop on the way
91 };
92 body.walk(&scene, dt, input);
93 }
94 let eye = body.eye_pos(); // = Camera::from_yaw_pitch(eye.into(), yaw, pitch)
95 // ANCHOR_END: frame
96
97 // The trajectory the walk above promises, pinned:
98 assert!(body.on_ground(), "settled after the hop");
99 // It fell to the floor plane, then stepped up the 1-voxel ledge
100 // (surface z = 99) while walking +x.
101 assert!(body.pos().x > 90.0, "reached the ledge region");
102 assert!(
103 (body.pos().z - 99.0).abs() < 0.01,
104 "standing on the ledge, feet at {}",
105 body.pos().z
106 );
107 assert!(eye.z < body.pos().z, "the eye is above the feet (-z is up)");
108
109 // Fly mode is the demos' free camera: no gravity, full-3D wish,
110 // instant start/stop, still sliding along walls.
111 body.set_mode(MoveMode::Fly);
112 body.walk(&scene, dt, WalkInput::default());
113 assert_eq!(body.vel(), DVec3::ZERO, "fly idles in place");
114
115 // The water curtain from `build_world` is passable: probe the
116 // veto directly (the same query walk() uses).
117 let wading = roxlap_scene::box_overlaps_solid(
118 &scene,
119 DVec3::new(40.2, 50.0, 90.0),
120 DVec3::new(40.8, 50.6, 91.8),
121 body.def().solidity,
122 );
123 assert!(!wading, "water is passable under the veto");
124
125 println!("book_controller: all controller assertions hold");
126}Sourcepub fn set_pos(&mut self, pos: DVec3)
pub fn set_pos(&mut self, pos: DVec3)
Reposition the feet, KEEPING velocity and contact state — for
world-bounds clamps and moving-platform style corrections.
For spawns and respawns use teleport.
Sourcepub fn teleport(&mut self, pos: DVec3)
pub fn teleport(&mut self, pos: DVec3)
Hard-place the feet at pos, zeroing velocity and contact
flags. No collision check — placing inside solid is allowed
(the stuck-escape rule below makes it recoverable).
Examples found in repository?
61fn main() {
62 let scene = build_world();
63
64 // ANCHOR: setup
65 // A walking body: a feet-positioned collision box, f64 world.
66 // Distances are voxels, times seconds; +z is DOWN, so gravity is
67 // positive and a jump impulse negative.
68 let mut body = CharacterBody::new(CharacterDef {
69 radius: 0.4, // xy half-extent of the box
70 height: 1.8, // feet → head (toward -z)
71 eye_height: 1.62, // feet → camera anchor
72 step_up: 1.05, // auto-step ledges up to 1 voxel
73 solidity: Solidity {
74 bedrock_blocks: false, // match your renderer's policy
75 passable: Some(water_passes),
76 },
77 ..CharacterDef::default()
78 });
79 body.teleport(DVec3::new(50.0, 50.0, 95.0)); // FEET position
80 // ANCHOR_END: setup
81
82 // ANCHOR: frame
83 // Per frame: build a wish direction from input (unit-length or
84 // zero — walk() clamps), call walk() EVERY frame (a zero wish is
85 // what stops the body), then anchor the camera at the eye.
86 let dt = 1.0 / 60.0;
87 for frame in 0..480 {
88 let input = WalkInput {
89 wish: DVec3::new(1.0, 0.2, 0.0), // toward the ledge
90 jump: frame == 120, // one hop on the way
91 };
92 body.walk(&scene, dt, input);
93 }
94 let eye = body.eye_pos(); // = Camera::from_yaw_pitch(eye.into(), yaw, pitch)
95 // ANCHOR_END: frame
96
97 // The trajectory the walk above promises, pinned:
98 assert!(body.on_ground(), "settled after the hop");
99 // It fell to the floor plane, then stepped up the 1-voxel ledge
100 // (surface z = 99) while walking +x.
101 assert!(body.pos().x > 90.0, "reached the ledge region");
102 assert!(
103 (body.pos().z - 99.0).abs() < 0.01,
104 "standing on the ledge, feet at {}",
105 body.pos().z
106 );
107 assert!(eye.z < body.pos().z, "the eye is above the feet (-z is up)");
108
109 // Fly mode is the demos' free camera: no gravity, full-3D wish,
110 // instant start/stop, still sliding along walls.
111 body.set_mode(MoveMode::Fly);
112 body.walk(&scene, dt, WalkInput::default());
113 assert_eq!(body.vel(), DVec3::ZERO, "fly idles in place");
114
115 // The water curtain from `build_world` is passable: probe the
116 // veto directly (the same query walk() uses).
117 let wading = roxlap_scene::box_overlaps_solid(
118 &scene,
119 DVec3::new(40.2, 50.0, 90.0),
120 DVec3::new(40.8, 50.6, 91.8),
121 body.def().solidity,
122 );
123 assert!(!wading, "water is passable under the veto");
124
125 println!("book_controller: all controller assertions hold");
126}Sourcepub fn walk(&mut self, scene: &Scene, dt: f64, input: WalkInput)
pub fn walk(&mut self, scene: &Scene, dt: f64, input: WalkInput)
Advance the body by dt seconds against scene. Behaviour
follows the current MoveMode; everything below describes
MoveMode::Walk.
Integration order: horizontal velocity approaches
wish · walk_speed at the ground/air accel rate; gravity;
jump if grounded; then the displacement is applied in
substeps of at most radius per axis (the no-tunnel
guarantee), each substep moving x, then y, then z, clamping
flush against the blocking cell plane and zeroing that
velocity component on contact — unless a grounded horizontal
block steps up a ledge (CharacterDef::step_up). +z contact
grounds the body; −z contact is a head bump.
Stuck escape (kept verbatim from the demos): if the body starts the frame overlapping solid — an edit carved under the player, a bake reclassified a column — the whole frame moves without collision so the player can escape rather than jam.
Examples found in repository?
61fn main() {
62 let scene = build_world();
63
64 // ANCHOR: setup
65 // A walking body: a feet-positioned collision box, f64 world.
66 // Distances are voxels, times seconds; +z is DOWN, so gravity is
67 // positive and a jump impulse negative.
68 let mut body = CharacterBody::new(CharacterDef {
69 radius: 0.4, // xy half-extent of the box
70 height: 1.8, // feet → head (toward -z)
71 eye_height: 1.62, // feet → camera anchor
72 step_up: 1.05, // auto-step ledges up to 1 voxel
73 solidity: Solidity {
74 bedrock_blocks: false, // match your renderer's policy
75 passable: Some(water_passes),
76 },
77 ..CharacterDef::default()
78 });
79 body.teleport(DVec3::new(50.0, 50.0, 95.0)); // FEET position
80 // ANCHOR_END: setup
81
82 // ANCHOR: frame
83 // Per frame: build a wish direction from input (unit-length or
84 // zero — walk() clamps), call walk() EVERY frame (a zero wish is
85 // what stops the body), then anchor the camera at the eye.
86 let dt = 1.0 / 60.0;
87 for frame in 0..480 {
88 let input = WalkInput {
89 wish: DVec3::new(1.0, 0.2, 0.0), // toward the ledge
90 jump: frame == 120, // one hop on the way
91 };
92 body.walk(&scene, dt, input);
93 }
94 let eye = body.eye_pos(); // = Camera::from_yaw_pitch(eye.into(), yaw, pitch)
95 // ANCHOR_END: frame
96
97 // The trajectory the walk above promises, pinned:
98 assert!(body.on_ground(), "settled after the hop");
99 // It fell to the floor plane, then stepped up the 1-voxel ledge
100 // (surface z = 99) while walking +x.
101 assert!(body.pos().x > 90.0, "reached the ledge region");
102 assert!(
103 (body.pos().z - 99.0).abs() < 0.01,
104 "standing on the ledge, feet at {}",
105 body.pos().z
106 );
107 assert!(eye.z < body.pos().z, "the eye is above the feet (-z is up)");
108
109 // Fly mode is the demos' free camera: no gravity, full-3D wish,
110 // instant start/stop, still sliding along walls.
111 body.set_mode(MoveMode::Fly);
112 body.walk(&scene, dt, WalkInput::default());
113 assert_eq!(body.vel(), DVec3::ZERO, "fly idles in place");
114
115 // The water curtain from `build_world` is passable: probe the
116 // veto directly (the same query walk() uses).
117 let wading = roxlap_scene::box_overlaps_solid(
118 &scene,
119 DVec3::new(40.2, 50.0, 90.0),
120 DVec3::new(40.8, 50.6, 91.8),
121 body.def().solidity,
122 );
123 assert!(!wading, "water is passable under the veto");
124
125 println!("book_controller: all controller assertions hold");
126}Trait Implementations§
Source§impl Clone for CharacterBody
impl Clone for CharacterBody
Source§fn clone(&self) -> CharacterBody
fn clone(&self) -> CharacterBody
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreimpl Copy for CharacterBody
Auto Trait Implementations§
impl Freeze for CharacterBody
impl RefUnwindSafe for CharacterBody
impl Send for CharacterBody
impl Sync for CharacterBody
impl Unpin for CharacterBody
impl UnsafeUnpin for CharacterBody
impl UnwindSafe for CharacterBody
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more