Merge branch 'main' of github.com-personal:Back777space/among-me
This commit is contained in:
227
src/player.rs
Normal file
227
src/player.rs
Normal file
@@ -0,0 +1,227 @@
|
||||
use bevy::{
|
||||
input::mouse::AccumulatedMouseMotion, pbr::NotShadowCaster,
|
||||
prelude::*, render::view::RenderLayers,
|
||||
};
|
||||
|
||||
|
||||
#[derive(Debug, Component)]
|
||||
pub struct Player;
|
||||
|
||||
#[derive(Debug, Component, Deref, DerefMut)]
|
||||
pub struct CameraSensitivity(Vec2);
|
||||
impl Default for CameraSensitivity {
|
||||
fn default() -> Self {
|
||||
Self(
|
||||
Vec2::new(0.003, 0.002),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Component)]
|
||||
struct WorldModelCamera;
|
||||
|
||||
|
||||
#[derive(Debug, Component, Clone, Copy, PartialEq, Default, Deref, DerefMut)]
|
||||
pub struct AccumulatedInput(Vec3);
|
||||
|
||||
|
||||
#[derive(Debug, Component, Clone, Copy, PartialEq, Default, Deref, DerefMut)]
|
||||
pub struct Velocity(Vec3);
|
||||
|
||||
|
||||
|
||||
/// The actual position of the player in the physics simulation.
|
||||
/// This is separate from the `Transform`, which is merely a visual representation.
|
||||
///
|
||||
/// If you want to make sure that this component is always initialized
|
||||
/// with the same value as the `Transform`'s translation, you can
|
||||
/// use a [component lifecycle hook](https://docs.rs/bevy/0.14.0/bevy/ecs/component/struct.ComponentHooks.html)
|
||||
#[derive(Debug, Component, Clone, Copy, PartialEq, Default, Deref, DerefMut)]
|
||||
pub struct PhysicalTranslation(Vec3);
|
||||
|
||||
/// The value [`PhysicalTranslation`] had in the last fixed timestep.
|
||||
/// Used for interpolation in the `interpolate_rendered_transform` system.
|
||||
#[derive(Debug, Component, Clone, Copy, PartialEq, Default, Deref, DerefMut)]
|
||||
pub struct PreviousPhysicalTranslation(Vec3);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Used implicitly by all entities without a `RenderLayers` component.
|
||||
/// Our world model camera and all objects other than the player are on this layer.
|
||||
/// The light source belongs to both layers.
|
||||
// const DEFAULT_RENDER_LAYER: usize = 0;
|
||||
|
||||
/// Used by the view model camera and the player's arm.
|
||||
/// The light source belongs to both layers.
|
||||
const STATIC_LAYER: usize = 1;
|
||||
|
||||
pub fn init_player(
|
||||
mut commands: Commands,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
) {
|
||||
let arm = meshes.add(Cuboid::new(0.1, 0.1, 0.5));
|
||||
let arm_material = materials.add(Color::WHITE);
|
||||
|
||||
commands
|
||||
.spawn((
|
||||
Player,
|
||||
CameraSensitivity::default(),
|
||||
Transform::from_xyz(0.0, 1.0, 0.0),
|
||||
Visibility::default(),
|
||||
AccumulatedInput::default(),
|
||||
Velocity::default(),
|
||||
PhysicalTranslation(Vec3::new(0.0, 1.0, 0.0)),
|
||||
PreviousPhysicalTranslation(Vec3::new(0.0, 1.0, 0.0)),
|
||||
))
|
||||
.with_children(|parent| {
|
||||
parent.spawn((
|
||||
WorldModelCamera,
|
||||
Camera3d::default(),
|
||||
Projection::from(PerspectiveProjection {
|
||||
fov: 90.0_f32.to_radians(),
|
||||
..default()
|
||||
}),
|
||||
));
|
||||
|
||||
// we use a second layer ("framebuffer") to draw the player's arm on
|
||||
// there also a second camera that only views this buffer
|
||||
// this makes it easy because the second camera doesn't move with the player
|
||||
parent.spawn((
|
||||
Camera3d::default(),
|
||||
Camera {
|
||||
order: 1,
|
||||
..default()
|
||||
},
|
||||
Projection::from(PerspectiveProjection {
|
||||
fov: 70.0_f32.to_radians(),
|
||||
..default()
|
||||
}),
|
||||
RenderLayers::layer(STATIC_LAYER),
|
||||
));
|
||||
|
||||
parent.spawn((
|
||||
Mesh3d(arm),
|
||||
MeshMaterial3d(arm_material),
|
||||
Transform::from_xyz(0.2, -0.1, -0.25),
|
||||
RenderLayers::layer(STATIC_LAYER),
|
||||
NotShadowCaster,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
use std::f32::consts::FRAC_PI_2;
|
||||
const PITCH_LIMIT: f32 = FRAC_PI_2 - 0.01;
|
||||
|
||||
pub fn move_camera(
|
||||
accumulated_mouse_motion: Res<AccumulatedMouseMotion>,
|
||||
mut player: Query<(&mut Transform, &CameraSensitivity), With<Player>>,
|
||||
) {
|
||||
let Ok((mut transform, camera_sensitivity)) = player.get_single_mut() else {
|
||||
return;
|
||||
};
|
||||
let delta = accumulated_mouse_motion.delta;
|
||||
|
||||
if delta != Vec2::ZERO {
|
||||
let delta_yaw = -delta.x * camera_sensitivity.x;
|
||||
let delta_pitch = -delta.y * camera_sensitivity.y;
|
||||
|
||||
let (yaw, pitch, roll) = transform.rotation.to_euler(EulerRot::YXZ);
|
||||
let yaw = yaw + delta_yaw;
|
||||
let pitch = (pitch + delta_pitch).clamp(-PITCH_LIMIT, PITCH_LIMIT);
|
||||
transform.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, roll);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// PLAYER MOVEMENT
|
||||
|
||||
pub fn handle_input(
|
||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||
mut query: Query<(&Transform, &mut AccumulatedInput, &mut Velocity), With<Player>>,
|
||||
) {
|
||||
const SPEED: f32 = 2.0;
|
||||
for (transform, mut input, mut velocity) in query.iter_mut() {
|
||||
let forward = transform.forward(); // Forward direction (z axis)
|
||||
let right = transform.right(); // Right direction (x axis)
|
||||
|
||||
if keyboard_input.pressed(KeyCode::KeyW) { input.x += 1.0; }
|
||||
if keyboard_input.pressed(KeyCode::KeyS) { input.x -= 1.0; }
|
||||
if keyboard_input.pressed(KeyCode::KeyA) { input.z -= 1.0; }
|
||||
if keyboard_input.pressed(KeyCode::KeyD) { input.z += 1.0; }
|
||||
if keyboard_input.pressed(KeyCode::Space) { input.y += 1.0; }
|
||||
if keyboard_input.pressed(KeyCode::ShiftLeft) { input.y -= 1.0; }
|
||||
// velocity.0 = input * SPEED;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn step(
|
||||
fixed_time: Res<Time<Fixed>>,
|
||||
mut query: Query<(
|
||||
&mut PhysicalTranslation,
|
||||
&mut PreviousPhysicalTranslation,
|
||||
&mut AccumulatedInput,
|
||||
&Velocity,
|
||||
)>,
|
||||
) {
|
||||
for (
|
||||
mut current_physical_translation,
|
||||
mut previous_physical_translation,
|
||||
mut input,
|
||||
velocity,
|
||||
) in query.iter_mut()
|
||||
{
|
||||
previous_physical_translation.0 = current_physical_translation.0;
|
||||
current_physical_translation.0 += velocity.0 * fixed_time.delta_secs();
|
||||
input.0 = Vec3::ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn interpolate_rendered_transform(
|
||||
fixed_time: Res<Time<Fixed>>,
|
||||
mut query: Query<(
|
||||
&mut Transform,
|
||||
&PhysicalTranslation,
|
||||
&PreviousPhysicalTranslation,
|
||||
)>,
|
||||
) {
|
||||
for (mut transform, current_physical_translation, previous_physical_translation) in
|
||||
query.iter_mut()
|
||||
{
|
||||
let previous = previous_physical_translation.0;
|
||||
let current = current_physical_translation.0;
|
||||
// The overstep fraction is a value between 0 and 1 that tells us how far we are between two fixed timesteps.
|
||||
let alpha = fixed_time.overstep_fraction();
|
||||
|
||||
let rendered_translation = previous.lerp(current, alpha);
|
||||
transform.translation = rendered_translation;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn advance_physics(
|
||||
fixed_time: Res<Time<Fixed>>,
|
||||
mut query: Query<(
|
||||
&mut PhysicalTranslation,
|
||||
&mut PreviousPhysicalTranslation,
|
||||
&mut AccumulatedInput,
|
||||
&Velocity,
|
||||
)>,
|
||||
) {
|
||||
for (
|
||||
mut current_physical_translation,
|
||||
mut previous_physical_translation,
|
||||
mut input,
|
||||
velocity,
|
||||
) in query.iter_mut()
|
||||
{
|
||||
previous_physical_translation.0 = current_physical_translation.0;
|
||||
current_physical_translation.0 += velocity.0 * fixed_time.delta_secs();
|
||||
|
||||
// Reset the input accumulator, as we are currently consuming all input that happened since the last fixed timestep.
|
||||
input.0 = Vec3::ZERO;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user