|
|
|
@ -1,9 +1,9 @@
|
|
|
|
// Bevy basically forces "complex types" with Querys
|
|
|
|
// Bevy basically forces "complex types" with Querys
|
|
|
|
#![allow(clippy::type_complexity)]
|
|
|
|
#![allow(clippy::type_complexity)]
|
|
|
|
|
|
|
|
|
|
|
|
use std::hash::BuildHasher;
|
|
|
|
|
|
|
|
use games::physics2d::*;
|
|
|
|
use games::physics2d::*;
|
|
|
|
use games::*;
|
|
|
|
use games::*;
|
|
|
|
|
|
|
|
use std::hash::BuildHasher;
|
|
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
fn main() {
|
|
|
|
App::new()
|
|
|
|
App::new()
|
|
|
|
@ -35,9 +35,9 @@ fn main() {
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
.add_systems(OnEnter(PlayerState::Alive), alive_bird)
|
|
|
|
.add_systems(OnEnter(PlayerState::Alive), alive_bird)
|
|
|
|
|
|
|
|
.add_systems(OnEnter(PlayerState::Rewind), alive_bird)
|
|
|
|
.add_systems(OnEnter(PlayerState::Pause), pause_bird)
|
|
|
|
.add_systems(OnEnter(PlayerState::Pause), pause_bird)
|
|
|
|
.add_systems(OnEnter(PlayerState::Stasis), pause_bird)
|
|
|
|
.add_systems(OnEnter(PlayerState::Stasis), pause_bird)
|
|
|
|
// .add_systems(OnEnter(PlayerState::Rewind), pause_bird)
|
|
|
|
|
|
|
|
.add_systems(
|
|
|
|
.add_systems(
|
|
|
|
Update,
|
|
|
|
Update,
|
|
|
|
(
|
|
|
|
(
|
|
|
|
@ -84,21 +84,16 @@ fn main() {
|
|
|
|
update_batch_position.run_if(any_component_changed::<Batch>),
|
|
|
|
update_batch_position.run_if(any_component_changed::<Batch>),
|
|
|
|
update_tooltip.run_if(in_state(DebuggingState::On)),
|
|
|
|
update_tooltip.run_if(in_state(DebuggingState::On)),
|
|
|
|
// TODO: Add run_if to this system
|
|
|
|
// TODO: Add run_if to this system
|
|
|
|
manage_batches,
|
|
|
|
hitbox_collision_handler,
|
|
|
|
(
|
|
|
|
// TODO: Add run_if to this system
|
|
|
|
// Temp debugging systems
|
|
|
|
manage_score,
|
|
|
|
debug_collision_events.run_if(on_event::<CollisionEnded>),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
.add_observer(debug_collision_start_observations)
|
|
|
|
|
|
|
|
.add_observer(debug_collision_end_observations)
|
|
|
|
|
|
|
|
.add_observer(flap)
|
|
|
|
.add_observer(flap)
|
|
|
|
.add_observer(populate_batch)
|
|
|
|
.add_observer(populate_batch)
|
|
|
|
.add_observer(populate_pipe)
|
|
|
|
.add_observer(populate_pipe)
|
|
|
|
.add_observer(populate_ground)
|
|
|
|
.add_observer(populate_ground)
|
|
|
|
.add_observer(populate_hitbox)
|
|
|
|
.add_observer(populate_hitbox)
|
|
|
|
.add_observer(manage_score)
|
|
|
|
|
|
|
|
.run();
|
|
|
|
.run();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -275,7 +270,7 @@ fn populate_pipe(
|
|
|
|
pipes: Query<(&Pipe, &Batch)>,
|
|
|
|
pipes: Query<(&Pipe, &Batch)>,
|
|
|
|
pipe_assets: Res<PipeAssets>,
|
|
|
|
pipe_assets: Res<PipeAssets>,
|
|
|
|
mut commands: Commands,
|
|
|
|
mut commands: Commands,
|
|
|
|
rand: Res<Rand>
|
|
|
|
rand: Res<Rand>,
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
let pipe_t = {
|
|
|
|
let pipe_t = {
|
|
|
|
let (pipe, Batch(id)) = pipes.get(trigger.target()).unwrap();
|
|
|
|
let (pipe, Batch(id)) = pipes.get(trigger.target()).unwrap();
|
|
|
|
@ -294,8 +289,12 @@ fn populate_pipe(
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
match pipe {
|
|
|
|
match pipe {
|
|
|
|
Pipe::Top => Transform::from_xyz(0.0, 200.0 + offset, -1.0).with_scale(Vec3::splat(100.0)),
|
|
|
|
Pipe::Top => {
|
|
|
|
Pipe::Bottom => Transform::from_xyz(0.0, -100.0 + offset, -1.0).with_scale(Vec3::splat(100.0)),
|
|
|
|
Transform::from_xyz(0.0, 200.0 + offset, -1.0).with_scale(Vec3::splat(100.0))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Pipe::Bottom => {
|
|
|
|
|
|
|
|
Transform::from_xyz(0.0, -100.0 + offset, -1.0).with_scale(Vec3::splat(100.0))
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
commands.entity(trigger.target()).insert((
|
|
|
|
commands.entity(trigger.target()).insert((
|
|
|
|
@ -447,14 +446,22 @@ fn init_ui(mut commands: Commands) {
|
|
|
|
..default()
|
|
|
|
..default()
|
|
|
|
},
|
|
|
|
},
|
|
|
|
PlayerState::Credits,
|
|
|
|
PlayerState::Credits,
|
|
|
|
children![(Text::new(credits_str), TextLayout::new_with_justify(JustifyText::Center))],
|
|
|
|
children![(
|
|
|
|
|
|
|
|
Text::new(credits_str),
|
|
|
|
|
|
|
|
TextLayout::new_with_justify(JustifyText::Center)
|
|
|
|
|
|
|
|
)],
|
|
|
|
))
|
|
|
|
))
|
|
|
|
.with_children(|parent| {
|
|
|
|
.with_children(|parent| {
|
|
|
|
parent.spawn((Node {
|
|
|
|
parent.spawn((
|
|
|
|
|
|
|
|
Node {
|
|
|
|
align_self: AlignSelf::Center,
|
|
|
|
align_self: AlignSelf::Center,
|
|
|
|
..default()
|
|
|
|
..default()
|
|
|
|
}, Button, children![Text::new("Close")]));
|
|
|
|
},
|
|
|
|
}).observe(hide_credits);
|
|
|
|
Button,
|
|
|
|
|
|
|
|
children![Text::new("Close")],
|
|
|
|
|
|
|
|
));
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.observe(hide_credits);
|
|
|
|
|
|
|
|
|
|
|
|
fn start_game(_trigger: Trigger<Pointer<Click>>, mut next: ResMut<NextState<PlayerState>>) {
|
|
|
|
fn start_game(_trigger: Trigger<Pointer<Click>>, mut next: ResMut<NextState<PlayerState>>) {
|
|
|
|
next.set(PlayerState::Alive);
|
|
|
|
next.set(PlayerState::Alive);
|
|
|
|
@ -635,6 +642,7 @@ fn record(
|
|
|
|
|
|
|
|
|
|
|
|
fn rewind(
|
|
|
|
fn rewind(
|
|
|
|
#[cfg(debug_assertions)] state: Res<State<PlayerState>>,
|
|
|
|
#[cfg(debug_assertions)] state: Res<State<PlayerState>>,
|
|
|
|
|
|
|
|
mut next: ResMut<NextState<PlayerState>>,
|
|
|
|
mut birds: Query<
|
|
|
|
mut birds: Query<
|
|
|
|
(
|
|
|
|
(
|
|
|
|
&mut AccumulatedTranslation,
|
|
|
|
&mut AccumulatedTranslation,
|
|
|
|
@ -660,7 +668,10 @@ fn rewind(
|
|
|
|
|
|
|
|
|
|
|
|
birds.iter_mut().for_each(
|
|
|
|
birds.iter_mut().for_each(
|
|
|
|
|(mut at, mut lv, mut av, mut eai, mut ef, mut ei, mut et, mut p, mut r, mut tape)| {
|
|
|
|
|(mut at, mut lv, mut av, mut eai, mut ef, mut ei, mut et, mut p, mut r, mut tape)| {
|
|
|
|
if !tape.positions.is_empty() {
|
|
|
|
if tape.positions.is_empty() {
|
|
|
|
|
|
|
|
next.set(PlayerState::Pause);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// TODO: Only record/restore variables that we manage!
|
|
|
|
at.0 = tape.accumulated_translations.pop().unwrap().0;
|
|
|
|
at.0 = tape.accumulated_translations.pop().unwrap().0;
|
|
|
|
lv.0 = tape.linear_velocities.pop().unwrap().0;
|
|
|
|
lv.0 = tape.linear_velocities.pop().unwrap().0;
|
|
|
|
av.0 = tape.angular_velocities.pop().unwrap().0;
|
|
|
|
av.0 = tape.angular_velocities.pop().unwrap().0;
|
|
|
|
@ -701,12 +712,8 @@ fn detect_dead(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn alive_bird(
|
|
|
|
fn alive_bird(
|
|
|
|
#[cfg(debug_assertions)] state: Res<State<PlayerState>>,
|
|
|
|
|
|
|
|
mut bird: Single<&mut RigidBody, With<Bird>>,
|
|
|
|
mut bird: Single<&mut RigidBody, With<Bird>>,
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
|
|
|
|
debug_assert!(matches!(state.get(), PlayerState::Alive));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
debug!("Setting bird to Dynamic");
|
|
|
|
debug!("Setting bird to Dynamic");
|
|
|
|
**bird = RigidBody::Dynamic;
|
|
|
|
**bird = RigidBody::Dynamic;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -716,8 +723,6 @@ fn pause_bird(
|
|
|
|
mut bird: Single<&mut RigidBody, With<Bird>>,
|
|
|
|
mut bird: Single<&mut RigidBody, With<Bird>>,
|
|
|
|
mut deaths: ResMut<Deaths>,
|
|
|
|
mut deaths: ResMut<Deaths>,
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
debug_assert!(!matches!(state.get(), PlayerState::Alive));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Increment death count
|
|
|
|
// Increment death count
|
|
|
|
if state.get() == &PlayerState::Stasis {
|
|
|
|
if state.get() == &PlayerState::Stasis {
|
|
|
|
deaths.0 += 1
|
|
|
|
deaths.0 += 1
|
|
|
|
@ -775,65 +780,45 @@ impl Display for Deaths {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn manage_score(
|
|
|
|
fn manage_score(
|
|
|
|
trigger: Trigger<OnCollisionEnd>,
|
|
|
|
mut start: EventReader<CollisionStarted>,
|
|
|
|
|
|
|
|
mut end: EventReader<CollisionEnded>,
|
|
|
|
state: Res<State<PlayerState>>,
|
|
|
|
state: Res<State<PlayerState>>,
|
|
|
|
bird: Query<Entity, With<Bird>>,
|
|
|
|
|
|
|
|
hitboxes: Query<&Batch, With<Hitbox>>,
|
|
|
|
hitboxes: Query<&Batch, With<Hitbox>>,
|
|
|
|
mut score: ResMut<Score>,
|
|
|
|
mut score: ResMut<Score>,
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
let a = trigger.target();
|
|
|
|
match state.get() {
|
|
|
|
let b = trigger.collider;
|
|
|
|
PlayerState::Rewind => {
|
|
|
|
if bird.contains(a) && hitboxes.contains(b) {
|
|
|
|
start.read().for_each(|CollisionStarted(a, b)| {
|
|
|
|
debug!("Hit event while {:?}", state.get());
|
|
|
|
// Set score to collided hitbox
|
|
|
|
let Batch(id) = hitboxes.get(b).unwrap();
|
|
|
|
if let Ok(Batch(this)) = hitboxes.get(*a)
|
|
|
|
score.0 = match state.get() {
|
|
|
|
{
|
|
|
|
PlayerState::Alive => *id,
|
|
|
|
info!("[Rewind] Setting score to {this}");
|
|
|
|
PlayerState::Rewind => *id - 1,
|
|
|
|
score.0 = this - 1;
|
|
|
|
_ => *id, // HOW???
|
|
|
|
} else if let Ok(Batch(this)) = hitboxes.get(*b) {
|
|
|
|
|
|
|
|
info!("[Rewind] Setting score to {this}");
|
|
|
|
|
|
|
|
score.0 = this - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
|
|
|
|
|
|
|
|
fn debug_collision_events(
|
|
|
|
|
|
|
|
mut end: EventReader<CollisionEnded>,
|
|
|
|
|
|
|
|
mut start: EventReader<CollisionStarted>,
|
|
|
|
|
|
|
|
state: Res<State<PlayerState>>,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
start.read().for_each(|CollisionStarted(a, b)| {
|
|
|
|
|
|
|
|
debug!("Collision started between {a} and {b} in {:?}", state.get());
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
end.read().for_each(|CollisionEnded(a, b)| {
|
|
|
|
end.read().for_each(|CollisionEnded(a, b)| {
|
|
|
|
debug!("Collision ended between {a} and {b} in {:?}", state.get());
|
|
|
|
// Set score to collided hitbox
|
|
|
|
});
|
|
|
|
if let Ok(Batch(this)) = hitboxes.get(*b)
|
|
|
|
}
|
|
|
|
{
|
|
|
|
|
|
|
|
info!("[Alive] Setting score to {this}");
|
|
|
|
fn debug_collision_start_observations(
|
|
|
|
score.0 = *this;
|
|
|
|
trigger: Trigger<OnCollisionStart>,
|
|
|
|
} else if let Ok(Batch(this)) = hitboxes.get(*a) {
|
|
|
|
state: Res<State<PlayerState>>,
|
|
|
|
info!("[Alive] Setting score to {this}");
|
|
|
|
) {
|
|
|
|
score.0 = *this;
|
|
|
|
debug!(
|
|
|
|
}
|
|
|
|
"Collision started between {} and {} in {:?}",
|
|
|
|
})
|
|
|
|
trigger.target(),
|
|
|
|
}
|
|
|
|
trigger.collider,
|
|
|
|
}
|
|
|
|
state.get()
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn debug_collision_end_observations(
|
|
|
|
|
|
|
|
trigger: Trigger<OnCollisionEnd>,
|
|
|
|
|
|
|
|
state: Res<State<PlayerState>>,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
debug!(
|
|
|
|
|
|
|
|
"Collision end between {} and {} in {:?}",
|
|
|
|
|
|
|
|
trigger.target(),
|
|
|
|
|
|
|
|
trigger.collider,
|
|
|
|
|
|
|
|
state.get()
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// When the player moves forward while alive
|
|
|
|
/// When the player moves forward while alive
|
|
|
|
/// spawn more batches and despawn old batches
|
|
|
|
/// spawn more batches and despawn old batches
|
|
|
|
fn manage_batches(
|
|
|
|
fn hitbox_collision_handler(
|
|
|
|
bird: Query<&ColliderAabb, With<Bird>>,
|
|
|
|
bird: Query<&ColliderAabb, With<Bird>>,
|
|
|
|
hitboxes: Query<(Entity, &ColliderAabb), With<Hitbox>>,
|
|
|
|
hitboxes: Query<(Entity, &ColliderAabb), With<Hitbox>>,
|
|
|
|
batches: Query<(Entity, &Batch)>,
|
|
|
|
batches: Query<(Entity, &Batch)>,
|
|
|
|
@ -841,24 +826,25 @@ fn manage_batches(
|
|
|
|
mut commands: Commands,
|
|
|
|
mut commands: Commands,
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
bird.iter().for_each(|bird_aabb| {
|
|
|
|
bird.iter().for_each(|bird_aabb| {
|
|
|
|
if let Some(e) = hitboxes.iter().find_map(|(e, hitbox_aabb)| {
|
|
|
|
if let Some(e) = hitboxes
|
|
|
|
bird_aabb.intersects(hitbox_aabb).then_some(e)
|
|
|
|
.iter()
|
|
|
|
}) {
|
|
|
|
.find_map(|(e, hitbox_aabb)| bird_aabb.intersects(hitbox_aabb).then_some(e))
|
|
|
|
|
|
|
|
{
|
|
|
|
let (_, Batch(curr)) = batches.get(e).unwrap();
|
|
|
|
let (_, Batch(curr)) = batches.get(e).unwrap();
|
|
|
|
let (target_batch_id, new_batch_id) = match state.get() {
|
|
|
|
let (target_batch_id, new_batch_id) = match state.get() {
|
|
|
|
PlayerState::Alive => (curr.saturating_sub(2), curr.saturating_add(2)),
|
|
|
|
PlayerState::Alive => (curr.saturating_sub(2), curr.saturating_add(2)),
|
|
|
|
PlayerState::Rewind => (curr.saturating_add(2), curr.saturating_sub(2)),
|
|
|
|
PlayerState::Rewind => (curr.saturating_add(2), curr.saturating_sub(2)),
|
|
|
|
_ => (*curr, *curr),
|
|
|
|
_ => (*curr, *curr),
|
|
|
|
};
|
|
|
|
};
|
|
|
|
if target_batch_id == 0 || new_batch_id == 0 {
|
|
|
|
if target_batch_id > 0
|
|
|
|
// skip
|
|
|
|
&& new_batch_id > 0
|
|
|
|
} else {
|
|
|
|
&& target_batch_id != new_batch_id
|
|
|
|
if target_batch_id != new_batch_id {
|
|
|
|
&& let Some(e_old) = batches
|
|
|
|
if let Some(e_old) = batches.iter().find_map(|(e, b)| (b.0 == target_batch_id).then_some(e)) {
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
.find_map(|(e, b)| (b.0 == target_batch_id).then_some(e))
|
|
|
|
|
|
|
|
{
|
|
|
|
commands.entity(e_old).insert(Batch(new_batch_id));
|
|
|
|
commands.entity(e_old).insert(Batch(new_batch_id));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
};
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|