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 asset_loading::ImageAssets;
|
||||||
use bevy::{prelude::*, state::app::StatesPlugin};
|
use bevy::prelude::*;
|
||||||
|
use player_plugin::PlayerPlugin;
|
||||||
|
use physics_plugin::PhysicsPlugin;
|
||||||
|
|
||||||
mod asset_loading;
|
mod asset_loading;
|
||||||
|
mod player_plugin;
|
||||||
pub mod player;
|
mod physics_plugin;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins((DefaultPlugins, asset_loading::plugin))
|
.add_plugins((DefaultPlugins, asset_loading::plugin, PlayerPlugin, PhysicsPlugin))
|
||||||
.init_state::<GameState>()
|
.init_state::<GameState>()
|
||||||
// We need to register components to make them visible to Blenvy
|
// 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(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();
|
.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::{
|
use bevy::{prelude::*, render::view::RenderLayers, input::mouse::AccumulatedMouseMotion, pbr::NotShadowCaster};
|
||||||
input::mouse::AccumulatedMouseMotion, pbr::NotShadowCaster,
|
use crate::physics_plugin::{AccumulatedInput, Velocity, PhysicalTranslation, PreviousPhysicalTranslation};
|
||||||
prelude::*, render::view::RenderLayers,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Component)]
|
#[derive(Debug, Component)]
|
||||||
pub struct Player;
|
pub struct Player;
|
||||||
@@ -20,32 +17,14 @@ impl Default for CameraSensitivity {
|
|||||||
#[derive(Debug, Component)]
|
#[derive(Debug, Component)]
|
||||||
struct WorldModelCamera;
|
struct WorldModelCamera;
|
||||||
|
|
||||||
|
pub struct PlayerPlugin;
|
||||||
#[derive(Debug, Component, Clone, Copy, PartialEq, Default, Deref, DerefMut)]
|
impl Plugin for PlayerPlugin {
|
||||||
pub struct AccumulatedInput(Vec3);
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_systems(Startup, init_player)
|
||||||
|
.add_systems(Update, move_camera)
|
||||||
#[derive(Debug, Component, Clone, Copy, PartialEq, Default, Deref, DerefMut)]
|
.add_systems(RunFixedMainLoop, handle_input.in_set(RunFixedMainLoopSystem::BeforeFixedMainLoop));
|
||||||
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);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -113,6 +92,7 @@ pub fn init_player(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
use std::f32::consts::FRAC_PI_2;
|
use std::f32::consts::FRAC_PI_2;
|
||||||
const PITCH_LIMIT: f32 = FRAC_PI_2 - 0.01;
|
const PITCH_LIMIT: f32 = FRAC_PI_2 - 0.01;
|
||||||
|
|
||||||
@@ -136,10 +116,6 @@ pub fn move_camera(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// PLAYER MOVEMENT
|
|
||||||
|
|
||||||
pub fn handle_input(
|
pub fn handle_input(
|
||||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||||
mut query: Query<(&Transform, &mut AccumulatedInput, &mut Velocity), With<Player>>,
|
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 forward = transform.forward(); // Forward direction (z axis)
|
||||||
let right = transform.right(); // Right direction (x axis)
|
let right = transform.right(); // Right direction (x axis)
|
||||||
|
|
||||||
if keyboard_input.pressed(KeyCode::KeyW) { input.x += 1.0; }
|
if keyboard_input.pressed(KeyCode::KeyW) {
|
||||||
if keyboard_input.pressed(KeyCode::KeyS) { input.x -= 1.0; }
|
input.x += forward.x;
|
||||||
if keyboard_input.pressed(KeyCode::KeyA) { input.z -= 1.0; }
|
input.z += forward.z;
|
||||||
if keyboard_input.pressed(KeyCode::KeyD) { input.z += 1.0; }
|
}
|
||||||
|
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::Space) { input.y += 1.0; }
|
||||||
if keyboard_input.pressed(KeyCode::ShiftLeft) { 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