Skip to content

Commit

Permalink
Made controller render more efficient and added CameraConfig (#25)
Browse files Browse the repository at this point in the history
* * Made controller render more efficient
* Added CameraConfig for more configurability

* Updated example
  • Loading branch information
FastestMolasses authored Oct 24, 2023
1 parent c6e47b9 commit 580a3b0
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 75 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 38 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,36 +40,46 @@ fn main() {

fn setup(mut commands: Commands, ...) {
...
commands.spawn((
Collider::capsule(Vec3::Y * 0.5, Vec3::Y * 1.5, 0.5),
Friction {
coefficient: 0.0,
combine_rule: CoefficientCombineRule::Min,
},
Restitution {
coefficient: 0.0,
combine_rule: CoefficientCombineRule::Min,
},
ActiveEvents::COLLISION_EVENTS,
Velocity::zero(),
RigidBody::Dynamic,
Sleeping::disabled(),
LockedAxes::ROTATION_LOCKED,
AdditionalMassProperties::Mass(1.0),
GravityScale(0.0),
Ccd { enabled: true }, // Prevent clipping when going fast
TransformBundle::from_transform(Transform::from_xyz(0.0, 3.0, 0.0)),
LogicalPlayer(0),
FpsControllerInput {
pitch: -TAU / 12.0,
yaw: TAU * 5.0 / 8.0,
..default()
},
FpsController { ..default() }
));
let logical_entity = commands
.spawn((
Collider::capsule(Vec3::Y * 0.5, Vec3::Y * 1.5, 0.5),
Friction {
coefficient: 0.0,
combine_rule: CoefficientCombineRule::Min,
},
Restitution {
coefficient: 0.0,
combine_rule: CoefficientCombineRule::Min,
},
ActiveEvents::COLLISION_EVENTS,
Velocity::zero(),
RigidBody::Dynamic,
Sleeping::disabled(),
LockedAxes::ROTATION_LOCKED,
AdditionalMassProperties::Mass(1.0),
GravityScale(0.0),
Ccd { enabled: true }, // Prevent clipping when going fast
TransformBundle::from_transform(Transform::from_xyz(0.0, 3.0, 0.0)),
LogicalPlayer(0),
FpsControllerInput {
pitch: -TAU / 12.0,
yaw: TAU * 5.0 / 8.0,
..default()
},
FpsController { ..default() }
))
.insert(CameraConfig {
height_offset: 0.0,
radius_scale: 0.75,
})
.id();

commands.spawn((
Camera3dBundle::default(),
RenderPlayer(0),
RenderPlayer {
id: 0,
logical_entity,
},
));
...
}
Expand Down
72 changes: 41 additions & 31 deletions examples/minimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,36 +54,43 @@ fn setup(
// The other is a "render" player that is what is displayed to the user
// This distinction is useful for later on if you want to add multiplayer,
// where often time these two ideas are not exactly synced up
commands.spawn((
Collider::capsule(Vec3::Y * 0.5, Vec3::Y * 1.5, 0.5),
Friction {
coefficient: 0.0,
combine_rule: CoefficientCombineRule::Min,
},
Restitution {
coefficient: 0.0,
combine_rule: CoefficientCombineRule::Min,
},
ActiveEvents::COLLISION_EVENTS,
Velocity::zero(),
RigidBody::Dynamic,
Sleeping::disabled(),
LockedAxes::ROTATION_LOCKED,
AdditionalMassProperties::Mass(1.0),
GravityScale(0.0),
Ccd { enabled: true }, // Prevent clipping when going fast
TransformBundle::from_transform(Transform::from_translation(SPAWN_POINT)),
LogicalPlayer(0),
FpsControllerInput {
pitch: -TAU / 12.0,
yaw: TAU * 5.0 / 8.0,
..default()
},
FpsController {
air_acceleration: 80.0,
..default()
}
));
let logical_entity = commands
.spawn((
Collider::capsule(Vec3::Y * 0.5, Vec3::Y * 1.5, 0.5),
Friction {
coefficient: 0.0,
combine_rule: CoefficientCombineRule::Min,
},
Restitution {
coefficient: 0.0,
combine_rule: CoefficientCombineRule::Min,
},
ActiveEvents::COLLISION_EVENTS,
Velocity::zero(),
RigidBody::Dynamic,
Sleeping::disabled(),
LockedAxes::ROTATION_LOCKED,
AdditionalMassProperties::Mass(1.0),
GravityScale(0.0),
Ccd { enabled: true }, // Prevent clipping when going fast
TransformBundle::from_transform(Transform::from_translation(SPAWN_POINT)),
LogicalPlayer(0),
FpsControllerInput {
pitch: -TAU / 12.0,
yaw: TAU * 5.0 / 8.0,
..default()
},
FpsController {
air_acceleration: 80.0,
..default()
},
))
.insert(CameraConfig {
height_offset: 0.0,
radius_scale: 0.75,
})
.id();

commands.spawn((
Camera3dBundle {
projection: Projection::Perspective(PerspectiveProjection {
Expand All @@ -92,7 +99,10 @@ fn setup(
}),
..default()
},
RenderPlayer(0),
RenderPlayer {
id: 0,
logical_entity,
},
));

commands.insert_resource(MainScene {
Expand Down
31 changes: 16 additions & 15 deletions src/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,16 @@ pub enum MoveMode {
pub struct LogicalPlayer(pub u8);

#[derive(Component)]
pub struct RenderPlayer(pub u8);
pub struct RenderPlayer {
pub id: u8,
pub logical_entity: Entity,
}

#[derive(Component)]
pub struct CameraConfig {
pub height_offset: f32,
pub radius_scale: f32,
}

#[derive(Component, Default)]
pub struct FpsControllerInput {
Expand Down Expand Up @@ -445,21 +454,13 @@ fn get_axis(key_input: &Res<Input<KeyCode>>, key_pos: KeyCode, key_neg: KeyCode)
// ╚═╝ ╚═╝╚══════╝╚═╝ ╚═══╝╚═════╝ ╚══════╝╚═╝ ╚═╝

pub fn fps_controller_render(
logical_query: Query<
(&Transform, &Collider, &FpsController, &LogicalPlayer),
With<LogicalPlayer>,
>,
mut render_query: Query<(&mut Transform, &RenderPlayer), Without<LogicalPlayer>>,
mut render_query: Query<(&mut Transform, &RenderPlayer), With<RenderPlayer>>,
logical_query: Query<(&Transform, &Collider, &FpsController, &CameraConfig), (With<LogicalPlayer>, Without<RenderPlayer>)>,
) {
// TODO: inefficient O(N^2) loop, use hash map?
for (logical_transform, collider, controller, logical_player_id) in logical_query.iter() {
if let Some(capsule) = collider.as_capsule() {
for (mut render_transform, render_player_id) in render_query.iter_mut() {
if logical_player_id.0 != render_player_id.0 {
continue;
}
// TODO: let this be more configurable
let camera_height = capsule.segment().b().y + capsule.radius() * 0.75;
for (mut render_transform, render_player) in render_query.iter_mut() {
if let Ok((logical_transform, collider, controller, camera_config)) = logical_query.get(render_player.logical_entity) {
if let Some(capsule) = collider.as_capsule() {
let camera_height = capsule.segment().b().y + capsule.radius() * camera_config.radius_scale + camera_config.height_offset;
render_transform.translation = logical_transform.translation + Vec3::Y * camera_height;
render_transform.rotation = Quat::from_euler(EulerRot::YXZ, controller.yaw, controller.pitch, 0.0);
}
Expand Down

0 comments on commit 580a3b0

Please sign in to comment.