Skip to content
Snippets Groups Projects
  • Jerome Humbert's avatar
    Upgrade to Bevy 0.8 · 0b69cdb6
    Jerome Humbert authored
    Upgrade to the latest released version 0.8.0 of Bevy.
    
    Add a new `bevy_asset` feature to enable animation of Bevy assets
    (types implementing the `Asset` trait). Bevy 0.8 does not contain
    `bevy_asset` in its defaul features, so this new feature reflects that
    new possibility to build Bevy and í½ƒ Bevy Tweening without support
    for the `bevy_asset` crate. The new feature is enabled by default for
    discoverability and to prevent a behavior breaking change.
    0b69cdb6
sequence.rs 6.62 KiB
use bevy::prelude::*;
use bevy_tweening::{lens::*, *};
use std::time::Duration;

fn main() {
    App::default()
        .insert_resource(WindowDescriptor {
            title: "Sequence".to_string(),
            width: 600.,
            height: 600.,
            present_mode: bevy::window::PresentMode::Fifo, // vsync
            ..default()
        })
        .add_plugins(DefaultPlugins)
        .add_plugin(TweeningPlugin)
        .add_startup_system(setup)
        .add_system(update_text)
        .run();
}

#[derive(Component)]
struct RedProgress;

#[derive(Component)]
struct BlueProgress;

#[derive(Component)]
struct RedSprite;

#[derive(Component)]
struct BlueSprite;

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
    commands.spawn_bundle(Camera2dBundle::default());

    let font = asset_server.load("fonts/FiraMono-Regular.ttf");
    let text_style_red = TextStyle {
        font: font.clone(),
        font_size: 50.0,
        color: Color::RED,
    };
    let text_style_blue = TextStyle {
        font,
        font_size: 50.0,
        color: Color::BLUE,
    };

    let text_alignment = TextAlignment {
        vertical: VerticalAlign::Center,
        horizontal: HorizontalAlign::Center,
    };

    // Text with the index of the active tween in the sequence
    commands
        .spawn_bundle(Text2dBundle {
            text: Text {
                sections: vec![
                    TextSection {
                        value: "progress: ".to_owned(),
                        style: text_style_red.clone(),
                    },
                    TextSection {
                        value: "0%".to_owned(),
                        style: text_style_red,
                    },
                ],
                alignment: text_alignment,
            },
            transform: Transform::from_translation(Vec3::new(0., 40., 0.)),
            ..default()
        })
        .insert(RedProgress);

    // Text with progress of the active tween in the sequence
    commands
        .spawn_bundle(Text2dBundle {
            text: Text {
                sections: vec![
                    TextSection {
                        value: "progress: ".to_owned(),
                        style: text_style_blue.clone(),
                    },
                    TextSection {
                        value: "0%".to_owned(),
                        style: text_style_blue,
                    },
                ],
                alignment: text_alignment,
            },
            transform: Transform::from_translation(Vec3::new(0., -40., 0.)),
            ..default()
        })
        .insert(BlueProgress);

    let size = 25.;

    let margin = 40.;
    let screen_x = 600.;
    let screen_y = 600.;
    let center = Vec3::new(screen_x / 2., screen_y / 2., 0.);

    // Run around the window from corner to corner
    let dests = &[
        Vec3::new(margin, margin, 0.),
        Vec3::new(screen_x - margin, margin, 0.),
        Vec3::new(screen_x - margin, screen_y - margin, 0.),
        Vec3::new(margin, screen_y - margin, 0.),
        Vec3::new(margin, margin, 0.),
    ];
    // Build a sequence from an iterator over a Tweenable (here, a Tween<Transform>)
    let seq = Sequence::new(dests.windows(2).enumerate().map(|(index, pair)| {
        Tween::new(
            EaseFunction::QuadraticInOut,
            TweeningType::Once,
            Duration::from_secs(1),
            TransformPositionLens {
                start: pair[0] - center,
                end: pair[1] - center,
            },
        )
        // Get an event after each segment
        .with_completed_event(index as u64)
    }));

    commands
        .spawn_bundle(SpriteBundle {
            sprite: Sprite {
                color: Color::RED,
                custom_size: Some(Vec2::new(size, size)),
                ..default()
            },
            ..default()
        })
        .insert(RedSprite)
        .insert(Animator::new(seq));

    // First move from left to right, then rotate around self 180 degrees while
    // scaling size at the same time.
    let tween_move = Tween::new(
        EaseFunction::QuadraticInOut,
        TweeningType::Once,
        Duration::from_secs(1),
        TransformPositionLens {
            start: Vec3::new(-200., 100., 0.),
            end: Vec3::new(200., 100., 0.),
        },
    )
    .with_completed_event(99); // Get an event once move completed
    let tween_rotate = Tween::new(
        EaseFunction::QuadraticInOut,
        TweeningType::Once,
        Duration::from_secs(1),
        TransformRotationLens {
            start: Quat::IDENTITY,
            end: Quat::from_rotation_z(180_f32.to_radians()),
        },
    );
    let tween_scale = Tween::new(
        EaseFunction::QuadraticInOut,
        TweeningType::Once,
        Duration::from_secs(1),
        TransformScaleLens {
            start: Vec3::ONE,
            end: Vec3::splat(2.0),
        },
    );
    // Build parallel tracks executing two tweens at the same time: rotate and
    // scale.
    let tracks = Tracks::new([tween_rotate, tween_scale]);
    // Build a sequence from an heterogeneous list of tweenables by casting them
    // manually to a BoxedTweenable: first move, then { rotate + scale }.
    let seq2 = Sequence::new([Box::new(tween_move) as BoxedTweenable<_>, tracks.into()]);

    commands
        .spawn_bundle(SpriteBundle {
            sprite: Sprite {
                color: Color::BLUE,
                custom_size: Some(Vec2::new(size * 3., size)),
                ..default()
            },
            ..Default::default()
        })
        .insert(BlueSprite)
        .insert(Animator::new(seq2));
}

fn update_text(
    mut query_text_red: Query<&mut Text, (With<RedProgress>, Without<BlueProgress>)>,
    mut query_text_blue: Query<&mut Text, (With<BlueProgress>, Without<RedProgress>)>,
    query_anim_red: Query<&Animator<Transform>, With<RedSprite>>,
    query_anim_blue: Query<&Animator<Transform>, With<BlueSprite>>,
    mut query_event: EventReader<TweenCompleted>,
) {
    let anim_red = query_anim_red.single();
    let tween_red = anim_red.tweenable().unwrap();
    let progress_red = tween_red.progress();

    let anim_blue = query_anim_blue.single();
    let tween_blue = anim_blue.tweenable().unwrap();
    let progress_blue = tween_blue.progress();

    let mut red_text = query_text_red.single_mut();
    red_text.sections[1].value = format!("{:5.1}%", progress_red * 100.);

    let mut blue_text = query_text_blue.single_mut();
    blue_text.sections[1].value = format!("{:5.1}%", progress_blue * 100.);

    for ev in query_event.iter() {
        println!(
            "Event: TweenCompleted entity={:?} user_data={}",
            ev.entity, ev.user_data
        );
    }
}