Multirious / bevy_tween

Flexible tweening plugin library for Bevy.
Apache License 2.0
87 stars 2 forks source link

Find out when a tweener is done repeating #14

Closed musjj closed 4 months ago

musjj commented 4 months ago

It looks like that when you use something like Repeat::times(8), SpanTweenerEnded is reported every time a repetition is completed. Is there a way to find out when the tweener is actually done?

musjj commented 4 months ago

Never mind, you can do that pretty easily:

if let Some(repeat) = ended.with_repeat {
    if repeat.exhausted() {
        // do something
    }
}
musjj commented 4 months ago

Hmmm, I'm getting a weird behavior here. Let's say I have Repeat::times(8) and I have this code:

if let Some(repeat) = ended.with_repeat {
    println!("repeat");
    if repeat.exhausted() {
        println!("done");
    }
}

This is what I see in the console:

repeat
repeat
repeat
repeat
repeat
repeat
repeat
repeat
done
repeat
done

What's going on here?

Multirious commented 4 months ago

Is it possibly because of how events are buffered by 1 frame? If repeat.exhausted() is fired 2 times per entity then surely one of my example must have caught it. (The example click use the event to remove an entity after completion. It would've crashed if the entity is despawned 2 times) I will do further testing for Repeat::times (I didn't bother testing them 😅).

Site note: You can use the is_completed method on the event.

Multirious commented 4 months ago

Here the test result came back

use bevy::prelude::*;
use bevy_tween::prelude::*;

fn main() {
    App::new()
        .add_plugins((MinimalPlugins, DefaultTweenPlugins))
        .add_systems(Startup, setup)
        .add_systems(Update, check_event)
        .run();
}

fn setup(mut commands: Commands) {
    commands.spawn(SpanTweenerBundle::new(Duration::from_secs(2)).with_repeat(Repeat::times(3)));
}

fn check_event(mut event: EventReader<SpanTweenerEnded>) {
    for ended in event.read() {
        if let Some(repeat) = ended.with_repeat {
            if repeat.exhausted() {
                println!("done");
            } else {
                println!("repeated");
            }
        }
    }
}

output:

repeated
repeated
repeated
done

seems good to me

musjj commented 4 months ago

This isn't the same bug, but I think the problem was related with RepeatStyle::PingPong. This only prints done once (with the latest main):

use bevy::prelude::*;
use bevy_tween::prelude::*;

fn main() {
    App::new()
        .add_plugins((MinimalPlugins, DefaultTweenPlugins))
        .add_systems(Startup, setup)
        .add_systems(Update, check_event)
        .run();
}

fn setup(mut commands: Commands) {
    commands.spawn(
        SpanTweenerBundle::new(Duration::from_secs_f32(0.5))
            .with_repeat(Repeat::times(8))
            .with_repeat_style(RepeatStyle::PingPong),
    );
}

fn check_event(mut event: EventReader<SpanTweenerEnded>) {
    for ended in event.read() {
        if ended.is_completed() {
            println!("done");
        } else {
            println!("repeated");
        }
    }
}
Multirious commented 4 months ago

Apparently the bug is introduced by bd6841c 🙈. Now fixed by eac77aa

musjj commented 4 months ago

Thanks, it works fine now! No idea what was causing the original problem, but I can't reproduce it anymore.