Skip to content
This repository has been archived by the owner on Oct 24, 2024. It is now read-only.

Commit

Permalink
Start elevator close animation when scene loaded (#112)
Browse files Browse the repository at this point in the history
  • Loading branch information
porkbrain authored Mar 29, 2024
1 parent fcda69e commit 62a5c2f
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 31 deletions.
2 changes: 1 addition & 1 deletion common/visuals/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl bevy::app::Plugin for Plugin {
.register_type::<AtlasAnimationTimer>()
.register_type::<TranslationInterpolation>()
.register_type::<ColorInterpolation>()
.register_type::<BeginAtlasAnimationAtRandom>()
.register_type::<BeginAtlasAnimation>()
.register_type::<Flicker>();

app.add_plugins(FrameTimeDiagnosticsPlugin)
Expand Down
45 changes: 36 additions & 9 deletions common/visuals/src/systems.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use common_ext::ColorExt;

use crate::{
AtlasAnimation, AtlasAnimationEnd, AtlasAnimationTimer,
BeginAtlasAnimationAtRandom, BeginInterpolationEvent, ColorInterpolation,
Flicker, OnInterpolationFinished, TranslationInterpolation,
UiStyleHeightInterpolation,
BeginAtlasAnimation, BeginAtlasAnimationCond, BeginInterpolationEvent,
ColorInterpolation, Flicker, OnInterpolationFinished,
TranslationInterpolation, UiStyleHeightInterpolation,
};

/// Advances the animation by one frame.
Expand Down Expand Up @@ -43,10 +43,10 @@ pub fn advance_atlas_animation(
AtlasAnimationEnd::RemoveTimer => {
cmd.entity(entity).remove::<AtlasAnimationTimer>();
}
AtlasAnimationEnd::Custom { with_fn: Some(fun) } => {
AtlasAnimationEnd::Custom { with: Some(fun) } => {
fun(entity, &mut atlas, &mut visibility, &mut cmd);
}
AtlasAnimationEnd::Custom { with_fn: None } => {
AtlasAnimationEnd::Custom { with: None } => {
// nothing happens
}
AtlasAnimationEnd::Loop => {
Expand All @@ -73,7 +73,7 @@ pub fn begin_atlas_animation_at_random(
time: Res<Time>,

mut query: Query<
(Entity, &mut BeginAtlasAnimationAtRandom, &mut Visibility),
(Entity, &mut BeginAtlasAnimation, &mut Visibility),
Without<AtlasAnimationTimer>,
>,
) {
Expand All @@ -88,9 +88,36 @@ pub fn begin_atlas_animation_at_random(
}
settings.with_min_delay = None;

if rand::random::<f32>()
< settings.chance_per_second * time.delta_seconds()
{
let should_start = match &settings.cond {
BeginAtlasAnimationCond::Immediately
| BeginAtlasAnimationCond::Custom { with: None } => true,
BeginAtlasAnimationCond::AtRandom(chance_per_second) => {
rand::random::<f32>() < chance_per_second * time.delta_seconds()
}
BeginAtlasAnimationCond::Custom { with: Some(fun) } => {
let frame_time = settings.frame_time;
let fun = fun.clone();
cmd.add(move |w: &mut World| {
if !fun(w, entity) {
return;
}

if let Some(mut entity) = w.get_entity_mut(entity) {
entity.remove::<BeginAtlasAnimation>();
entity.insert(AtlasAnimationTimer::new(
frame_time,
TimerMode::Repeating,
));
}
});

// the condition has to be evaluated later bcs we don't have
// access to the world here
false
}
};

if should_start {
*visibility = Visibility::Visible;
cmd.entity(entity).insert(AtlasAnimationTimer::new(
settings.frame_time,
Expand Down
54 changes: 47 additions & 7 deletions common/visuals/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub enum AtlasAnimationEnd {
/// action because otherwise the animation will keep looping on the
/// last frame.
#[reflect(ignore)]
with_fn: Option<CustomAtlasAnimationEndFn>,
with: Option<CustomAtlasAnimationEndFn>,
},
}

Expand All @@ -62,18 +62,39 @@ pub struct AtlasAnimationTimer(pub(crate) Timer);

/// Allows to start an animation at random.
#[derive(Component, Default, Reflect)]
pub struct BeginAtlasAnimationAtRandom {
/// We roll a dice every delta seconds.
/// This scales that delta.
/// Between 0 and 1.
pub chance_per_second: f32,
pub struct BeginAtlasAnimation {
/// The condition to start the animation.
pub cond: BeginAtlasAnimationCond,
/// Once the animation is started, how long should each frame be shown?
pub frame_time: Duration,
/// If present, the animation cannot be started before this time has
/// passed.
pub with_min_delay: Option<(Duration, Stopwatch)>,
}

/// Various conditions to start an animation.
#[derive(Default, Reflect)]
pub enum BeginAtlasAnimationCond {
/// Makes sense only when [`BeginAtlasAnimationAtRandom::with_min_delay`]
/// is set.
/// Otherwise, just insert the [`AtlasAnimationTimer`] directly.
#[default]
Immediately,
/// We roll a dice every delta seconds.
/// This scales that delta.
/// Between 0 and 1.
AtRandom(f32),
/// Since the system that runs the conds doesn't have access to the world,
/// this is scheduled as a command.
Custom {
/// Option to be able to implement reflect.
///
/// If returns true, the animation will be started.
#[reflect(ignore)]
with: Option<fn(&World, Entity) -> bool>,
},
}

/// Shows entity at random for a given duration.
/// Then hides it again.
#[derive(Component, Reflect)]
Expand Down Expand Up @@ -126,7 +147,7 @@ pub(crate) enum OnInterpolationFinished {
impl AtlasAnimationEnd {
/// Runs this fn when the last frame of the animation is reached.
pub fn run(fun: CustomAtlasAnimationEndFn) -> Self {
Self::Custom { with_fn: Some(fun) }
Self::Custom { with: Some(fun) }
}
}

Expand Down Expand Up @@ -459,3 +480,22 @@ impl AtlasAnimation {
}
}
}

impl BeginAtlasAnimation {
/// Run the given function and when it returns true, that's when we can
/// start the animation.
///
/// Note that the function is called every frame and added as a command
/// that's evaluated single-threaded.
pub fn run(
fun: fn(&World, Entity) -> bool,
frame_time: Duration,
with_min_delay: Option<Duration>,
) -> Self {
Self {
cond: BeginAtlasAnimationCond::Custom { with: Some(fun) },
frame_time,
with_min_delay: with_min_delay.map(|d| (d, Stopwatch::new())),
}
}
}
24 changes: 15 additions & 9 deletions main_game_lib/src/cutscene/enter_an_elevator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use common_story::{
};
use common_visuals::{
AtlasAnimation, AtlasAnimationEnd, AtlasAnimationTimer,
BeginAtlasAnimationAtRandom, EASE_IN_OUT,
BeginAtlasAnimation, EASE_IN_OUT,
};
use top_down::layout::LAYOUT;

Expand Down Expand Up @@ -300,13 +300,19 @@ pub fn start_with_open_elevator_and_close_it(
trace!("Setting elevator to last frame");
// set the last frame as the current index
elevator.get_mut::<TextureAtlas>().unwrap().index = last_frame;
// start the animation asap
elevator.insert(BeginAtlasAnimationAtRandom {
chance_per_second: 1.0,
frame_time: from_millis(150),
// TODO: https://github.com/porkbrain/dont-count-the-sheep/issues/111
with_min_delay: Some((from_millis(1750), Stopwatch::new())),
});
// start the animation as soon as we are in running state
fn is_in_running_global_state(w: &World, _: Entity) -> bool {
// SAFETY: GlobalGameState always present
let current_state = w.get_resource::<State<GlobalGameState>>().unwrap();
current_state
.state_semantics()
.is_some_and(|sem| sem.running == **current_state)
}
elevator.insert(common_visuals::BeginAtlasAnimation::run(
is_in_running_global_state,
from_millis(150),
Some(from_millis(1500)),
));

let mut a = elevator.get_mut::<AtlasAnimation>().unwrap();
// animation runs in reverse
Expand All @@ -324,7 +330,7 @@ pub fn start_with_open_elevator_and_close_it(
trace!("Setting elevator animation back to normal");
// no anim running
e.remove::<AtlasAnimationTimer>();
e.remove::<BeginAtlasAnimationAtRandom>();
e.remove::<BeginAtlasAnimation>();

let mut a = e.get_mut::<AtlasAnimation>().unwrap();
// back to normal
Expand Down
6 changes: 4 additions & 2 deletions scenes/meditation/src/background.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,10 @@ fn spawn_shooting_star(
cmd.spawn((
BackgroundEntity,
RenderLayers::layer(render_layer::OBJ),
BeginAtlasAnimationAtRandom {
chance_per_second: SHOOTING_STAR_CHANCE_PER_SECOND,
BeginAtlasAnimation {
cond: common_visuals::BeginAtlasAnimationCond::AtRandom(
SHOOTING_STAR_CHANCE_PER_SECOND,
),
frame_time: SHOOTING_STAR_FRAME_TIME,
..default()
},
Expand Down
6 changes: 4 additions & 2 deletions scenes/meditation/src/polpos/effects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,10 @@ pub(crate) mod black_hole {
on_last_frame,
..default()
},
BeginAtlasAnimationAtRandom {
chance_per_second: BLACK_HOLE_DESPAWN_CHANCE_PER_SECOND,
BeginAtlasAnimation {
cond: common_visuals::BeginAtlasAnimationCond::AtRandom(
BLACK_HOLE_DESPAWN_CHANCE_PER_SECOND,
),
frame_time: BLACK_HOLE_FRAME_TIME,
with_min_delay: Some((BLACK_HOLE_MIN_LIFE, Stopwatch::new())),
},
Expand Down
2 changes: 1 addition & 1 deletion scenes/meditation/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub(crate) use common_physics::{
};
pub(crate) use common_visuals::{
AtlasAnimation, AtlasAnimationEnd, AtlasAnimationTimer,
BeginAtlasAnimationAtRandom, Flicker,
BeginAtlasAnimation, Flicker,
};
pub(crate) use main_game_lib::prelude::*;

Expand Down

0 comments on commit 62a5c2f

Please sign in to comment.