|
|
|
|
@ -12,7 +12,9 @@ fn main() {
|
|
|
|
|
.init_state::<PlayerState>()
|
|
|
|
|
.add_systems(Startup, (init_bird, init_obstacles, init_ui, tweak_camera.after(setup_camera)))
|
|
|
|
|
.add_systems(OnEnter(PlayerState::Alive), alive_bird)
|
|
|
|
|
.add_systems(OnExit(PlayerState::Alive), kill_bird)
|
|
|
|
|
.add_systems(OnEnter(PlayerState::Pause), pause_bird)
|
|
|
|
|
.add_systems(OnEnter(PlayerState::Stasis), pause_bird)
|
|
|
|
|
.add_systems(OnEnter(PlayerState::Rewind), pause_bird)
|
|
|
|
|
.add_systems(
|
|
|
|
|
Update,
|
|
|
|
|
(
|
|
|
|
|
@ -42,6 +44,8 @@ fn main() {
|
|
|
|
|
rewind.run_if(in_state(PlayerState::Rewind)),
|
|
|
|
|
// Camera follows when bird moves regardless of player state
|
|
|
|
|
camera_follow_bird.run_if(any_component_changed::<Transform>),
|
|
|
|
|
// Pause when the player presses Escape
|
|
|
|
|
pause_game.run_if(input_just_pressed(KeyCode::Escape)),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
.run();
|
|
|
|
|
@ -63,10 +67,11 @@ struct Bird;
|
|
|
|
|
|
|
|
|
|
#[derive(States, Clone, Eq, PartialEq, Debug, Hash, Default, Component)]
|
|
|
|
|
enum PlayerState {
|
|
|
|
|
#[default]
|
|
|
|
|
Alive,
|
|
|
|
|
Rewind,
|
|
|
|
|
Dead,
|
|
|
|
|
Stasis,
|
|
|
|
|
#[default]
|
|
|
|
|
Pause
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A tape tracking the bird's state every frame
|
|
|
|
|
@ -96,7 +101,7 @@ fn init_bird(
|
|
|
|
|
let t = Transform::from_xyz(0.0, 0.0, 0.0).with_rotation(Quat::from_rotation_x(PI / 2.0));
|
|
|
|
|
|
|
|
|
|
let physics = (
|
|
|
|
|
RigidBody::Dynamic,
|
|
|
|
|
RigidBody::Static,
|
|
|
|
|
Collider::capsule(1.0, 1.0), Mass(1.0),
|
|
|
|
|
ExternalForce::new(Vec3::X * 1.0).with_persistence(true),
|
|
|
|
|
ExternalImpulse::default().with_persistence(false),
|
|
|
|
|
@ -150,7 +155,7 @@ fn init_obstacles(
|
|
|
|
|
// screens and then "move" them around.
|
|
|
|
|
// This is considerably more complexity so can be implemented later, but would keep memory
|
|
|
|
|
// overhead fairly static.
|
|
|
|
|
(1..50).for_each(|i| {
|
|
|
|
|
(1..99).for_each(|i| {
|
|
|
|
|
// TODO: Jitter up/down/close/far of pipes for challenge
|
|
|
|
|
let above = Transform::from_xyz(5.0 * i as f32, 4.0, 0.0);
|
|
|
|
|
let below = Transform::from_xyz(5.0 * i as f32, -4.0, 0.0);
|
|
|
|
|
@ -173,12 +178,38 @@ fn init_ui(
|
|
|
|
|
flex_direction: FlexDirection::Column,
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
PlayerState::Dead,
|
|
|
|
|
PlayerState::Stasis,
|
|
|
|
|
children![
|
|
|
|
|
Text::new("You Died"),
|
|
|
|
|
Text::new("Press R to Rewind"),
|
|
|
|
|
],
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
fn start_game(_trigger: Trigger<Pointer<Click>>, mut next: ResMut<NextState<PlayerState>>) {
|
|
|
|
|
next.set(PlayerState::Alive);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
commands.spawn((
|
|
|
|
|
Node {
|
|
|
|
|
align_self: AlignSelf::Center,
|
|
|
|
|
justify_self: JustifySelf::Center,
|
|
|
|
|
flex_direction: FlexDirection::Column,
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
Button,
|
|
|
|
|
// TODO: Add Pause (basically Stasis) state
|
|
|
|
|
PlayerState::Pause,
|
|
|
|
|
children![
|
|
|
|
|
Text::new("Go!"),
|
|
|
|
|
],
|
|
|
|
|
)).observe(start_game);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Pause the game when the player presses "Escape"
|
|
|
|
|
fn pause_game(
|
|
|
|
|
mut next: ResMut<NextState<PlayerState>>,
|
|
|
|
|
) {
|
|
|
|
|
next.set(PlayerState::Pause);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: Create floor (and ceiling?)
|
|
|
|
|
@ -268,7 +299,7 @@ fn detect_dead(
|
|
|
|
|
if obstacles.iter().any(|obstacle| {
|
|
|
|
|
bird.intersects(obstacle)
|
|
|
|
|
}) {
|
|
|
|
|
next.set(PlayerState::Dead);
|
|
|
|
|
next.set(PlayerState::Stasis);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -276,17 +307,17 @@ fn alive_bird(
|
|
|
|
|
#[cfg(debug_assertions)] state: Res<State<PlayerState>>,
|
|
|
|
|
mut bird: Single<&mut RigidBody, With<Bird>>,
|
|
|
|
|
) {
|
|
|
|
|
debug_assert!(!matches!(state.get(), PlayerState::Dead));
|
|
|
|
|
debug!("Aliving bird");
|
|
|
|
|
debug_assert!(matches!(state.get(), PlayerState::Alive));
|
|
|
|
|
debug!("Setting bird to Dynamic");
|
|
|
|
|
**bird = RigidBody::Dynamic;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn kill_bird(
|
|
|
|
|
fn pause_bird(
|
|
|
|
|
#[cfg(debug_assertions)] state: Res<State<PlayerState>>,
|
|
|
|
|
mut bird: Single<&mut RigidBody, With<Bird>>,
|
|
|
|
|
) {
|
|
|
|
|
debug_assert!(!matches!(state.get(), PlayerState::Alive));
|
|
|
|
|
debug!("Killing bird");
|
|
|
|
|
debug!("Setting bird to Static");
|
|
|
|
|
**bird = RigidBody::Static;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|