wip: wild physics
parent
97c8808281
commit
352fca7093
|
|
@ -18,31 +18,23 @@ impl Plugin for KinematicPlugin {
|
||||||
|
|
||||||
#[derive(Bundle)]
|
#[derive(Bundle)]
|
||||||
pub struct KinematicBundle {
|
pub struct KinematicBundle {
|
||||||
pub kinematic: KinematicState,
|
pub state: KinematicState,
|
||||||
|
pub properties: KinematicProperties,
|
||||||
pub rigidbody: RigidBody,
|
pub rigidbody: RigidBody,
|
||||||
pub velocity: Velocity,
|
|
||||||
pub gravity_scale: GravityScale,
|
|
||||||
pub collider: Collider,
|
|
||||||
pub locked_axes: LockedAxes,
|
|
||||||
pub events: ActiveEvents,
|
pub events: ActiveEvents,
|
||||||
pub collisions: ActiveCollisionTypes,
|
pub collisions: ActiveCollisionTypes,
|
||||||
pub properties: KinematicProperties,
|
|
||||||
pub transform: TransformBundle,
|
pub transform: TransformBundle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for KinematicBundle {
|
impl Default for KinematicBundle {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
KinematicBundle {
|
KinematicBundle {
|
||||||
kinematic: KinematicState::default(),
|
state: KinematicState::default(),
|
||||||
rigidbody: RigidBody::Dynamic,
|
properties: KinematicProperties::default(),
|
||||||
gravity_scale: GravityScale(3.0),
|
rigidbody: RigidBody::KinematicPositionBased,
|
||||||
locked_axes: LockedAxes::ROTATION_LOCKED,
|
|
||||||
events: ActiveEvents::COLLISION_EVENTS,
|
events: ActiveEvents::COLLISION_EVENTS,
|
||||||
collisions: ActiveCollisionTypes::all(),
|
collisions: ActiveCollisionTypes::all(),
|
||||||
collider: Collider::default(),
|
|
||||||
properties: KinematicProperties::default(),
|
|
||||||
transform: TransformBundle::default(),
|
transform: TransformBundle::default(),
|
||||||
velocity: Velocity::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -50,27 +42,15 @@ impl Default for KinematicBundle {
|
||||||
#[derive(Component, Reflect, Default)]
|
#[derive(Component, Reflect, Default)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct KinematicState {
|
pub struct KinematicState {
|
||||||
on_ground: bool,
|
// TODO: fork rapier2d and make it reflect?
|
||||||
did_jump: bool,
|
#[reflect(ignore)]
|
||||||
air_jump_counter: u8,
|
pub last_move: Option<MoveShapeOutput>,
|
||||||
|
pub did_jump: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KinematicState {
|
impl KinematicState {
|
||||||
#[inline]
|
|
||||||
pub fn on_ground(&self) -> bool {
|
|
||||||
self.on_ground
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
pub fn did_jump(&self) -> bool {
|
|
||||||
self.did_jump
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
pub fn air_jump_counter(&self) -> u8 {
|
|
||||||
self.air_jump_counter
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn can_jump(&self) -> bool {
|
pub fn can_jump(&self) -> bool {
|
||||||
self.on_ground && !self.did_jump
|
self.last_move.as_ref().map_or(false, |last| last.grounded) && !self.did_jump
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,7 +64,7 @@ pub struct KinematicProperties {
|
||||||
pub air_acceleration: f32,
|
pub air_acceleration: f32,
|
||||||
pub air_friction: f32,
|
pub air_friction: f32,
|
||||||
pub jump_height: f32,
|
pub jump_height: f32,
|
||||||
pub air_jumps: u8,
|
pub gravity: Option<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for KinematicProperties {
|
impl Default for KinematicProperties {
|
||||||
|
|
@ -97,7 +77,7 @@ impl Default for KinematicProperties {
|
||||||
air_acceleration: 10.0,
|
air_acceleration: 10.0,
|
||||||
air_friction: 10.0,
|
air_friction: 10.0,
|
||||||
jump_height: 150.0,
|
jump_height: 150.0,
|
||||||
air_jumps: 1,
|
gravity: Some(1.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -113,37 +93,27 @@ fn kinematic_movement(
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
mut query: Query<(
|
mut query: Query<(
|
||||||
Entity,
|
Entity,
|
||||||
&mut Velocity,
|
|
||||||
&mut KinematicState,
|
&mut KinematicState,
|
||||||
|
&mut Transform,
|
||||||
&KinematicProperties,
|
&KinematicProperties,
|
||||||
&GlobalTransform,
|
&GlobalTransform,
|
||||||
Option<&KinematicInput>,
|
Option<&KinematicInput>,
|
||||||
Option<&GravityScale>,
|
|
||||||
Option<&Collider>,
|
|
||||||
)>,
|
)>,
|
||||||
rapier_context: Res<RapierContext>,
|
shape_query: Query<&Collider, Without<Sensor>>,
|
||||||
|
child_query: Query<&Children>,
|
||||||
|
mut rapier_context: ResMut<RapierContext>,
|
||||||
) {
|
) {
|
||||||
for (
|
for (entity, mut kinematic_state, mut transform, props, global_transform, input) in
|
||||||
entity,
|
query.iter_mut()
|
||||||
mut velocity,
|
|
||||||
mut kinematic_state,
|
|
||||||
props,
|
|
||||||
global_transform,
|
|
||||||
input,
|
|
||||||
gravity,
|
|
||||||
collider,
|
|
||||||
) in query.iter_mut()
|
|
||||||
{
|
{
|
||||||
let default = &KinematicInput::default();
|
let default = &KinematicInput::default();
|
||||||
let input = input.unwrap_or(default);
|
let input = input.unwrap_or(default);
|
||||||
|
|
||||||
let has_gravity = if let Some(gravity) = gravity {
|
let (speed, acceleration, friction) = if kinematic_state
|
||||||
gravity.0.abs() > f32::EPSILON
|
.last_move
|
||||||
} else {
|
.as_ref()
|
||||||
false
|
.map_or(false, |last| last.grounded)
|
||||||
};
|
{
|
||||||
|
|
||||||
let (speed, acceleration, friction) = if kinematic_state.on_ground {
|
|
||||||
(
|
(
|
||||||
props.ground_speed,
|
props.ground_speed,
|
||||||
props.ground_acceleration,
|
props.ground_acceleration,
|
||||||
|
|
@ -155,7 +125,10 @@ fn kinematic_movement(
|
||||||
|
|
||||||
const GRAVITY_DIR: Vec2 = Vec2::NEG_Y;
|
const GRAVITY_DIR: Vec2 = Vec2::NEG_Y;
|
||||||
|
|
||||||
let current_velocity = velocity.linvel;
|
let current_velocity = kinematic_state
|
||||||
|
.last_move
|
||||||
|
.as_ref()
|
||||||
|
.map_or(Vec2::ZERO, |last| last.effective_translation);
|
||||||
let target_velocity =
|
let target_velocity =
|
||||||
input.movement * speed + current_velocity.project_onto_normalized(GRAVITY_DIR);
|
input.movement * speed + current_velocity.project_onto_normalized(GRAVITY_DIR);
|
||||||
|
|
||||||
|
|
@ -178,43 +151,96 @@ fn kinematic_movement(
|
||||||
let delta_interpolation = angle_lerp.clamp(0.0, 1.0);
|
let delta_interpolation = angle_lerp.clamp(0.0, 1.0);
|
||||||
let velocity_change_speed = lerp(acceleration, friction, delta_interpolation) * speed;
|
let velocity_change_speed = lerp(acceleration, friction, delta_interpolation) * speed;
|
||||||
|
|
||||||
velocity.linvel = move_towards_vec2(
|
let mut velocity = move_towards_vec2(
|
||||||
current_velocity,
|
current_velocity,
|
||||||
target_velocity,
|
target_velocity,
|
||||||
velocity_change_speed * time.delta_seconds(),
|
velocity_change_speed * time.delta_seconds(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if input.want_jump && kinematic_state.can_jump() {
|
if input.want_jump && kinematic_state.can_jump() {
|
||||||
velocity.linvel = Vec2 {
|
velocity = Vec2 {
|
||||||
y: props.jump_height,
|
y: props.jump_height,
|
||||||
..velocity.linvel
|
..velocity
|
||||||
};
|
};
|
||||||
kinematic_state.did_jump = true;
|
kinematic_state.did_jump = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_gravity {
|
let shape = if let Ok(shape) = shape_query.get(entity) {
|
||||||
|
Some(shape)
|
||||||
|
} else if let Ok(children) = child_query.get(entity) {
|
||||||
|
children
|
||||||
|
.iter()
|
||||||
|
.find_map(|child| shape_query.get(*child).ok())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
// gravity
|
||||||
|
if let Some(gravity) = props.gravity {
|
||||||
|
velocity.y += -9.81 * gravity * time.delta_seconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
// move
|
||||||
|
kinematic_state.last_move = if let Some(shape) = shape {
|
||||||
|
let (_scale, rotation, translation) = global_transform.to_scale_rotation_translation();
|
||||||
|
|
||||||
|
let move_options = &MoveShapeOptions {
|
||||||
|
up: Vec2::Y,
|
||||||
|
autostep: Some(CharacterAutostep {
|
||||||
|
min_width: CharacterLength::Absolute(0.5),
|
||||||
|
max_height: CharacterLength::Absolute(2.1),
|
||||||
|
include_dynamic_bodies: false,
|
||||||
|
}),
|
||||||
|
slide: true,
|
||||||
|
max_slope_climb_angle: (50.0_f32).to_radians(),
|
||||||
|
min_slope_slide_angle: (50.0_f32).to_radians(),
|
||||||
|
snap_to_ground: Some(CharacterLength::Absolute(5.0)),
|
||||||
|
offset: CharacterLength::Absolute(0.01),
|
||||||
|
..MoveShapeOptions::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let last_move = rapier_context.move_shape(
|
||||||
|
velocity * time.delta_seconds(),
|
||||||
|
shape,
|
||||||
|
translation.truncate(),
|
||||||
|
rotation.to_euler(EulerRot::ZYX).0,
|
||||||
|
shape.raw.0.mass_properties(1.0).mass(),
|
||||||
|
move_options,
|
||||||
|
QueryFilter::new(),
|
||||||
|
|coll: CharacterCollision| println!("Collided! {coll:?}"),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Apply movement
|
||||||
|
transform.translation += last_move.effective_translation.extend(0.0);
|
||||||
|
|
||||||
|
Some(last_move)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
if props.gravity.is_some() {
|
||||||
// Reset any possible jump snapping and stuff after the peak of jump
|
// Reset any possible jump snapping and stuff after the peak of jump
|
||||||
if velocity.linvel.y <= 0.0 {
|
if velocity.y <= 0.0 {
|
||||||
kinematic_state.did_jump = false;
|
kinematic_state.did_jump = false;
|
||||||
}
|
}
|
||||||
if let Some(collider) = collider {
|
// if let Some(collider) = collider {
|
||||||
let (_, rot, pos) = global_transform.to_scale_rotation_translation();
|
// let (_, rot, pos) = global_transform.to_scale_rotation_translation();
|
||||||
let angle = rot.to_euler(EulerRot::YXZ).2;
|
// let angle = rot.to_euler(EulerRot::YXZ).2;
|
||||||
let mut shape = collider.clone();
|
// let mut shape = collider.clone();
|
||||||
shape.set_scale(Vec2::ONE * 0.9, 1);
|
// shape.set_scale(Vec2::ONE * 0.9, 1);
|
||||||
if let Some((_coll_entity, _hit)) = rapier_context.cast_shape(
|
// if let Some((_coll_entity, _hit)) = rapier_context.cast_shape(
|
||||||
Vec2::new(pos.x, pos.y),
|
// Vec2::new(pos.x, pos.y),
|
||||||
angle,
|
// angle,
|
||||||
Vec2::NEG_Y,
|
// Vec2::NEG_Y,
|
||||||
&shape,
|
// &shape,
|
||||||
2.0,
|
// 2.0,
|
||||||
QueryFilter::new().exclude_collider(entity),
|
// QueryFilter::new().exclude_collider(entity),
|
||||||
) {
|
// ) {
|
||||||
kinematic_state.on_ground = true;
|
// kinematic_state.on_ground = true;
|
||||||
} else {
|
// } else {
|
||||||
kinematic_state.on_ground = false;
|
// kinematic_state.on_ground = false;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,6 @@ fn input_to_axis(negative: bool, positive: bool) -> f32 {
|
||||||
|
|
||||||
pub fn player_spawn(mut commands: Commands) {
|
pub fn player_spawn(mut commands: Commands) {
|
||||||
let kinematic = KinematicBundle {
|
let kinematic = KinematicBundle {
|
||||||
collider: Collider::cuboid(3.0, 6.0),
|
|
||||||
transform: TransformBundle::from_transform(Transform::from_translation(Vec3::new(
|
transform: TransformBundle::from_transform(Transform::from_translation(Vec3::new(
|
||||||
256.0, 128.0, 0.0,
|
256.0, 128.0, 0.0,
|
||||||
))),
|
))),
|
||||||
|
|
@ -77,10 +76,22 @@ pub fn player_spawn(mut commands: Commands) {
|
||||||
},
|
},
|
||||||
..default()
|
..default()
|
||||||
})
|
})
|
||||||
|
.insert(TransformBundle::from_transform(Transform::from_xyz(
|
||||||
|
256.0, 128.0, 0.0,
|
||||||
|
)))
|
||||||
|
.insert(Collider::cuboid(3.0, 6.0))
|
||||||
.insert(PlayerBundle {
|
.insert(PlayerBundle {
|
||||||
kinematic,
|
kinematic,
|
||||||
..default()
|
..default()
|
||||||
})
|
})
|
||||||
|
// .insert(RigidBody::KinematicPositionBased)
|
||||||
|
// .insert(Velocity::default())
|
||||||
|
// .insert(GravityScale(1.0))
|
||||||
|
// .insert(KinematicCharacterController {
|
||||||
|
// offset: CharacterLength::Absolute(0.01),
|
||||||
|
// up: Vec2::Y,
|
||||||
|
// ..default()
|
||||||
|
// })
|
||||||
.insert(KinematicInput::default())
|
.insert(KinematicInput::default())
|
||||||
.insert(Ccd::enabled())
|
.insert(Ccd::enabled())
|
||||||
.insert(Sleeping::disabled())
|
.insert(Sleeping::disabled())
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue