use std::time::Duration;
use bevy::{prelude::*, utils::Instant};
use bevy_asset_loader::asset_collection::AssetCollection;
use keyframe::functions::*;
use crate::AppState;
const FADE_IN_TIME: f32 = 2.5;
const ZOOM_OUT_TIME: f32 = 2.0;
const FULL_FADE_FINISHED: f32 = 4.0;
const FADE_OUT_TIME: f32 = 1.0;
const QUIT_TIME: f32 = 0.5;
const LOGO_FINISHED_SCALE: f32 = 0.2;
pub struct LogoPlugin;
#[derive(AssetCollection, Resource)]
pub struct LogoAssets {
#[asset(path = "logo.ktx2")]
logo_texture: Handle<Image>,
}
#[derive(Resource)]
struct LogoData {
logo_entity: Entity,
camera_entity: Entity,
}
impl Plugin for LogoPlugin {
fn build(&self, app: &mut App) {
app.add_systems(OnEnter(AppState::Logo), load_logo)
.add_systems(Update, fade_in_logo.run_if(in_state(AppState::Logo)))
.add_systems(OnExit(AppState::Logo), cleanup_logo);
}
}
#[derive(Component)]
struct LogoTimer(Instant, Instant);
impl LogoTimer {
fn elapsed_secs(&self) -> f32 {
self.0.elapsed().as_secs_f32()
}
fn finished(&self) -> bool {
Instant::now() > self.1
}
}
fn load_logo(mut commands: Commands, assets: Res<LogoAssets>) {
let now = Instant::now();
commands.insert_resource(ClearColor(Color::BLACK));
let sprite_entity = commands
.spawn((
SpriteBundle {
texture: assets.logo_texture.clone(),
sprite: Sprite {
color: Color::rgba(1.0, 1.0, 1.0, 0.0),
..Default::default()
},
transform: Transform::from_scale(Vec3::ONE),
..Default::default()
},
LogoTimer(
now,
now + Duration::from_secs_f32(QUIT_TIME + FULL_FADE_FINISHED + FADE_OUT_TIME),
),
))
.id();
let camera_entity = commands.spawn(Camera2dBundle::default()).id();
commands.insert_resource(LogoData {
logo_entity: sprite_entity,
camera_entity,
});
}
fn fade_in_logo(
mut query: Query<(&mut Sprite, &mut Transform, &LogoTimer)>,
mut next_state: ResMut<NextState<AppState>>,
keyboard_input: Res<ButtonInput<KeyCode>>,
) {
let (mut sprite, mut transform, timer) = query.single_mut();
let elapsed = timer.elapsed_secs();
if timer.finished() || keyboard_input.get_pressed().len() > 0 {
next_state.set(AppState::LoadingMenu);
} else if elapsed > FULL_FADE_FINISHED {
sprite.color.set_a(keyframe::ease_with_scaled_time(
EaseInCubic,
FULL_FADE_FINISHED,
0.0,
elapsed,
FADE_OUT_TIME + FULL_FADE_FINISHED,
));
} else {
sprite.color.set_a(keyframe::ease_with_scaled_time(
Linear,
0.0,
1.0,
elapsed,
FADE_IN_TIME,
));
transform.scale = Vec3::splat(keyframe::ease_with_scaled_time(
EaseOutQuint,
2.0,
LOGO_FINISHED_SCALE,
elapsed,
ZOOM_OUT_TIME,
));
}
}
fn cleanup_logo(mut commands: Commands, logo_data: Res<LogoData>) {
commands.entity(logo_data.logo_entity).despawn_recursive();
commands.entity(logo_data.camera_entity).despawn_recursive();
commands.remove_resource::<LogoData>();
commands.remove_resource::<LogoAssets>();
}