#bevy_tweening

1 messages · Page 1 of 1 (latest)

final salmon
eager trout
junior shore
#

Could we get API for setting completion events on all Tweenables? Right now it's only on Tween, which complicates detecting when a Sequence does end (because you need to add the even to the last tween before you type-erase it). It would be nice if at least Sequence itself had it.

eager trout
#

Sounds reasonable. Could you please open an issue for this on GitHub? Thanks!

junior shore
rustic prawn
#

not sure if missing something but if I want to do something like TweeningType::PingPongOnce I'd need to make two tweens and chain them right? or at least that's what i'm doing now

it might make sense to have not just Once that plays in one direction, since in a lot of tweens (like say on click) it feels common to make a thing do something and return to initial state

eager trout
#

The new API, which will be in the upcoming release this week hopefully, gets rid of TweeningType in favor of a more powerful explicit repeat count. So you can configure that with a repeat count of 2 and a repeat strategy of mirroring (ping-pong).

rustic prawn
#

oh awesome, thanks!

eager trout
trail silo
#

Is it not possible to have parallel tweens via Track for tweens that update different components at the same time?

#

I have

            Box::new(tween_rotation) as BoxedTweenable<_>,
            Box::new(tween_size) as BoxedTweenable<_>,
        ]);

but i get some errors about the component types being different

junior shore
#

You need separate Animator components on the entity

trail silo
#

I see, thanks. I thought one would override the other but I guess not.
Another question I have. I would like to do a tweening where the target position is moving (it's the position of another entity). Is that possible?

junior shore
#

That sounds like a task for a physics engine + regular systems, where you would point the velocity of your entity at the target

#

Tweening is about predefined, interpolated animations

eager trout
eager trout
honest gate
#

I was a little confused why I couldn't make a Track (which doesn't seem particularly documented?) contain multiple types (in my case, I was animating both the text opacity and the transform scale). Probably worth a note at least but ideally you would be able to run several in parallel without making multiple animators.

eager trout
#

The terminology is probably confusing here but there's no way what is currently Track can work on multiple types of components or assets. What you're asking here is a higher level construct that allows mutating multiple targets (component, asset) like you find under the animation track terminology in 3D softwares like Blender. This would require some kind of super-animator. But bevy_tweening doesn't aim at being a full animation library, in particular because indexing multiple targets like this efficiently and dynamically is an open problem that Bevy itself is trying to figure out in its animation crate.

#

I appreciate the value of the request and I wish it was easier, but this is probably out of scope of this library due to complexity. The tweening terminology of the name tried to highlight this (tweens are general simple animations, not full-featured ones). The main issue is that the system function needs to (mutably) access those targets to animate them, and having multiple of them just makes everything more complex. Not to mention their types need to be known at build time.

#

The type safety is the reason you need one Animator per component type.

honest gate
#

got it! thank you for the detailed explanation -- probably worth a quick note in the readme, or maybe my misunderstanding (i'm very new to game programming in general) is a very elementary one. i simply meant just attaching multiple animators, with no synchronization or fancy features in a more convenient manner.

#

another thing that i was confused by was programmatically starting/stopping animations. i assume it's very cheap to add/remove animators, but still seems ideal to be able to .reset() or similar to replay animations (or maybe i missed that too :)

eager trout
honest gate
unborn pendant
#

Hi! I want to create an animation curve like in the following image (the box with the gray border represents a screen, and the blue curve is the animation curve I want to achieve).

But there is a problem, animations for X and Y axis are different. So, to achieve this I need two Animator components for the one entity, but the app panics with the message: "Entity has duplicate components".

How can I fix it?

let x_animation = Tween::new(
    EaseMethod::Linear,
    TweeningType::Loop,
    Duration::from_secs(25),
    UiPositionLens {
        start: UiRect {
            left: Val::Percent(0.)
        },
        end: UiRect {
            left: Val::Percent(100.)
        }
    }
);

let y_animation = Tween::new(
    EaseMethod::CustomFunction(|x| {
        if x > 0.5 {
            1. - x
        } else {
            x
        }
    }),
    TweeningType::Loop,
    Duration::from_secs(25),
    UiPositionLens {
        start: UiRect {
            bottom: Val::Percent(50.),
        },
        end: UiRect {
            bottom: Val::Percent(100.),
        }
    }
);

commands.spawn((
    ...
    Animator::new(x_animation),
    Animator::new(y_animation),
    ...
));
unborn pendant
#

The Tracks does it 🤦‍♂️

eager trout
#

Tracks is the heavyweight way to do this. The way I'd personally do it is write a custom Lens that updates the X/Y components according to the curve equation, and have a linear easing method so the Lens receives the parameter t representing the position in [0:1] alongside the curve.

unborn pendant
little seal
#

this works fine, but I was wondering whether I overlooked smt.

junior shore
#

How is this different to just setting the start appropriately when you create the Tween?

little seal
#

It makes most sense for delayed tweens.

#

Though using it for immediate tweens means start doesn't have to be set/component doesn't have to be queried from the system adding the tween which I consider to be a slight ergonomic benefit. Might be just me though.

junior shore
#

Oh right, if you used that with delayed tweens. you wouldn't need a separate Timer

eager trout
# little seal Hello, <@699635624940142592> Have you considered adding relative/from tweens? ...

I guess this simplifies writing deleted tweens indeed. Do you have a concrete example?

The only thing -- and that's not specific to this change but reinforces the issue -- is that there's again a design question about what happens when e.g. the root tweenable loops, or you're seeking with set_elapsed(). Should the callback be raised in those cases? And when / how many times exactly?

eager trout
#

Or use the new bypass mechanism but that's dangerous because you don't know what the lens callback will do with target.

little seal
little seal
#

btw. when is the underlying component/resource not mutated when lerping it? Not questioning it, just curious.

little seal
eager trout
eager trout
little seal
#

I asked about the bypass simply 'cause I was curious.

fair nacelle
#

Hi! I'm new to bevy/gamedev and have a couple questions:

  1. What's the intended pattern for adding/removing animations to an entity? Use Option<Animator<T>> and commands.insert? If adding a second/third animation, the way to do that is to replace the tween with a tracks one?
  2. Is there a way to rotate a 2d element around a non-center point (like the mouse)?
    Thanks for the library!
eager trout
#

Hi Dan-

  1. The question is why you want to remove the animation? Do you really want to remove the animation, or just not have an animation played? In general there's 2 patterns: a) Leave the Animator forever, just pause it (change it's state). That way you can resume quickly without having to deal with component spawning. Great if you plan to run animations more than once on the same object (Entity). or b) spawn an Animator when needed then delete it once the animation is completed. To be honest I have yet to hear a compelling argument to do that. Maybe "to be clean, because I don't like having unused components" is the closest to a valid reason.
  2. Not with a built-in Lens, but the library very much encourages you too create your own Lens (don't forget to register the animator system).
fair nacelle
#

Thank you!
Re: 1: What I've been doing is spawning 'do nothing' animaors at startup so I can query for them later, and I figured that was bad somehow. It sounds like maybe that's fine?

eager trout
#

If you're going to reuse them at some point more than once that's the method I'd use, until proven that there's an issue with it.

#

To be fair, until you reach critical project size I'm pretty sure you won't notice any difference between spawning animators upfront or just in time. So unless you have tens of thousands of animators and you measure an overhead, I wouldn't worry too much about it.

little seal
#

set_elapsed doesn't access the target, so I don't think it can be really called at that point, can it?

#

my silly code just sets it during the tick of the tween since that's when the component is accessed

fn tick(
        &mut self,
        delta: Duration,
        target: &mut dyn Targetable<T>,
        entity: Entity,
        events: &mut Mut<Events<TweenCompleted>>,
    ) -> TweenState {
        if self.clock.state() == TweenState::Completed {
            return TweenState::Completed;
        }

        if self.times_completed() == 0
            && self.direction == TweeningDirection::Forward
            && self.progress() == 0.
        {
            self.lens.update_on_tween_start(target.target_mut());
        }

// ... rest
}

Is there a better place where to put this if the Lens callback needs &mut self and &T where T: Component?

eager trout
#

The only place which accesses the target is tick(), called from the animator

little seal
#

right, then the approach I took shouldn't trigger any extra change detection.

Should I draft a PR or this doesn't align with yr vision and I should just keep it as a fork?

eager trout
#

If the only change is the update_on_tween_start() then I believe it's a reasonable addition.

Although the devil's probably in the details of when that's called, or equivalently how we define "start". It seems your implementation above all calls it when at t=0 and moving forward, which means users using the Backward direction from t=0 won't get the callback. Is that a reasonable expectation? Not sure.

#

Maybe the callback should only be raised when the animator becomes enabled? That would prevent looping tweens from raising it every loop no?

#

Also, the == 0. on an f32 value is generally something I'd avoid to prevent issues with floating point imprecision. Here we should prefer the "elapsed" API anyway (Duration-based), which doesn't have this issue.

little seal
# eager trout If the only change is the `update_on_tween_start()` then I believe it's a reason...

I think the callback could pass in the direction and the iteration in case the lens might mutate on further iteration

fn update_on_tween_start(
        &mut self,
        target: &T,
        direction: TweeningDirection,
        times_completed: u32,
    ) {
    }

// ...

fn tick(
        &mut self,
        delta: Duration,
        target: &mut dyn Targetable<T>,
        entity: Entity,
        events: &mut Mut<Events<TweenCompleted>>,
    ) -> TweenState {
        if self.clock.state() == TweenState::Completed {
            return TweenState::Completed;
        }

        let target = target.target_mut();
        let times_completed_before = self.times_completed();

        // Check for the start of the tween
        if self.elapsed().is_zero() && times_completed_before == 0 && self.direction.is_forward() {
            self.lens.update_on_tween_start(target, self.direction, 0);
        }

        // Tick the animation clock
        let (state, times_completed) = self.clock.tick(delta);
        let (progress, times_completed_for_direction) = match state {
            TweenState::Active => (self.progress(), times_completed),
            TweenState::Completed => (1., times_completed.max(1) - 1), // ignore last
        };
        if self.clock.strategy == RepeatStrategy::MirroredRepeat
            && times_completed_for_direction & 1 != 0
        {
            self.direction = !self.direction;

            self.lens
                .update_on_tween_start(target, self.direction, times_completed);
        } else if times_completed != times_completed_before {
            self.lens
                .update_on_tween_start(target, self.direction, times_completed);
        }

//...
}



little seal
eager trout
# little seal What does enabled mean? When it goes from paused to playing combined with the el...

Good question 😂 I had forgotten there's only a pause state. Then nevermind ignore that comment.

I'm still not sure about when the callback should be raised though. Maybe we should formally define "start" first. But it seems that this is the same design issue as trying to define what happens to "times completed" when you use set_elapsed(); it's not very well defined and different users might have different expectations.

#

Maybe elapsed() == 0 is as good a definition as any. Though what happens if you tick(0) multiple times? You raise the callback each time?

little seal
#

then storing a flag or a tick count (u64?) in the AnimClock might work?

#

mutating the lens multiple times to the same initial value would probably be fine in most cases, but it'd still be unexpected to call it multiple times

ancient warren
#

how wuld you have multiple tweens that execute in parallel that change different components?

fiery chasm
#

How add waiter for start Tween?

eager trout
eager trout
fiery chasm
#

With repeat sequence, Any suggestions?

#

And if you know how I can make a lens for the BackgroundColor it would help me a lot

fiery chasm
fiery chasm
eager trout
#

I don't understand what you're trying to do. Do you want the delay once or repeated?

fiery chasm
eager trout
# fiery chasm Delay one, and repeat the next tween

This is not currently possible. This is essentially #16 and #79, with some of #60 too. The core reason is the design question of what happens to a looping sequence when the user "seeks" it with set_elapsed() or similar. There are various parameters like the completion count or the event callback for which there's no clear expected behavior (or, the expectation varies depending on users). This becomes even more complex for looking Tracks because not all parallel tracks are necessarily the same duration, so even mirroring is not well defined.

lucid root
#

I have trouble to run the examples on linux. It tells me that the platform is not supported...

eager trout
#

You didn't add the winit feature? See the README for example commands how to run

#

You also need to select a backend on Linux

north summit
#

Hi ! Does an example of the tick function calls with Duration::ZERO exists somewhere ? I tried to understand what are the arguments I should send in it ? especially for target and events I have no clue what are those exactly

stuck obsidian
#

Is there an easy way to animate a UI elements Opacity?

#

Nvm, just can implement it on backgroundcolor custom. Seems useful as a basic lens, does it warrant a pr?

eager trout
eager trout
little seal
#

Hey,
I added a setting to always fire the tween done event (or rather a default user data value) using a settings resource).

https://github.com/SecretPocketCat/bevy_tweening/commit/31db2db81b69682eed06c4fe2b047fa0a4264a3c#diff-f28ade83b4bc12c03b42d7f9094508645e500a5eb4f8863eedcd84f3452d1720

Would a PR make sense?

My usecase is adding a TweenDoneAction component which is handled when the event is fired, but that requires always setting the user data which is a bit boilerplate-y and easy to forget when the user data is not actually used, just the event.

little seal
frozen moss
#

Sup nerds. I noticed that this library was migrated to 0.11 but i cant do a cargo update on it:

"error: failed to select a version for the requirement bevy_tweening = "^0.8"
candidate versions found which didn't match: 0.7.0, 0.6.0, 0.5.0, ...
location searched: crates.io index
perhaps a crate was updated and forgotten to be re-vendored?"

Does it take time for it to be "re-vendored" or something?

eager trout
#

It's not published yet, waiting on bevy-inspector-egui

#

The code on GitHub using a version has nothing to do with cargo. Only versions published on https://crates.io/crates/bevy_tweening are considered by cargo, and 0.7.0 is the latest, as the error message indicates. There's no vendoring here.

frozen moss
#

My bad. I thought it would be available because the compatibility table was updated.

eager trout
#

Sorry that was an eager PR, shouldn't have updated so soon. Jakob just released bevy-inspector-egui so I will see when I have time to push a new release.

frozen moss
#

No worries! And ty for your work!

eager trout
#

Published yesterday evening, I'll make an announcement later but it's available already.

frozen moss
#

So i ran into an interesting "problem". I'm on 0.11.

If you make a tween like this:

Tween::new(
    EaseFunction::BounceIn,
    Duration::from_millis(5000),
    SpriteColorLens {
        start: Color::NONE,
        end: Color::WHITE,
    },
)

The sprite will start fully transparent, and then "bounce" into full opaqueness (over 5 seconds).

But if u prepend it with a delay, lets say of 1 second, it will spawn fully opaque for one second, abruptly become transparent, and then "bounce" into full opaqueness. My theory is that the delay doesn't seem to apply the "start" configuration of the subsequent tween, which may or may not be the intended behavior of the author.

I'm guessing the fix here for now is to have the sprite spawn fully transparent and not rely on the Tween logic. But its a shame that Id only have to do that when I use a delay.

It feels cleaner for the Tween code to handle it the same way in both scenarios. Currently, the animation logic can't be in one place, because the start of the animation wont also be where the tween is instantiated when a delay is used. So if you want to guess what the animation does just from reading the code, you have to consider how the sprite is being spawned. Which is not a huge deal, but its something I can see improved.

junior shore
#

Doesn't the SpriteColorLens only apply to the transition Tween and not the delay before it? Basically, for the duration of that delay, the sprite will have the color it spawned with (which in Bevy is 100% white by default) sicne bevy_tweening won't animate it at all

frozen moss
# junior shore Doesn't the `SpriteColorLens` only apply to the transition `Tween` and not the d...

Thats what im guessing it does, possibly by design. But i went from a tween doing one thing to it doing something very different just by adding a delay, which feels wrong to me. I can see why we may want to keep things as is, but this make me wonder if there is not a better way. Like if i can pass an input to the delay that configures the "start" so i dont have to do it inside the .spawn(), that might be considered an improvement?

junior shore
#

Your tween still does the same thing. What you did was combine it with a delay to produce a sequence of tweenables, which is different than what you started with. And again, the lens belong to your original tween, so it doesn't really make sense for them to affect the entity during the delay, which is a different tweenable altogether than the color animation. There are too many issues that would arise if you started doing that.

#

Consider e.g. a sequence that goes color A -> color B -> (delay) -> color C -> color D. If a delay can be affected by neighbouring tweens' lenses, then what color should the sprite have during the delay? B? C? Some mixture of those, which would essentially turn the delay into another animation? The rules would get way too complicated. It's better to simple have tweens that do exactly what you prescribe, and no more.

frozen moss
#

Hmm, actually i think i agree with u here.

thorn blade
#

Trying to add a Lens for Velocity and it doesn't seem to be working, any ideas?

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct VelocityLinVelLens {
    pub start: Vec3,
    pub end: Vec3,
}

impl Lens<Velocity> for VelocityLinVelLens {
    fn lerp(&mut self, target: &mut Velocity, ratio: f32) {
        println!("changing"); // THIS DOESN'T GET CALLED 
        target.linvel = self.start + (self.end - self.start) * ratio;
    }
}
...
let tween = Tween::new(
    EaseFunction::CubicOut,
    Duration::from_millis(250),
    VelocityLinVelLens {
        start: velocity.linvel,
        end: Vec3::ZERO,
    },
);
entity.insert(Animator::new(tween));
thorn blade
eager trout
#

Yeah that's a very common mistake. Not sure how we could detect it and emit a warning.

thorn blade
modest shell
#

How to change direction of a Tween from a system?

eager trout
#

There's no simple way at the minute because although it's trivial for a Tween, the behavior is not well defined for another Tweenable like Sequence or even worse Tracks. For that reason there's no set_direction() on the Tweenable trait, and so you can't really update it on the fly 😦

unborn pendant
#

I have a workaround for that issue. I added this function to the Tweenable trait:

fn as_any_mut(&mut self) -> &mut dyn Any;

And then in the Tween struct I implement it as:

fn as_any_mut(&mut self) -> &mut dyn Any {
  self
}

And then in a system I do:

let tween = animator.tweenable_mut().as_any_mut().downcast_mut::<Tween<Text>>().unwrap();
tween.set_direction(TweeningDirection::Forward);
orchid cargo
#

I can't seem to get my tween working properly. No matter what I do the duration appears as if it's 0. I'm trying to animate a UI position using the provided lens (opening and closing a menu), and while the changing of the position works, it seems to happen instantly regardless of the duration the tween is created with.

eager trout
fluid zephyr
#

I'm not sure if this is worth documenting, but I recently made a lens for a TextureAtlasSprite that didn't work until I added component_animator_system::<TextureAtlasSprite>, even though that's not a custom component. Is that expected?

eager trout
fluid zephyr
eager trout
#

This is really a limitation of the ECS here, if anyone has a better idea I'm all ears. But I don't see how you can fetch a random collection of components, short of using an exclusive system and doing manual queries.

stray rover
#

I have added both Animator::new(Tween::new(..TransformPositionLens and Animator::new(Tween::new(..TransformScaleLens to the same entity, and I am afraid the latter stops/replaces/blocks/hinders the former.

#

I know each entity can only have one Component of the same type, but I did not expect the types to be identical. Or is that the explanation?

#

Then, how to solve it? I was looking for a Tween or Lens that affects two aspects in parallel.

#

I found Tracks<T> (despite the name which does not ring any bell for me), but thought I could not use it because my Tweenables do not have the same type.

#

If there is some BoxedTweenable in play here, maybe that would answer all my questions…

stray rover
craggy birch
#

can i add a custom lens for a built-in bevy component? i want to animate Text changing its font size

craggy birch
#

seems like recreating pausing from bevy_easings would be pretty hard

craggy birch
#

wow this is super good

craggy birch
# stray rover Then, how to solve it? I was looking for a Tween or Lens that affects two aspec...

you can make your own Lens where you'd change any properties of a component (not just one property). this is what i did in my code, changing both font_size and alpha of Text:

#[derive(Debug, Copy, Clone, PartialEq)]
struct ClueTextLens {
    start_font_size: f32,
    start_alpha: f32,
    end_font_size: f32,
    end_alpha: f32,
}

impl Lens<Text> for ClueTextLens {
    fn lerp(&mut self, target: &mut Text, ratio: f32) {
        let font_size_value =
            self.start_font_size + (self.end_font_size - self.start_font_size) * ratio;
        let alpha_value = self.start_alpha + (self.end_alpha - self.start_alpha) * ratio;
        target.sections[0].style.font_size = font_size_value;
        target.sections[0].style.color.set_a(alpha_value);
    }
}

you can do a similar thing with Transform

stray rover
#

Actually, Tracks helped me to achieve my goal. I just had to pass the two tweens which anyhow had the same type (see above). In theory, I would have preferred to group the two animations on the lens level, because they share the same duration / easing, yet that is not worth the extra code IMO. But thanks for the example; that amount of code would be absolutely tolerable if it was better motivated in my case.

craggy birch
#

thanks for the link, i've yet to use Tracks. now to figure out how to use Delay

craggy birch
#

hm, my sprite flickers for a frame with full scale before starting to tween (i'm tweening it from small to normal scale)

#

am i supposed to spawn it with small scale?

#

i'm not seeing that happening in the examples

eager trout
#

It depends a bit when you spawn it compared to when the animators are updated. If you spawn after animation update and before rendering, tweening will only scale them on next frame.

#

There's a label for the animator update so you can order your systems relative to that.

eager trout
# stray rover Actually, `Tracks` helped me to achieve my goal. I just had to pass the two twee...

Custom lens is definitely the way to go here. Tracks are for synchronizing tweens on different components and is a lot more heavyweight. A custom lens for both position and scale is a common pattern. Unfortunately bevy_tweening cannot anticipate all combinations of usage so only ships with a very short number of ubiquitous lenses for core components. But the library design very much encourages you to write your own lens customized to your use case.

stray rover
#

Ok, thanks. In the meantime I cleaned that up, and it is now more elegant and not much more code, indeed.

hexed field
#

I'm having an issue with the TransformScaleLens. I can't seem to get it to end the tween at the right scale and I'm not sure which part is causing the issue.
If I SET the scale outside of the tween, it gets the size I want, so I used that value for the end value. I've been going through every EaseFunction and a few different time values

My tween is defined like this right now:

let tween = Tween::new(
    EaseFunction::QuadraticInOut,
    Duration::from_secs(1),
    TransformScaleLens {
        start: Vec3::ZERO,
        end: Vec3::new(EXPLOSION_RADIUS, EXPLOSION_RADIUS, EXPLOSION_RADIUS),
    },
);

It just.. is either too big or too small, never gets to the same size as setting the scale directly.

little seal
hexed field
# little seal the tweening should be absolute - aren't you setting the scale/overriding the sc...

I don't think so..
Below is a link with the whole method where I make the explosion, the one where they are spawned, and the one where I check for a collision between enemies and the explosion, I don't really touch them anywhere else.

I had it as EXPLOSION_RADIUS / 2 in the collsion checking (which I realized was a bad name, and changed it to Size), but I removed the division and it's closer. The explosion is still quite a bit bigger than the gizmo I use to see the actual area of the collision. So the issue could be with that instead.

It's just that using the different Easings is resulting in different sizes, so I'm not sure which to use. Mostly confused by the in and out (I realize it's the rate of change at the biginning and end, I just don't know how that is changing the resulting size so much).

https://gdl.space/esidugajip.php

OH, and thank you for the tip on Splat, that is a LOT better.

little seal
# hexed field I don't think so.. Below is a link with the whole method where I make the explos...

Easing is just the curve the tween
https://easings.net/

Unless the animator gets paused or removed by something the final size should be the same.

Not sure what the unit of the gizmos is, but the scale of the sprites is relative to the sprite size (which is the resolution of the texture if not overridden using custom_size)
https://docs.rs/bevy/latest/bevy/prelude/struct.Sprite.html#structfield.custom_size

Also the z scale of sprites affects their z order, so you might wanna not actually tween the z component of the scale vector in 2D (you can use Vec2::splat(size).expand(z) instead of Vec3::splat)

hexed field
# little seal Easing is just the curve the tween https://easings.net/ Unless the animator get...

The gizmo seems to correctly show when it affects the enemy, so I assumed that was correct.

Thanks for the tip on the z order, I was dealing with some z fighting which is why I set the z positions like that.

I DO have the sprite removed after a short amount of time. And it's less than the animation time. I didn't even consider the relation for some reason lol
I'll play around with that when I get back to my computer

Thanks a bunch for the help

eager trout
hexed field
# eager trout If you remove the sprite before the animation end time then yes indeed the "fina...

I entered the const I used for the time the sprite remains, minus 0.1, for the duration and the problem got worse. It would take up the whole screen, but it was consistent between easings.

So timing definitely was the reason all the easings were different. They simply were at different points of the curve when removed.

I think the issue had to do with scale just working different than distance. I was using the same number to scale the end of the tween and check the distance. I simply made a new const just for the scale and it works fine now.

I should have guessed that to begine with. Makes a lot of sense.

eager trout
#

Glad it worked

craggy birch
little seal
craggy birch
little seal
eager trout
#

Noted. Feel free to open a Bug on GitHub for that. It's indeed a common mistake but I'm not sure what wording could prevent it.

orchid cargo
#

Are there plans for 0.12? The plugin seems to have broken for me after updating 😔

thorn blade
# orchid cargo Are there plans for 0.12? The plugin seems to have broken for me after updating ...

there's a PR up, hasn't been updated in a while but at a glance it looks like it did most of the breaking changes already, I think it just needs the version changed from 0.12-dev to 0.12
https://github.com/djeedai/bevy_tweening/pull/100

GitHub

This implements some minor changes to prepare for the Bevy 0.12 release (will probably take a bit still).

#

I was gonna test it and do work on it if needed but I need oxidized_navigation first and I'm having trouble getting that one to compile..

orchid cargo
thorn blade
eager trout
#

Didn't announce yet but published a release yesterday

eager trout
#

Announced on #crates now

frozen moss
#

So I wanna run a one-shot system when a tween completes (without relying on events). Is this doable?

frozen moss
#

I was thinking i could use with_completed (i think thats what its called) to run a callback, but it doesnt let me use commands cus its not FnMut?

eager trout
#

I think this would require a small change (or at least would be easier with it) storing the system ID in the completion and invoking it directly. But I didn't look much at one-shot systems yet, so not sure.

frozen moss
eager trout
frozen moss
# eager trout If you want access to some Bevy stuffs, you probably need a system, and so you s...

Well, even with that limitation i can still clean up the design i got but i was also hoping to avoid polling for events. Feels silly to do that when u got a single event that will only be raised once, and only need to react to it once. In those cases, a one-shot system seems perfect.

At some point id like to make a PR to add "with_completed_oneshot" (not married to that name) to the crate, that just takes in a system ID and runs that system. Is this a feature you would accept?

eager trout
inland steppe
#

quick question if anyone happens to know, I'm patching bevy_tweening for main, the explicit Vec4 methods, rbga, rbga_linear, ... are now used.

#

Well the bevy_tweening tests only using rgba seems to indicate that they are the only discriminant expected. This could explain some bugs I had using rgba_linear colors in the past.

eager trout
#

Doing a linear interpolation between a start and end colors from different color spaces makes little sense. So for simplicity this was restricted to "some RGBA", keeping it loosely defined. The best way is to write your own Lens for the color space you use; there's no need to patch anything.

inland steppe
eager trout
orchid cargo
#

I'm trying to tween the rotation of my camera, and at first it seemed to work just fine. However, now it has suddenly started flipping upside down during the tween. Once it finishes, it is (instantaneously, not as part of the tween) flipped correctly again. Any ideas?

#

Relevant code (can provide more details if necessary)

#

To be clear, the resulting rotation is all good, it's during the tweening that it is flipped vertically

eager trout
orchid cargo
#

Sorry i can’t provide a better answer ferris_sob

eager trout
#

I don't know then. Sounds like a bug in Bevy maybe?

#

On your code above though, the loop on events is useless I think, only the last event matters. All the ones before do useless work overwritten by the last event.

#

I think there's a .last() on Iterator to get just the last event.

lone rapids
#

Hi ! I was just wondering how I could loop a Sequence ... I saw the issue about repeats in a Sequence, basically what I want to achieve is :

Animator::new(
    Delay::new(Duration::from_secs_f32(1.0))
        .then(Tween::new(
            EaseMethod::Linear,
            Duration::from_secs_f32(0.5),
            SpriteIndexLens { start: 0, end: 4 },
        ))
        .then(Tween::new(
            EaseMethod::Linear,
            Duration::from_secs_f32(0.2),
            SpriteIndexLens { start: 0, end: 4 },
        )),
)

I want to repeat each Tween twice, wich seems impossible right now, I guess I can live with some code duplication for now, but I don't know how to loop the complete Sequence ... SpriteIndexLens is a custom lens for TextureAtlasSprite. Any thoughts ?

eager trout
lone rapids
#

There is literally an issue named Make Sequence loopable ... How did I miss that one ... Anyway thanks 🙂

frozen moss
#

If I want two lenses to operate at the same time in parallel, and indefinitely, should that be doable? My first attempt with tracks with 2 tweens failed because only the last tween in the array gets used.

frozen moss
#

Actually could i just make a custom lens that essentially does both tweens and then just have that single lens run indefinitely? Never made a custom lens before so I'll try it.

#

aaaaand it worked like magic lol. I dont know if this would work in every use-case but its awesome how easy it is to make a custom Lens.

ornate reef
#

because i wasn't able to get it to work

#

this gets mad bc it doesn't see it as a valid component to tween

frozen moss
#

Huh, hold on..

ornate reef
#

I'm a bit surprised how difficult it is to fade something out while moving it

frozen moss
#

Oh yeah that makes sense. It specifically wants T: Component. So we couldnt do that

ornate reef
#

yeahh

#

is there any other solution to run two tweens in parallel?

frozen moss
ornate reef
#

Tracks also do not work

#

I'm gonna test it again just in case I did something really dumb

#

but it also had issues for me

frozen moss
#

Well let me know what error or other obstacle u run into and I might be able to help

ornate reef
ornate reef
frozen moss
#

yeah I forgot how i got around this, but i remember running into this before

ornate reef
#

rakapray2 i would hugely appreciate the solution

#

because my other solution was just manually updating the transform part myself lmao

frozen moss
#

Let me think on it, il get back to u if i find out. For now id move on to something else in your project so its not so frustrating lol.

ornate reef
#

yeahhh

#

3 day game jam and I wasted too many hours on this lol

frozen moss
#

@ornate reef OK so looking at my older project, im seeing that Im just attaching two animators to the same entity to get them to go at the same time? At first i though this would be impossible, but Animator<Sprite> and Animator <Transform> are considered different so they dont overwrite each other. Id try this out.

ornate reef
#

Oh interesting, let me try it out

frozen moss
#

I think my case was more annoying than that because they were both using Transform.

ornate reef
ornate reef
frozen moss
ornate reef
#

or a track

frozen moss
#

hence the custom lens

ornate reef
#

yeah, then probably would need lens

ornate reef
frozen moss
#

Yeah there are a few situations that should be documented imo.

eager trout
#

Bevy needs to know the type of component we mutate, so all tweenable unfortunately are generic on that. For multiple animations on a same component, add a single animator and write a custom lens. For multiple animations on different components, we need to access them all so need multiple animators.

Hopefully once we have dynamic queries we can simplify all of that and just have a single non generic animator which dynamically accesses the relevant component(s). But for now there's not much choice unfortunately.

One way that could possibly be improved in the meantime was to be generic on multiple components at the same time, but that might spiral into generics hell 🥲

frozen moss
eager trout
#

Yes, but I do understand how this is confusing. Unfortunately I tried a few times and I don't have a better solution at the minute 😦

#

This is akin to bevy_animation which needs to "animate everything (c)", and to do that has a complex entity path system to track components etc. But for bevy_tweening I don't want all that machinery, it's supposed to be a lightweight tweening system for small animation-like wobbles etc., not a full-featured animation package.

frozen moss
ornate reef
#

oh that makes a lot of sense, i really appreciate the transparency!

frozen moss
#

@eager trout Hi, im the author of https://github.com/djeedai/bevy_tweening/pull/111/. I dont know if u have email notifications on so im putting this here. I think we only have one unresolved conversation and then I think we can close this.

Thanks for working with me on this and I'm sorry that you had to deal with my amateur hour bs lol.

eager trout
#

Sorry @frozen moss I was a bit busy. CI is running, I'll merge after if green. Thanks for the contribution!

frozen moss
#

Oh and some of the tests failed, il look into it..

eager trout
#

Doc tests; you can run locally with cargo t --doc

#

So the one thing that was blocking me was the comment u had on the one unit test. Are we just giving on what u proposed, or did u add something? Sorry I might have missed it.
I closed it. It doesn't matter much, this can be improved later.

frozen moss
eager trout
willow sierra
#

How can I animate Transform its rotate_around using the bevy_tweening crate?

eager trout
#

@willow sierra create a custom type implementing the Lens<Transform> trait, and in the implementation use rotate_around

rapid zinc
#

@eager trout Any rough timeline on 0.14 support? Thanks in advance!

eager trout
#

As usual, waiting for bevy-inspector-egui, and generally within 2 days after that or less

#

There's a PR up already

eager trout
#

@rapid zinc 🍃 Bevy Tweening v0.11.0 supporting Bevy v0.14 was just released

frozen moss
#

@eager trout Would it be an issue if you triggered TweenCompleted (in addition to sending it) so that observers can work with it? I can submit a PR that does this, if u have no objections 🙂

eager trout
#

I don't understand what you're asking. What does "trigger" mean here, if not "send"?

frozen moss
weak glen
#

Hi! @eager trout ,I really like this plugin🙂 . By the way, may I ask when using the seq mode, I use a Vec<Vec3> array to move. How can I make the model face the moving direction?

#
for event in events.read() {
        if let Ok(entity) = query.get_single_mut(){
        let dests: &Vec<Vec3> = &event.path;
        let seq = Sequence::new(dests.windows(2).enumerate().map(|(_, pair)| {
            Tracks::new([
                    Tween::new(
                        EaseFunction::QuadraticInOut,
                        Duration::from_millis(250),
                        TransformPositionLens {
                            start: pair[0],
                            end: pair[1],
                        },
                    ),
                ])
            }
        ));
        commands.entity(entity).insert(Animator::new(seq));
        }
    }```
eager trout
eager trout
#

Finally, what's the "model" here and what's "facing"? You're moving some entity with a Transform, there's no model or facing involved in the example.

weak glen
#
fn listen_for_path_found_events(
    mut events: EventReader<PathFoundEvent>,
    mut query: Query<Entity, With<Character>>,
    mut commands: Commands,
) {
    for event in events.read() {
        if let Ok(entity) = query.get_single_mut(){
        let dests: &Vec<Vec3> = &event.path;
        let seq = Sequence::new(dests.windows(2).enumerate().map(|(i, pair)| {
            Tracks::new([
                    Tween::new(
                        EaseFunction::SineInOut,
                        Duration::from_millis(250),
                        TransformPositionLens {
                            start: pair[0],
                            end: pair[1],
                        },
                    )
                    .with_completed_event((i as u64) / ((dests.len()-2) as u64))
                    ,
                ])
            }
        ));
        commands.entity(entity).insert(Animator::new(seq));
        }
    }
}

fn listen_pathfound_complete(
    mut query_event: EventReader<TweenCompleted>,
    mut commands:Commands,
    children: Query<&Children>,
    mesh_q:Query<&Handle<Mesh>>,
) {

    for ev in query_event.read() {
        if ev.user_data == 1{
            for child_entity in children.iter_descendants(ev.entity) {
                if let Ok(_) = mesh_q.get(child_entity) {
                    commands.entity(child_entity).remove::<OutlineBundle>();
                }
            }
        }
    }
}
#

@eager trout Sorry, I'm a newbie🙂 . "dests" is the array of target points where I want to move.Every time I take a step, it triggers a with_completed_event. How can I listen only for the final step? (In my code, I determine the final step by check the value of userdata on the listening side.)

eager trout
#

Oh yeah ok you'd need a completed event on the Sequence instead of the one on each individual Tween. It's not currently possible but while be easy enough to add. Please feel free to open a GitHub issue.

frozen moss
#

@eager trout When i try to use ColorMaterialColorLens, i get

bevy::prelude::ColorMaterial is not a Component
the trait bevy::prelude::Component is not implemented for bevy::prelude::ColorMaterial
consider annotating bevy::prelude::ColorMaterial with #[derive(Component)]

and my cargo has this:
bevy_tweening = { version = "0.11", features = ["bevy_text", "bevy_ui", "bevy_asset", "bevy_sprite"] }

What did I miss?

little seal
frozen moss
eager trout
#

Yes unfortunately assets in Bevy work quite a bit differently from components, notably on the storage and change detection sides. So it's pretty hard to make an Animator that works for both. So for now there's 2 animators. And frankly I'm considering dropping support for the asset one, because assets are not really designed for things changing all the time. Although I appreciate that animating the color of an object is a pretty common use case.

jade kestrel
#

Hey, Is there a way to have a tween rotate and move a transform at the same time ? how would I set that up ? Also wondering if it's possible to get multiple full turns from a single tween ?
Also wondering if there is a way to have it start a tween at the value it already is at.

frozen moss
#

As for the rotation and movement, i think u need a custom lens for that does both at the same time. The only problem with that is that they're going to use the same easing function and animation duration, which might be fine depending on what ur doing.

little seal
little seal
frozen moss
frozen moss
little seal
frozen moss
#

Oh wow, i didnt bother to look at the other trait methods. I would have done it this way too. I got stuck on how to init the start so i just gave up lol

#

Its great cus it opens up opportunities for people to do other things besides what WE wanted to do.

eager trout
eager trout
#

I guess we could add a flag to force setting the start value on the first tick. This needs to be done by the Animator though, it's the only one with access to the component

frozen moss
eager trout
#

The problem is that this kind of thing introduces bad edge cases. The simulation is discrete, so if you have two tweens in a row (sequence) there's no guarantee you will end at the intermediate position between the two at exactly t=1 (for the first) <=> t=0 (for the second). From there you introduce some error, which depends on the speed at which you move (assuming here we're taking the example of a transform).

#

You can't recover that way the "real" start that makes the motion the one originally designed.

#

So it feels like if you need to tween from the current position, just update your start value to it and let the current design as is

#

That being said, I appreciate the API is inconvenient as you can't access the tweenables after construction, so you need some kind of shared lens

little seal
eager trout
#

Imagine your start and end points are on a grid. Now imagine the object moves from the first to second then third point (2 tweens) in a L shape. At the midpoint, even if the first endpoint is absolute, because of delta time and floating point the object might never reach exactly that midpoint. If the start point of the second tween is ignored and instead we take the current position, the object will move "out" of the grid

#

Hum... actually now that I think more about it, I'm not sure this would happen, because changing the start point of the lens doesn't affect the fact the animator applies partial frames correctly 🤔 Maybe that works

frozen moss
#

tbh im also confused. Whatever the problem is, i dont see how manually setting the start myself would prevent it. Its going to be the same value.

Either way, I think the "update_on_tween_start" that they added would allow us to make our own custom lenses that can do this, without needing to change any of the base behavior. The impl for it was one line of code, so super easy for lens makers. I also think this allows us to do other things that requires initialization at the start (im not sure what those use cases would be 😅 ), so its a good solution in my opinion.

frozen moss
# eager trout Yes unfortunately assets in Bevy work quite a bit differently from components, n...

I have a use case for allowing animation of assets, in case ur still open to keeping the behavior. I believe the argument for removing it hinges on the statement that: "assets are not really designed for things changing all the time" and I believe my use case serves as a counter example.

I just "finished" work on a custom 2D material that uses a custom vertex shader to allow me to rotate 2D sprites to produce a "fake 3D" effect. The custom material is stored as an asset, and its also where the x rotation and y rotation is stored which serve as shader inputs. I bet there are plenty of other shader ideas that require dynamic input. Admittedly im not super knowledgeable in this field so maybe my case is rare.

The point is that as long as Bevy is designed to work this way with shaders, then the AssetAnimator is valid.

However, if there is a way to remove the AssetAnimator from the crate while still somehow enabling us to recreate it, i.e by letting us make custom animators in a similar way to how we make custom lenses, then that would still work for me.

eager trout
#

I know about this use case and this is probably the only reason why assets are still supported. Still, this is a bad example I think. If your shader accepts parameters to modify the behavior of the rendering, then those parameters are not part of the asset itself. And therefore what you're animating is not the asset, but some runtime parameter. Now, admittedly I don't remember API-wise how that works so it's possible Bevy forces you to use the Asset interface. But conceptually that's wrong

frozen moss
ruby nexus
#

Is there a common way to query over all animators?
Currently the best solution I was able to come up with is make the system that queries them generic and register it for different components

frozen moss
eager trout
eager trout
# frozen moss I have a use case for allowing animation of assets, in case ur still open to kee...

The thing is, that use case in my opinion shouldn't use assets. See the Bevy example about animated shader: https://github.com/bevyengine/bevy/blob/main/examples/shader/animate_shader.rs -- the animated parameters are not stored in the material, but in a separate dynamic storage. In my mind the current Bevy asset design is to store rarely changing objects like textures. Each time you make a change to an asset there's a complex machinery that gets in motion to process the change, via ECS change detection in particular, and sync other resources like GPU ones related to the changed asset. In the use case of animated shader, you should pass those parameters to the shader itself directly, because all that change detection machinery is pure overhead (it won't do anything useful since the data changed only affects the shader result). A similar construct exists for example in Hanabi with properties, which are separate from the effect asset and dynamically uploaded potentially each frame, while the asset itself almost never changes.

frozen moss
# eager trout The thing is, that use case in my opinion shouldn't use assets. See the Bevy exa...

That example seems to be using some kind of "globals" input from a wgsl which is populated by bevy Internal code. It does not show how one would create their own parameters. U need to go into bevy_pbr to figure that out. I think id rather eat whatever cost my current method requires to avoid dissecting it. Its not reasonable to expect the average Bevy user to just find this and replicate. So until Bevy provides an easy and official way to do this, im not sure it can be part of the discussion for this crate. And please correct me if im wrong about any of that. If this is actually simpler than I think it is, id like to know that too. But trying to figure out mesh_view_bindings.rs and how it interacts with the rest of bevy seems daunting.

From a philosophical standpoint i totally agree with u, assuming what u said is correct (idk the details of the complex machinery u mentioned). I actually look forward to not needing to work with Handles or Assets to pass in those parameters, cus quite frankly, there is an ECS-style indirection that happens there that makes it annoying to deal with. But im not aware if thats being worked on right now.

eager trout
#

Yes I agree that example is not ideal, as it uses the time, which is always available. We should have a Bevy example showing how to use dynamic parameters. I have no idea how hard this is, but if complex then I agree this is an argument to not remove asset animation yet.

sage root
#

Hello. I have entities that move on a grid when keys are pressed. Rather than blocking input during the animation, or interrupting the in-progress tween, I'd like to dynamically queue the tweens so that they all play in order. I figured I could just spawn an Animator around an empty Sequence and then push tweens to that, but I couldn't find a straightforward way of accessing that inner Sequence from the animator. Should I just handle everything in some external queue and recreate the whole Animator every time the state changes (doing some math to figure out what the elapsed progress should be on the new animator)? Is there a direction you would recommend here? Thanks.

eager trout
#

With the current version @sage root you can use Animator::set_tweenable() to change the animation.

#

PSA

I've just merged a large API change that fixes most of the top issues and user-requested features, including loopable Sequence or auto-destroy on completion.
See https://mastodon.gamedev.place/@djee/115141603231527730

Just merged a change started 11 months ago which fixes 5+ major issues in 🍃 Bevy Tweening, including the removal of generics, loopable Sequences and repeating child, component-based animation and target (with ability to target a separate entity), and auto-destroy on completion. All made possible thanks to the typeless API of Bevy (access everything with runtime types, not compile-time ones), which didn't exist when the first version was written!

github.com/djeedai/bevy_tweeni…

#bevy #rustlang #gamedev

vapid elbow
#

@eager trout i think you did not migrate the menu example in the new release? it does not compile and it still tweens Transform instead of the new UiTransform which is what i was missing when porting my game because i am using scaling on UiTransform

eager trout
#

I will have a look. I thought I tested the examples but I was in a rush so may have missed it, with Hanabi also in the middle and all.

vapid elbow
eager trout
#

I will try to publish a v0.14.1 this week-end for this and the EntityEvent. I don't guarantee I'll have time.

vapid elbow
#

@eager trout awesome, i switched to your main branch and using UiTransformScaleLens works! thank you!
Now only TransformRotationLens equivalent for UiTransform is missing.

vapid elbow
#

@eager trout PR opened

frozen moss
#

@eager trout Hi! With the removal of user_data, i was wondering what the alternative is to get the same effect?

#

I.e, how can add custom context to an event so i can get it later when the animation completes?

frozen moss
#

Ok i think i get it. We're no longer inserting the animation components to the thing its mutating. They live on their own as their own entities with the AnimTarget relationship. So if i just attach my own UserData component to the animation, i just need the TweenAnim entity to get that component. I'll need to set the flag that prevents it from despawning upon completion. I really like this change!

flat stirrup
#

Heyy, anyone knows if it’s possible to add multiple animations to one entity in bevy_tweening version 0.14.0 (Because I used it in 0.13.0 and were able to add two Animation::new() to one single entity, but it doesn’t seem to be a thing anymore in 0.14.0)?

frozen moss
#

But uh, thats assuming ur not putting the TweenAnims on the same entity. So just spawn 2 different TweenAnims with a sequence in each one and then target the same entity, that should workl.

flat stirrup
#

Oh but I tried using a sequence but it doesn’t work when you work with two different components

frozen moss
flat stirrup
frozen moss
flat stirrup
#

It was a TODO error when trying to sequence different components something like that

flat stirrup
frozen moss