Skip to content

Commit 9c9ba45

Browse files
authored
testbed: add gravity control + character controller speed control (#822)
1 parent ad41b3d commit 9c9ba45

File tree

7 files changed

+87
-51
lines changed

7 files changed

+87
-51
lines changed

examples2d/character_controller2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ pub fn init_world(testbed: &mut Testbed) {
171171
/*
172172
* Callback to update the character based on user inputs.
173173
*/
174-
let mut control_mode = CharacterControlMode::Kinematic;
174+
let mut control_mode = CharacterControlMode::Kinematic(0.1);
175175
let mut controller = KinematicCharacterController {
176176
max_slope_climb_angle: impossible_slope_angle - 0.02,
177177
min_slope_slide_angle: impossible_slope_angle - 0.02,

examples2d/rope_joints2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ pub fn init_world(testbed: &mut Testbed) {
6060
/*
6161
* Callback to update the character based on user inputs.
6262
*/
63-
let mut control_mode = CharacterControlMode::Kinematic;
63+
let mut control_mode = CharacterControlMode::Kinematic(0.1);
6464
let mut controller = KinematicCharacterController::default();
6565
let mut pid = PidController::default();
6666

examples2d/utils/character.rs

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ use rapier_testbed2d::{
88
KeyCode, PhysicsState, TestbedGraphics,
99
};
1010

11-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
11+
pub type CharacterSpeed = Real;
12+
13+
#[derive(PartialEq, Clone, Copy, Debug)]
1214
pub enum CharacterControlMode {
13-
Kinematic,
14-
Pid,
15+
Kinematic(CharacterSpeed),
16+
Pid(CharacterSpeed),
1517
}
1618

1719
pub fn update_character(
@@ -27,28 +29,28 @@ pub fn update_character(
2729

2830
if *control_mode != prev_control_mode {
2931
match control_mode {
30-
CharacterControlMode::Kinematic => physics.bodies[character_handle]
32+
CharacterControlMode::Kinematic(_) => physics.bodies[character_handle]
3133
.set_body_type(RigidBodyType::KinematicPositionBased, false),
32-
CharacterControlMode::Pid => {
34+
CharacterControlMode::Pid(_) => {
3335
physics.bodies[character_handle].set_body_type(RigidBodyType::Dynamic, true)
3436
}
3537
}
3638
}
3739

3840
match *control_mode {
39-
CharacterControlMode::Kinematic => {
40-
update_kinematic_controller(graphics, physics, character_handle, controller)
41+
CharacterControlMode::Kinematic(speed) => {
42+
update_kinematic_controller(graphics, physics, character_handle, controller, speed)
4143
}
42-
CharacterControlMode::Pid => {
43-
update_pid_controller(graphics, physics, character_handle, pid)
44+
CharacterControlMode::Pid(speed) => {
45+
update_pid_controller(graphics, physics, character_handle, pid, speed)
4446
}
4547
}
4648
}
4749

4850
fn character_movement_from_inputs(
4951
gfx: &TestbedGraphics,
5052
mut speed: Real,
51-
artificial_gravity: bool,
53+
artificial_gravity: Option<Real>,
5254
) -> Vector<Real> {
5355
let mut desired_movement = Vector::zeros();
5456

@@ -75,8 +77,8 @@ fn character_movement_from_inputs(
7577

7678
desired_movement *= speed;
7779

78-
if artificial_gravity {
79-
desired_movement -= Vector::y() * speed;
80+
if let Some(artificial_gravity) = artificial_gravity {
81+
desired_movement += Vector::y() * artificial_gravity;
8082
}
8183

8284
desired_movement
@@ -87,8 +89,10 @@ fn update_pid_controller(
8789
phx: &mut PhysicsState,
8890
character_handle: RigidBodyHandle,
8991
pid: &mut PidController,
92+
speed: Real,
9093
) {
91-
let desired_movement = character_movement_from_inputs(gfx, 0.1, false);
94+
let desired_movement = character_movement_from_inputs(gfx, speed, None);
95+
9296
let character_body = &mut phx.bodies[character_handle];
9397

9498
// Adjust the controlled axis depending on the keys pressed by the user.
@@ -123,9 +127,9 @@ fn update_kinematic_controller(
123127
phx: &mut PhysicsState,
124128
character_handle: RigidBodyHandle,
125129
controller: &KinematicCharacterController,
130+
speed: Real,
126131
) {
127-
let speed = 0.1;
128-
let desired_movement = character_movement_from_inputs(gfx, speed, true);
132+
let desired_movement = character_movement_from_inputs(gfx, speed, Some(phx.gravity.y));
129133

130134
let character_body = &phx.bodies[character_handle];
131135
let character_collider = &phx.colliders[character_body.colliders()[0]];
@@ -139,7 +143,7 @@ fn update_kinematic_controller(
139143
&phx.query_pipeline,
140144
character_collider.shape(),
141145
character_collider.position(),
142-
desired_movement.cast::<Real>(),
146+
desired_movement,
143147
QueryFilter::new().exclude_rigid_body(character_handle),
144148
|c| collisions.push(c),
145149
);
@@ -178,29 +182,34 @@ fn character_control_ui(
178182
ComboBox::from_label("control mode")
179183
.selected_text(format!("{:?}", *control_mode))
180184
.show_ui(ui, |ui| {
181-
ui.selectable_value(control_mode, CharacterControlMode::Kinematic, "Kinematic");
182-
ui.selectable_value(control_mode, CharacterControlMode::Pid, "Pid");
185+
ui.selectable_value(
186+
control_mode,
187+
CharacterControlMode::Kinematic(0.1),
188+
"Kinematic",
189+
);
190+
ui.selectable_value(control_mode, CharacterControlMode::Pid(0.1), "Pid");
183191
});
184192

185193
match control_mode {
186-
CharacterControlMode::Kinematic => {
187-
kinematic_control_ui(ui, character_controller);
194+
CharacterControlMode::Kinematic(speed) => {
195+
kinematic_control_ui(ui, character_controller, speed);
188196
}
189-
CharacterControlMode::Pid => {
190-
pid_control_ui(ui, pid_controller);
197+
CharacterControlMode::Pid(speed) => {
198+
pid_control_ui(ui, pid_controller, speed);
191199
}
192200
}
193201
});
194202
}
195203

196-
fn pid_control_ui(ui: &mut Ui, pid_controller: &mut PidController) {
204+
fn pid_control_ui(ui: &mut Ui, pid_controller: &mut PidController, speed: &mut Real) {
197205
let mut lin_kp = pid_controller.pd.lin_kp.x;
198206
let mut lin_ki = pid_controller.lin_ki.x;
199207
let mut lin_kd = pid_controller.pd.lin_kd.x;
200208
let mut ang_kp = pid_controller.pd.ang_kp;
201209
let mut ang_ki = pid_controller.ang_ki;
202210
let mut ang_kd = pid_controller.pd.ang_kd;
203211

212+
ui.add(Slider::new(speed, 0.0..=1.0).text("speed"));
204213
ui.add(Slider::new(&mut lin_kp, 0.0..=100.0).text("linear Kp"));
205214
ui.add(Slider::new(&mut lin_ki, 0.0..=10.0).text("linear Ki"));
206215
ui.add(Slider::new(&mut lin_kd, 0.0..=1.0).text("linear Kd"));
@@ -216,7 +225,13 @@ fn pid_control_ui(ui: &mut Ui, pid_controller: &mut PidController) {
216225
pid_controller.pd.ang_kd = ang_kd;
217226
}
218227

219-
fn kinematic_control_ui(ui: &mut Ui, character_controller: &mut KinematicCharacterController) {
228+
fn kinematic_control_ui(
229+
ui: &mut Ui,
230+
character_controller: &mut KinematicCharacterController,
231+
speed: &mut Real,
232+
) {
233+
ui.add(Slider::new(speed, 0.0..=1.0).text("Speed"))
234+
.on_hover_text("The speed applied each simulation tick.");
220235
ui.checkbox(&mut character_controller.slide, "slide")
221236
.on_hover_text("Should the character try to slide against the floor if it hits it?");
222237
#[allow(clippy::useless_conversion)]

examples3d/character_controller3.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ pub fn init_world(testbed: &mut Testbed) {
187187
/*
188188
* Callback to update the character based on user inputs.
189189
*/
190-
let mut control_mode = CharacterControlMode::Kinematic;
190+
let mut control_mode = CharacterControlMode::Kinematic(0.1);
191191
let mut controller = KinematicCharacterController {
192192
max_slope_climb_angle: impossible_slope_angle - 0.02,
193193
min_slope_slide_angle: impossible_slope_angle - 0.02,

examples3d/rope_joints3.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ pub fn init_world(testbed: &mut Testbed) {
8888
/*
8989
* Callback to update the character based on user inputs.
9090
*/
91-
let mut control_mode = CharacterControlMode::Kinematic;
91+
let mut control_mode = CharacterControlMode::Kinematic(0.1);
9292
let mut controller = KinematicCharacterController::default();
9393
let mut pid = PidController::default();
9494

examples3d/utils/character.rs

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ use rapier_testbed3d::{
77
KeyCode, PhysicsState, TestbedGraphics,
88
};
99

10-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
10+
pub type CharacterSpeed = Real;
11+
12+
#[derive(PartialEq, Clone, Copy, Debug)]
1113
pub enum CharacterControlMode {
12-
Kinematic,
13-
Pid,
14+
Kinematic(CharacterSpeed),
15+
Pid(CharacterSpeed),
1416
}
1517

1618
pub fn update_character(
@@ -26,28 +28,28 @@ pub fn update_character(
2628

2729
if *control_mode != prev_control_mode {
2830
match control_mode {
29-
CharacterControlMode::Kinematic => physics.bodies[character_handle]
31+
CharacterControlMode::Kinematic(_) => physics.bodies[character_handle]
3032
.set_body_type(RigidBodyType::KinematicPositionBased, false),
31-
CharacterControlMode::Pid => {
33+
CharacterControlMode::Pid(_) => {
3234
physics.bodies[character_handle].set_body_type(RigidBodyType::Dynamic, true)
3335
}
3436
}
3537
}
3638

3739
match *control_mode {
38-
CharacterControlMode::Kinematic => {
39-
update_kinematic_controller(graphics, physics, character_handle, controller)
40+
CharacterControlMode::Kinematic(speed) => {
41+
update_kinematic_controller(graphics, physics, character_handle, controller, speed)
4042
}
41-
CharacterControlMode::Pid => {
42-
update_pid_controller(graphics, physics, character_handle, pid)
43+
CharacterControlMode::Pid(speed) => {
44+
update_pid_controller(graphics, physics, character_handle, pid, speed)
4345
}
4446
}
4547
}
4648

4749
fn character_movement_from_inputs(
4850
gfx: &TestbedGraphics,
4951
mut speed: Real,
50-
artificial_gravity: bool,
52+
artificial_gravity: Option<f32>,
5153
) -> Vector<Real> {
5254
let mut desired_movement = Vector::zeros();
5355

@@ -86,8 +88,8 @@ fn character_movement_from_inputs(
8688

8789
desired_movement *= speed;
8890

89-
if artificial_gravity {
90-
desired_movement -= Vector::y() * speed;
91+
if let Some(artificial_gravity) = artificial_gravity {
92+
desired_movement += Vector::y() * artificial_gravity;
9193
}
9294

9395
desired_movement
@@ -98,8 +100,9 @@ fn update_pid_controller(
98100
phx: &mut PhysicsState,
99101
character_handle: RigidBodyHandle,
100102
pid: &mut PidController,
103+
speed: Real,
101104
) {
102-
let desired_movement = character_movement_from_inputs(gfx, 0.1, false);
105+
let desired_movement = character_movement_from_inputs(gfx, speed, None);
103106
let character_body = &mut phx.bodies[character_handle];
104107

105108
// Adjust the controlled axis depending on the keys pressed by the user.
@@ -134,9 +137,9 @@ fn update_kinematic_controller(
134137
phx: &mut PhysicsState,
135138
character_handle: RigidBodyHandle,
136139
controller: &KinematicCharacterController,
140+
speed: Real,
137141
) {
138-
let speed = 0.1;
139-
let desired_movement = character_movement_from_inputs(gfx, speed, true);
142+
let desired_movement = character_movement_from_inputs(gfx, speed, Some(phx.gravity.y));
140143

141144
let character_body = &phx.bodies[character_handle];
142145
let character_collider = &phx.colliders[character_body.colliders()[0]];
@@ -189,29 +192,34 @@ fn character_control_ui(
189192
ComboBox::from_label("control mode")
190193
.selected_text(format!("{:?}", *control_mode))
191194
.show_ui(ui, |ui| {
192-
ui.selectable_value(control_mode, CharacterControlMode::Kinematic, "Kinematic");
193-
ui.selectable_value(control_mode, CharacterControlMode::Pid, "Pid");
195+
ui.selectable_value(
196+
control_mode,
197+
CharacterControlMode::Kinematic(0.1),
198+
"Kinematic",
199+
);
200+
ui.selectable_value(control_mode, CharacterControlMode::Pid(0.1), "Pid");
194201
});
195202

196203
match control_mode {
197-
CharacterControlMode::Kinematic => {
198-
kinematic_control_ui(ui, character_controller);
204+
CharacterControlMode::Kinematic(speed) => {
205+
kinematic_control_ui(ui, character_controller, speed);
199206
}
200-
CharacterControlMode::Pid => {
201-
pid_control_ui(ui, pid_controller);
207+
CharacterControlMode::Pid(speed) => {
208+
pid_control_ui(ui, pid_controller, speed);
202209
}
203210
}
204211
});
205212
}
206213

207-
fn pid_control_ui(ui: &mut Ui, pid_controller: &mut PidController) {
214+
fn pid_control_ui(ui: &mut Ui, pid_controller: &mut PidController, speed: &mut Real) {
208215
let mut lin_kp = pid_controller.pd.lin_kp.x;
209216
let mut lin_ki = pid_controller.lin_ki.x;
210217
let mut lin_kd = pid_controller.pd.lin_kd.x;
211218
let mut ang_kp = pid_controller.pd.ang_kp.x;
212219
let mut ang_ki = pid_controller.ang_ki.x;
213220
let mut ang_kd = pid_controller.pd.ang_kd.x;
214221

222+
ui.add(Slider::new(speed, 0.0..=1.0).text("speed"));
215223
ui.add(Slider::new(&mut lin_kp, 0.0..=100.0).text("linear Kp"));
216224
ui.add(Slider::new(&mut lin_ki, 0.0..=10.0).text("linear Ki"));
217225
ui.add(Slider::new(&mut lin_kd, 0.0..=1.0).text("linear Kd"));
@@ -227,7 +235,13 @@ fn pid_control_ui(ui: &mut Ui, pid_controller: &mut PidController) {
227235
pid_controller.pd.ang_kd.fill(ang_kd);
228236
}
229237

230-
fn kinematic_control_ui(ui: &mut Ui, character_controller: &mut KinematicCharacterController) {
238+
fn kinematic_control_ui(
239+
ui: &mut Ui,
240+
character_controller: &mut KinematicCharacterController,
241+
speed: &mut Real,
242+
) {
243+
ui.add(Slider::new(speed, 0.0..=1.0).text("Speed"))
244+
.on_hover_text("The speed applied each simulation tick.");
231245
ui.checkbox(&mut character_controller.slide, "slide")
232246
.on_hover_text("Should the character try to slide against the floor if it hits it?");
233247
#[allow(clippy::useless_conversion)]

src_testbed/ui.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,13 @@ pub(crate) fn update_ui(
235235

236236
let mut frequency = integration_parameters.inv_dt().round() as u32;
237237
ui.add(Slider::new(&mut frequency, 0..=240).text("frequency (Hz)"));
238+
let mut gravity_y = harness.physics.gravity.y;
239+
if ui
240+
.add(Slider::new(&mut gravity_y, 0.0..=-200.0).text("Gravity"))
241+
.changed()
242+
{
243+
harness.physics.gravity.y = gravity_y;
244+
}
238245
integration_parameters.set_inv_dt(frequency as Real);
239246

240247
let mut sleep = state.flags.contains(TestbedStateFlags::SLEEP);

0 commit comments

Comments
 (0)