-
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
);
}
}