124 lines
3.5 KiB
Rust
124 lines
3.5 KiB
Rust
use bevy::prelude::*;
|
|
|
|
use crate::collision::check_collision_with_player;
|
|
use crate::collision::{Collider, HasCollided};
|
|
use crate::obstacle::RegenerateObstacles;
|
|
|
|
const FALL_SPEED: f32 = 600.0; // Falling speed
|
|
const DIVE_SPEED: f32 = 1000.0; // Falling speed sped up
|
|
const HORIZONTAL_SPEED: f32 = 350.0; // Lateral movement speed
|
|
pub const START_POSITION: Vec3 = Vec3::new(0.0, 0.0, 2.0); // Start position
|
|
const RATE: f32 = 13.0; // Inertia rate
|
|
|
|
// The player
|
|
#[derive(Component)]
|
|
pub struct Player;
|
|
|
|
// Speed of the player
|
|
#[derive(Component)]
|
|
pub struct Velocity(Vec2);
|
|
|
|
// Falling bool
|
|
#[derive(Resource, Default)]
|
|
pub struct FallStarted(pub bool);
|
|
|
|
// Spawn entity player
|
|
fn spawn_player(mut commands: Commands) {
|
|
commands.spawn((
|
|
Player,
|
|
Collider {
|
|
size: Vec2::new(20.0, 40.0),
|
|
},
|
|
Velocity(Vec2::ZERO),
|
|
Sprite::from_color(Color::srgb(1.0, 1.0, 1.0), Vec2::new(20.0, 40.0)),
|
|
Transform::from_xyz(START_POSITION.x, START_POSITION.y, START_POSITION.z),
|
|
));
|
|
}
|
|
|
|
// Input + movement system for the player
|
|
pub(crate) fn move_player(
|
|
input: Res<ButtonInput<KeyCode>>,
|
|
time: Res<Time>,
|
|
mut player: Query<(&mut Velocity, &mut Transform), With<Player>>,
|
|
mut fall_started: ResMut<FallStarted>,
|
|
) {
|
|
// If matching entity
|
|
let Ok((mut velocity, mut transform)) = player.single_mut() else {
|
|
return;
|
|
};
|
|
|
|
if !fall_started.0
|
|
&& (input.just_pressed(KeyCode::KeyA)
|
|
|| input.just_pressed(KeyCode::KeyD)
|
|
|| input.just_pressed(KeyCode::KeyS))
|
|
{
|
|
fall_started.0 = true;
|
|
} else if !fall_started.0 {
|
|
// Null speed
|
|
return;
|
|
}
|
|
|
|
// Change then horizontal direction regardless the input
|
|
let direction = if input.pressed(KeyCode::KeyA) {
|
|
-1.0
|
|
} else if input.pressed(KeyCode::KeyD) {
|
|
1.0
|
|
} else {
|
|
0.0
|
|
};
|
|
|
|
let facteur = 1.0 - (-RATE * time.delta_secs()).exp();
|
|
let target = Vec2::new(
|
|
direction * HORIZONTAL_SPEED,
|
|
-if input.pressed(KeyCode::KeyS) {
|
|
DIVE_SPEED
|
|
} else {
|
|
FALL_SPEED
|
|
},
|
|
);
|
|
|
|
velocity.0 = velocity.0.lerp(target, facteur);
|
|
|
|
// Position update (no smoothness in velocity)
|
|
transform.translation += velocity.0.extend(0.0) * time.delta_secs();
|
|
}
|
|
|
|
// Reset player position
|
|
pub fn reset_player(
|
|
mut player: Single<(&mut Transform, &mut Velocity, &mut Sprite), With<Player>>,
|
|
input: Res<ButtonInput<KeyCode>>,
|
|
mut has_collided: ResMut<HasCollided>,
|
|
mut fall_started: ResMut<FallStarted>,
|
|
mut regenerate_obstacles: ResMut<RegenerateObstacles>,
|
|
) {
|
|
let (mut transform, mut velocity, mut sprite) = player.into_inner();
|
|
|
|
// R key for reset or player has collider
|
|
if input.just_pressed(KeyCode::KeyR) || has_collided.0 {
|
|
transform.translation = Vec3::new(START_POSITION.x, START_POSITION.y, START_POSITION.z);
|
|
velocity.0 = Vec2::ZERO;
|
|
sprite.color = Color::WHITE;
|
|
|
|
has_collided.0 = false;
|
|
fall_started.0 = false;
|
|
// TODO: uncomment when obstacle chunk logic is implemented
|
|
// regenerate_obstacles.0 = true;
|
|
}
|
|
}
|
|
|
|
pub struct PlayerPlugin;
|
|
|
|
impl Plugin for PlayerPlugin {
|
|
fn build(&self, app: &mut App) {
|
|
app.add_systems(Startup, spawn_player)
|
|
.init_resource::<FallStarted>()
|
|
.add_systems(Update, move_player)
|
|
.add_systems(
|
|
Update,
|
|
reset_player
|
|
.after(move_player)
|
|
.after(check_collision_with_player),
|
|
);
|
|
}
|
|
}
|