player and physics plygins
This commit is contained in:
21
src/main.rs
21
src/main.rs
@@ -1,26 +1,19 @@
|
||||
use asset_loading::ImageAssets;
|
||||
use bevy::{prelude::*, state::app::StatesPlugin};
|
||||
use bevy::prelude::*;
|
||||
use player_plugin::PlayerPlugin;
|
||||
use physics_plugin::PhysicsPlugin;
|
||||
|
||||
mod asset_loading;
|
||||
|
||||
pub mod player;
|
||||
mod player_plugin;
|
||||
mod physics_plugin;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins((DefaultPlugins, asset_loading::plugin))
|
||||
.add_plugins((DefaultPlugins, asset_loading::plugin, PlayerPlugin, PhysicsPlugin))
|
||||
.init_state::<GameState>()
|
||||
// We need to register components to make them visible to Blenvy
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(OnExit(GameState::Loading), debug_our_king)
|
||||
.add_systems(Startup, (setup, player::init_player))
|
||||
.add_systems(Update, player::move_camera)
|
||||
.add_systems(FixedUpdate, player::advance_physics)
|
||||
.add_systems(
|
||||
RunFixedMainLoop,
|
||||
(
|
||||
player::handle_input.in_set(RunFixedMainLoopSystem::BeforeFixedMainLoop),
|
||||
player::interpolate_rendered_transform.in_set(RunFixedMainLoopSystem::AfterFixedMainLoop),
|
||||
),
|
||||
)
|
||||
.run();
|
||||
}
|
||||
|
||||
|
||||
72
src/physics_plugin.rs
Normal file
72
src/physics_plugin.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
use bevy::prelude::*;
|
||||
|
||||
#[derive(Debug, Component, Clone, Copy, PartialEq, Default, Deref, DerefMut)]
|
||||
pub struct Velocity(pub 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(pub 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(pub Vec3);
|
||||
|
||||
#[derive(Debug, Component, Clone, Copy, PartialEq, Default, Deref, DerefMut)]
|
||||
pub struct AccumulatedInput(pub Vec3);
|
||||
|
||||
pub struct PhysicsPlugin;
|
||||
impl Plugin for PhysicsPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_systems(RunFixedMainLoop, interpolate_rendered_transform.in_set(RunFixedMainLoopSystem::AfterFixedMainLoop))
|
||||
.add_systems(FixedUpdate, step);
|
||||
}
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
use bevy::{
|
||||
input::mouse::AccumulatedMouseMotion, pbr::NotShadowCaster,
|
||||
prelude::*, render::view::RenderLayers,
|
||||
};
|
||||
|
||||
use bevy::{prelude::*, render::view::RenderLayers, input::mouse::AccumulatedMouseMotion, pbr::NotShadowCaster};
|
||||
use crate::physics_plugin::{AccumulatedInput, Velocity, PhysicalTranslation, PreviousPhysicalTranslation};
|
||||
|
||||
#[derive(Debug, Component)]
|
||||
pub struct Player;
|
||||
@@ -20,32 +17,14 @@ impl Default for CameraSensitivity {
|
||||
#[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);
|
||||
|
||||
|
||||
|
||||
pub struct PlayerPlugin;
|
||||
impl Plugin for PlayerPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_systems(Startup, init_player)
|
||||
.add_systems(Update, move_camera)
|
||||
.add_systems(RunFixedMainLoop, handle_input.in_set(RunFixedMainLoopSystem::BeforeFixedMainLoop));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -113,6 +92,7 @@ pub fn init_player(
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
use std::f32::consts::FRAC_PI_2;
|
||||
const PITCH_LIMIT: f32 = FRAC_PI_2 - 0.01;
|
||||
|
||||
@@ -136,10 +116,6 @@ pub fn move_camera(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// PLAYER MOVEMENT
|
||||
|
||||
pub fn handle_input(
|
||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||
mut query: Query<(&Transform, &mut AccumulatedInput, &mut Velocity), With<Player>>,
|
||||
@@ -149,79 +125,26 @@ pub fn handle_input(
|
||||
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::KeyW) {
|
||||
input.x += forward.x;
|
||||
input.z += forward.z;
|
||||
}
|
||||
if keyboard_input.pressed(KeyCode::KeyS) {
|
||||
input.x -= forward.x;
|
||||
input.z -= forward.z;
|
||||
}
|
||||
if keyboard_input.pressed(KeyCode::KeyA) {
|
||||
input.x -= right.x;
|
||||
input.z -= right.z;
|
||||
}
|
||||
if keyboard_input.pressed(KeyCode::KeyD) {
|
||||
input.x += right.x;
|
||||
input.z += right.z;
|
||||
}
|
||||
if keyboard_input.pressed(KeyCode::Space) { input.y += 1.0; }
|
||||
if keyboard_input.pressed(KeyCode::ShiftLeft) { input.y -= 1.0; }
|
||||
// velocity.0 = input * SPEED;
|
||||
velocity.0 = input.normalize_or_zero() * 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