use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, (spawn_text, spawn_player))
.add_systems(FixedUpdate, advance_physics)
.add_systems(
RunFixedMainLoop,
(
handle_input.in_set(RunFixedMainLoopSystem::BeforeFixedMainLoop),
interpolate_rendered_transform.in_set(RunFixedMainLoopSystem::AfterFixedMainLoop),
),
)
.run();
}
#[derive(Debug, Component, Clone, Copy, PartialEq, Default, Deref, DerefMut)]
struct AccumulatedInput(Vec2);
#[derive(Debug, Component, Clone, Copy, PartialEq, Default, Deref, DerefMut)]
struct Velocity(Vec3);
#[derive(Debug, Component, Clone, Copy, PartialEq, Default, Deref, DerefMut)]
struct PhysicalTranslation(Vec3);
#[derive(Debug, Component, Clone, Copy, PartialEq, Default, Deref, DerefMut)]
struct PreviousPhysicalTranslation(Vec3);
fn spawn_player(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(Camera2d);
commands.spawn((
Name::new("Player"),
Sprite::from_image(asset_server.load("branding/icon.png")),
Transform::from_scale(Vec3::splat(0.3)),
AccumulatedInput::default(),
Velocity::default(),
PhysicalTranslation::default(),
PreviousPhysicalTranslation::default(),
));
}
fn spawn_text(mut commands: Commands) {
commands
.spawn(Node {
position_type: PositionType::Absolute,
bottom: Val::Px(12.0),
left: Val::Px(12.0),
..default()
})
.with_child((
Text::new("Move the player with WASD"),
TextFont {
font_size: 25.0,
..default()
},
));
}
fn handle_input(
keyboard_input: Res<ButtonInput<KeyCode>>,
mut query: Query<(&mut AccumulatedInput, &mut Velocity)>,
) {
const SPEED: f32 = 210.0;
for (mut input, mut velocity) in query.iter_mut() {
if keyboard_input.pressed(KeyCode::KeyW) {
input.y += 1.0;
}
if keyboard_input.pressed(KeyCode::KeyS) {
input.y -= 1.0;
}
if keyboard_input.pressed(KeyCode::KeyA) {
input.x -= 1.0;
}
if keyboard_input.pressed(KeyCode::KeyD) {
input.x += 1.0;
}
velocity.0 = input.extend(0.0).normalize_or_zero() * SPEED;
}
}
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();
input.0 = Vec2::ZERO;
}
}
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;
let alpha = fixed_time.overstep_fraction();
let rendered_translation = previous.lerp(current, alpha);
transform.translation = rendered_translation;
}
}