Skip to content
Snippets Groups Projects
Verified Commit ed708608 authored by Louis's avatar Louis :fire:
Browse files

Upgrade to Bevy 0.10

parent 38082690
No related branches found
No related tags found
No related merge requests found
......@@ -25,10 +25,10 @@ bevy_text = ["bevy/bevy_text", "bevy/bevy_render"]
[dependencies]
interpolation = "0.2"
bevy = { version = "0.9", default-features = false }
bevy = { version = "0.10", default-features = false }
[dev-dependencies]
bevy-inspector-egui = "0.14"
bevy-inspector-egui = "0.18.0"
[[example]]
name = "menu"
......@@ -61,7 +61,7 @@ required-features = [ "bevy_text", "bevy/bevy_winit" ]
[[example]]
name = "sequence"
required-features = [ "bevy/bevy_winit" ]
[workspace]
resolver = "2"
members = [".", "benchmarks/"]
#
#[workspace]
#resolver = "2"
#members = [".", "benchmarks/"]
......@@ -38,32 +38,34 @@ use crate::{tweenable::ComponentTarget, Animator, AnimatorState, TweenCompleted}
pub struct TweeningPlugin;
impl Plugin for TweeningPlugin {
fn build(&self, app: &mut App) {
app.add_event::<TweenCompleted>().add_system(
component_animator_system::<Transform>.label(AnimationSystem::AnimationUpdate),
);
#[cfg(feature = "bevy_ui")]
app.add_system(component_animator_system::<Style>.label(AnimationSystem::AnimationUpdate));
#[cfg(feature = "bevy_sprite")]
app.add_system(component_animator_system::<Sprite>.label(AnimationSystem::AnimationUpdate));
#[cfg(all(feature = "bevy_sprite", feature = "bevy_asset"))]
app.add_system(
asset_animator_system::<ColorMaterial>.label(AnimationSystem::AnimationUpdate),
);
#[cfg(feature = "bevy_text")]
app.add_system(component_animator_system::<Text>.label(AnimationSystem::AnimationUpdate));
}
fn build(&self, app: &mut App) {
app.add_event::<TweenCompleted>().add_system(
component_animator_system::<Transform>.in_set(AnimationSystem::AnimationUpdate),
);
#[cfg(feature = "bevy_ui")]
app.add_system(component_animator_system::<Style>.in_set(AnimationSystem::AnimationUpdate));
#[cfg(feature = "bevy_sprite")]
app.add_system(
component_animator_system::<Sprite>.in_set(AnimationSystem::AnimationUpdate),
);
#[cfg(all(feature = "bevy_sprite", feature = "bevy_asset"))]
app.add_system(
asset_animator_system::<ColorMaterial>.in_set(AnimationSystem::AnimationUpdate),
);
#[cfg(feature = "bevy_text")]
app.add_system(component_animator_system::<Text>.in_set(AnimationSystem::AnimationUpdate));
}
}
/// Label enum for the systems relating to animations
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, SystemLabel)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, SystemSet)]
pub enum AnimationSystem {
/// Ticks animations
AnimationUpdate,
/// Ticks animations
AnimationUpdate,
}
/// Animator system for components.
......@@ -71,23 +73,23 @@ pub enum AnimationSystem {
/// This system extracts all components of type `T` with an `Animator<T>`
/// attached to the same entity, and tick the animator to animate the component.
pub fn component_animator_system<T: Component>(
time: Res<Time>,
mut query: Query<(Entity, &mut T, &mut Animator<T>)>,
events: ResMut<Events<TweenCompleted>>,
time: Res<Time>,
mut query: Query<(Entity, &mut T, &mut Animator<T>)>,
events: ResMut<Events<TweenCompleted>>,
) {
let mut events: Mut<Events<TweenCompleted>> = events.into();
for (entity, target, mut animator) in query.iter_mut() {
if animator.state != AnimatorState::Paused {
let speed = animator.speed();
let mut target = ComponentTarget::new(target);
animator.tweenable_mut().tick(
time.delta().mul_f32(speed),
&mut target,
entity,
&mut events,
);
}
}
let mut events: Mut<Events<TweenCompleted>> = events.into();
for (entity, target, mut animator) in query.iter_mut() {
if animator.state != AnimatorState::Paused {
let speed = animator.speed();
let mut target = ComponentTarget::new(target);
animator.tweenable_mut().tick(
time.delta().mul_f32(speed),
&mut target,
entity,
&mut events,
);
}
}
}
/// Animator system for assets.
......@@ -98,166 +100,166 @@ pub fn component_animator_system<T: Component>(
/// This requires the `bevy_asset` feature (enabled by default).
#[cfg(feature = "bevy_asset")]
pub fn asset_animator_system<T: Asset>(
time: Res<Time>,
assets: ResMut<Assets<T>>,
mut query: Query<(Entity, &mut AssetAnimator<T>)>,
events: ResMut<Events<TweenCompleted>>,
time: Res<Time>,
assets: ResMut<Assets<T>>,
mut query: Query<(Entity, &mut AssetAnimator<T>)>,
events: ResMut<Events<TweenCompleted>>,
) {
let mut events: Mut<Events<TweenCompleted>> = events.into();
let mut target = AssetTarget::new(assets);
for (entity, mut animator) in query.iter_mut() {
if animator.state != AnimatorState::Paused {
target.handle = animator.handle().clone();
if !target.is_valid() {
continue;
}
let speed = animator.speed();
animator.tweenable_mut().tick(
time.delta().mul_f32(speed),
&mut target,
entity,
&mut events,
);
}
}
let mut events: Mut<Events<TweenCompleted>> = events.into();
let mut target = AssetTarget::new(assets);
for (entity, mut animator) in query.iter_mut() {
if animator.state != AnimatorState::Paused {
target.handle = animator.handle().clone();
if !target.is_valid() {
continue;
}
let speed = animator.speed();
animator.tweenable_mut().tick(
time.delta().mul_f32(speed),
&mut target,
entity,
&mut events,
);
}
}
}
#[cfg(test)]
mod tests {
use bevy::prelude::{Events, IntoSystem, System, Transform, World};
use crate::{lens::TransformPositionLens, *};
/// A simple isolated test environment with a [`World`] and a single
/// [`Entity`] in it.
struct TestEnv {
world: World,
entity: Entity,
}
impl TestEnv {
/// Create a new test environment containing a single entity with a
/// [`Transform`], and add the given animator on that same entity.
pub fn new<T: Component>(animator: T) -> Self {
let mut world = World::new();
world.init_resource::<Events<TweenCompleted>>();
let mut time = Time::default();
time.update();
world.insert_resource(time);
let entity = world.spawn((Transform::default(), animator)).id();
Self { world, entity }
}
/// Get the test world.
pub fn world_mut(&mut self) -> &mut World {
&mut self.world
}
/// Tick the test environment, updating the simulation time and ticking
/// the given system.
pub fn tick(&mut self, duration: Duration, system: &mut dyn System<In = (), Out = ()>) {
// Simulate time passing by updating the simulation time resource
{
let mut time = self.world.resource_mut::<Time>();
let last_update = time.last_update().unwrap();
time.update_with_instant(last_update + duration);
}
// Reset world-related change detection
self.world.clear_trackers();
assert!(!self.transform().is_changed());
// Tick system
system.run((), &mut self.world);
// Update events after system ticked, in case system emitted some events
let mut events = self.world.resource_mut::<Events<TweenCompleted>>();
events.update();
}
/// Get the animator for the transform.
pub fn animator(&self) -> &Animator<Transform> {
self.world
.entity(self.entity)
.get::<Animator<Transform>>()
.unwrap()
}
/// Get the transform component.
pub fn transform(&mut self) -> Mut<Transform> {
self.world.get_mut::<Transform>(self.entity).unwrap()
}
/// Get the emitted event count since last tick.
pub fn event_count(&self) -> usize {
let events = self.world.resource::<Events<TweenCompleted>>();
events.get_reader().len(events)
}
}
#[test]
fn change_detect_component() {
let tween = Tween::new(
EaseMethod::Linear,
Duration::from_secs(1),
TransformPositionLens {
start: Vec3::ZERO,
end: Vec3::ONE,
},
)
.with_completed_event(0);
let mut env = TestEnv::new(Animator::new(tween));
// After being inserted, components are always considered changed
let transform = env.transform();
assert!(transform.is_changed());
//fn nit() {}
//let mut system = IntoSystem::into_system(nit);
let mut system = IntoSystem::into_system(component_animator_system::<Transform>);
system.initialize(env.world_mut());
env.tick(Duration::ZERO, &mut system);
let animator = env.animator();
assert_eq!(animator.state, AnimatorState::Playing);
assert_eq!(animator.tweenable().times_completed(), 0);
let transform = env.transform();
assert!(transform.is_changed());
assert!(transform.translation.abs_diff_eq(Vec3::ZERO, 1e-5));
env.tick(Duration::from_millis(500), &mut system);
assert_eq!(env.event_count(), 0);
let animator = env.animator();
assert_eq!(animator.state, AnimatorState::Playing);
assert_eq!(animator.tweenable().times_completed(), 0);
let transform = env.transform();
assert!(transform.is_changed());
assert!(transform.translation.abs_diff_eq(Vec3::splat(0.5), 1e-5));
env.tick(Duration::from_millis(500), &mut system);
assert_eq!(env.event_count(), 1);
let animator = env.animator();
assert_eq!(animator.state, AnimatorState::Playing);
assert_eq!(animator.tweenable().times_completed(), 1);
let transform = env.transform();
assert!(transform.is_changed());
assert!(transform.translation.abs_diff_eq(Vec3::ONE, 1e-5));
env.tick(Duration::from_millis(100), &mut system);
assert_eq!(env.event_count(), 0);
let animator = env.animator();
assert_eq!(animator.state, AnimatorState::Playing);
assert_eq!(animator.tweenable().times_completed(), 1);
let transform = env.transform();
assert!(!transform.is_changed());
assert!(transform.translation.abs_diff_eq(Vec3::ONE, 1e-5));
}
use bevy::prelude::{Events, IntoSystem, System, Transform, World};
use crate::{lens::TransformPositionLens, *};
/// A simple isolated test environment with a [`World`] and a single
/// [`Entity`] in it.
struct TestEnv {
world: World,
entity: Entity,
}
impl TestEnv {
/// Create a new test environment containing a single entity with a
/// [`Transform`], and add the given animator on that same entity.
pub fn new<T: Component>(animator: T) -> Self {
let mut world = World::new();
world.init_resource::<Events<TweenCompleted>>();
let mut time = Time::default();
time.update();
world.insert_resource(time);
let entity = world.spawn((Transform::default(), animator)).id();
Self { world, entity }
}
/// Get the test world.
pub fn world_mut(&mut self) -> &mut World {
&mut self.world
}
/// Tick the test environment, updating the simulation time and ticking
/// the given system.
pub fn tick(&mut self, duration: Duration, system: &mut dyn System<In = (), Out = ()>) {
// Simulate time passing by updating the simulation time resource
{
let mut time = self.world.resource_mut::<Time>();
let last_update = time.last_update().unwrap();
time.update_with_instant(last_update + duration);
}
// Reset world-related change detection
self.world.clear_trackers();
assert!(!self.transform().is_changed());
// Tick system
system.run((), &mut self.world);
// Update events after system ticked, in case system emitted some events
let mut events = self.world.resource_mut::<Events<TweenCompleted>>();
events.update();
}
/// Get the animator for the transform.
pub fn animator(&self) -> &Animator<Transform> {
self.world
.entity(self.entity)
.get::<Animator<Transform>>()
.unwrap()
}
/// Get the transform component.
pub fn transform(&mut self) -> Mut<Transform> {
self.world.get_mut::<Transform>(self.entity).unwrap()
}
/// Get the emitted event count since last tick.
pub fn event_count(&self) -> usize {
let events = self.world.resource::<Events<TweenCompleted>>();
events.get_reader().len(events)
}
}
#[test]
fn change_detect_component() {
let tween = Tween::new(
EaseMethod::Linear,
Duration::from_secs(1),
TransformPositionLens {
start: Vec3::ZERO,
end: Vec3::ONE,
},
)
.with_completed_event(0);
let mut env = TestEnv::new(Animator::new(tween));
// After being inserted, components are always considered changed
let transform = env.transform();
assert!(transform.is_changed());
//fn nit() {}
//let mut system = IntoSystem::into_system(nit);
let mut system = IntoSystem::into_system(component_animator_system::<Transform>);
system.initialize(env.world_mut());
env.tick(Duration::ZERO, &mut system);
let animator = env.animator();
assert_eq!(animator.state, AnimatorState::Playing);
assert_eq!(animator.tweenable().times_completed(), 0);
let transform = env.transform();
assert!(transform.is_changed());
assert!(transform.translation.abs_diff_eq(Vec3::ZERO, 1e-5));
env.tick(Duration::from_millis(500), &mut system);
assert_eq!(env.event_count(), 0);
let animator = env.animator();
assert_eq!(animator.state, AnimatorState::Playing);
assert_eq!(animator.tweenable().times_completed(), 0);
let transform = env.transform();
assert!(transform.is_changed());
assert!(transform.translation.abs_diff_eq(Vec3::splat(0.5), 1e-5));
env.tick(Duration::from_millis(500), &mut system);
assert_eq!(env.event_count(), 1);
let animator = env.animator();
assert_eq!(animator.state, AnimatorState::Playing);
assert_eq!(animator.tweenable().times_completed(), 1);
let transform = env.transform();
assert!(transform.is_changed());
assert!(transform.translation.abs_diff_eq(Vec3::ONE, 1e-5));
env.tick(Duration::from_millis(100), &mut system);
assert_eq!(env.event_count(), 0);
let animator = env.animator();
assert_eq!(animator.state, AnimatorState::Playing);
assert_eq!(animator.tweenable().times_completed(), 1);
let transform = env.transform();
assert!(!transform.is_changed());
assert!(transform.translation.abs_diff_eq(Vec3::ONE, 1e-5));
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment