Cleanup some things which shouldn't be components (#2982)

# Objective

- Using `Stopwatch` and `Timer` as raw components is a footgun.

## Solution

- Stop them from being components
This commit is contained in:
Daniel McNab 2022-02-03 23:56:57 +00:00
parent 1f99363de9
commit 6f111136b9
6 changed files with 48 additions and 45 deletions

View file

@ -1,4 +1,3 @@
use bevy_ecs::{component::Component, reflect::ReflectComponent};
use bevy_reflect::Reflect;
use bevy_utils::Duration;
@ -23,8 +22,7 @@ use bevy_utils::Duration;
/// assert!(stopwatch.paused());
/// assert_eq!(stopwatch.elapsed_secs(), 0.0);
/// ```
#[derive(Component, Clone, Debug, Default, Reflect)]
#[reflect(Component)]
#[derive(Clone, Debug, Default, Reflect)]
pub struct Stopwatch {
elapsed: Duration,
paused: bool,

View file

@ -1,5 +1,4 @@
use crate::Stopwatch;
use bevy_ecs::{component::Component, reflect::ReflectComponent};
use bevy_reflect::Reflect;
use bevy_utils::Duration;
@ -10,8 +9,7 @@ use bevy_utils::Duration;
/// exceeded, and can still be reset at any given point.
///
/// Paused timers will not have elapsed time increased.
#[derive(Component, Clone, Debug, Default, Reflect)]
#[reflect(Component)]
#[derive(Clone, Debug, Default, Reflect)]
pub struct Timer {
stopwatch: Stopwatch,
duration: Duration,

View file

@ -15,6 +15,7 @@ fn main() {
.add_system(move_system)
.add_system(collision_system)
.add_system(select_system)
.insert_resource(SelectTimer(Timer::from_seconds(SHOWCASE_TIMER_SECS, true)))
.run();
}
@ -26,8 +27,7 @@ struct ContributorSelection {
idx: usize,
}
#[derive(Component)]
struct SelectTimer;
struct SelectTimer(Timer);
#[derive(Component)]
struct ContributorDisplay;
@ -120,8 +120,6 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn_bundle(OrthographicCameraBundle::new_2d());
commands.spawn_bundle(UiCameraBundle::default());
commands.spawn_bundle((SelectTimer, Timer::from_seconds(SHOWCASE_TIMER_SECS, true)));
commands
.spawn()
.insert(ContributorDisplay)
@ -157,22 +155,13 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
/// Finds the next contributor to display and selects the entity
fn select_system(
mut timer: ResMut<SelectTimer>,
mut contributor_selection: ResMut<ContributorSelection>,
mut text_query: Query<&mut Text, With<ContributorDisplay>>,
mut timer_query: Query<&mut Timer, With<SelectTimer>>,
mut query: Query<(&Contributor, &mut Sprite, &mut Transform)>,
time: Res<Time>,
) {
let mut timer_fired = false;
for mut timer in timer_query.iter_mut() {
if !timer.tick(time.delta()).just_finished() {
continue;
}
timer.reset();
timer_fired = true;
}
if !timer_fired {
if !timer.0.tick(time.delta()).just_finished() {
return;
}

View file

@ -17,8 +17,8 @@ fn main() {
.add_plugin(FrameTimeDiagnosticsPlugin::default())
.add_plugins(DefaultPlugins)
.add_startup_system(setup)
.add_system(tick_system.label("Tick"))
.add_system(move_camera_system.after("Tick"))
.add_system(print_sprite_count.label("Tick"))
.add_system(move_camera.after("Tick"))
.run()
}
@ -37,7 +37,6 @@ fn setup(mut commands: Commands, assets: Res<AssetServer>) {
commands
.spawn()
.insert_bundle(OrthographicCameraBundle::new_2d())
.insert(Timer::from_seconds(1.0, true))
.insert(Transform::from_xyz(0.0, 0.0, 1000.0));
// Builds and spawns the sprites
@ -68,19 +67,26 @@ fn setup(mut commands: Commands, assets: Res<AssetServer>) {
}
// System for rotating and translating the camera
fn move_camera_system(time: Res<Time>, mut camera_query: Query<&mut Transform, With<Camera>>) {
fn move_camera(time: Res<Time>, mut camera_query: Query<&mut Transform, With<Camera>>) {
let mut camera_transform = camera_query.single_mut();
camera_transform.rotate(Quat::from_rotation_z(time.delta_seconds() * 0.5));
*camera_transform = *camera_transform
* Transform::from_translation(Vec3::X * CAMERA_SPEED * time.delta_seconds());
}
// System for printing the number of sprites on every tick of the timer
fn tick_system(time: Res<Time>, sprites_query: Query<&Sprite>, mut timer_query: Query<&mut Timer>) {
let mut timer = timer_query.single_mut();
timer.tick(time.delta());
struct PrintingTimer(Timer);
if timer.just_finished() {
info!("Sprites: {}", sprites_query.iter().count(),);
impl Default for PrintingTimer {
fn default() -> Self {
Self(Timer::from_seconds(1.0, true))
}
}
// System for printing the number of sprites on every tick of the timer
fn print_sprite_count(time: Res<Time>, mut timer: Local<PrintingTimer>, sprites: Query<&Sprite>) {
timer.0.tick(time.delta());
if timer.0.just_finished() {
info!("Sprites: {}", sprites.iter().count(),);
}
}

View file

@ -4,18 +4,25 @@ fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_startup_system(setup)
.add_system(animate_sprite_system)
.add_system(animate_sprite)
.run();
}
fn animate_sprite_system(
#[derive(Component)]
struct AnimationTimer(Timer);
fn animate_sprite(
time: Res<Time>,
texture_atlases: Res<Assets<TextureAtlas>>,
mut query: Query<(&mut Timer, &mut TextureAtlasSprite, &Handle<TextureAtlas>)>,
mut query: Query<(
&mut AnimationTimer,
&mut TextureAtlasSprite,
&Handle<TextureAtlas>,
)>,
) {
for (mut timer, mut sprite, texture_atlas_handle) in query.iter_mut() {
timer.tick(time.delta());
if timer.finished() {
timer.0.tick(time.delta());
if timer.0.just_finished() {
let texture_atlas = texture_atlases.get(texture_atlas_handle).unwrap();
sprite.index = (sprite.index + 1) % texture_atlas.textures.len();
}
@ -37,5 +44,5 @@ fn setup(
transform: Transform::from_scale(Vec3::splat(6.0)),
..Default::default()
})
.insert(Timer::from_seconds(0.1, true));
.insert(AnimationTimer(Timer::from_seconds(0.1, true)));
}

View file

@ -4,12 +4,15 @@ fn main() {
App::new()
.add_plugins(DefaultPlugins)
.init_resource::<Countdown>()
.add_startup_system(setup_system)
.add_system(countdown_system)
.add_system(timer_system)
.add_startup_system(setup)
.add_system(countdown)
.add_system(print_when_completed)
.run();
}
#[derive(Component)]
pub struct PrintOnCompletionTimer(Timer);
pub struct Countdown {
pub percent_trigger: Timer,
pub main_timer: Timer,
@ -30,16 +33,18 @@ impl Default for Countdown {
}
}
fn setup_system(mut commands: Commands) {
fn setup(mut commands: Commands) {
// Add an entity to the world with a timer
commands.spawn().insert(Timer::from_seconds(5.0, false));
commands
.spawn()
.insert(PrintOnCompletionTimer(Timer::from_seconds(5.0, false)));
}
/// This system ticks all the `Timer` components on entities within the scene
/// using bevy's `Time` resource to get the delta between each update.
fn timer_system(time: Res<Time>, mut query: Query<&mut Timer>) {
fn print_when_completed(time: Res<Time>, mut query: Query<&mut PrintOnCompletionTimer>) {
for mut timer in query.iter_mut() {
if timer.tick(time.delta()).just_finished() {
if timer.0.tick(time.delta()).just_finished() {
info!("Entity timer just finished")
}
}
@ -47,7 +52,7 @@ fn timer_system(time: Res<Time>, mut query: Query<&mut Timer>) {
/// This system controls ticking the timer within the countdown resource and
/// handling its state.
fn countdown_system(time: Res<Time>, mut countdown: ResMut<Countdown>) {
fn countdown(time: Res<Time>, mut countdown: ResMut<Countdown>) {
countdown.main_timer.tick(time.delta());
// The API encourages this kind of timer state checking (if you're only checking for one value)