#bevy_tweening
1 messages · Page 1 of 1 (latest)
Author here! 🙂 Feel free to ask questions, or directly open a bug at https://github.com/djeedai/bevy_tweening/issues/new
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.
Sounds reasonable. Could you please open an issue for this on GitHub? Thanks!
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
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).
oh awesome, thanks!
The new README has an example with the new syntax here:
https://github.com/djeedai/bevy_tweening/blob/30bc490b03f2c2a81050e99d2bf39fd81e42cd46/README.md?plain=1#L56-L73
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
You need separate Animator components on the entity
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?
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
Yes, Animator<T: Component> works on a single component type, and each monomorphism is treated by Bevy as a different component so you can add Animator<A> and Animator<B> on the same Entity.
There's no trivial way to do that. The hack I see is to have a custom lens with an extern reference like Arc<T> to allow mutating the lens after it's added to the Tweenable, because it takes ownership of the lens otherwise so you can't modify it.
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.
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.
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 :)
There used to be a reset() I think, though I don't see it in the latest API. I think you can use stop() instead, then start again by setting the Animator.state field.
Component to control the animation of another component.
got it, i did see the state but didn't think of just manipulating it directly. thank you!
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),
...
));
The Tracks does it 🤦♂️
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.
Oh, yeah, it's clever, thank you
Hello, @eager trout
Have you considered adding relative/from tweens?
I have a fork in which I added a on_start callback to the tween trait (with a blanket noop impl
this works fine, but I was wondering whether I overlooked smt.
with .7 it probably changes change detection at the start by getting the mut ref
https://github.com/djeedai/bevy_tweening/commit/19aa443ada3081e573759abfde9d0e56da54de0e#diff-f28ade83b4bc12c03b42d7f9094508645e500a5eb4f8863eedcd84f3452d1720
How is this different to just setting the start appropriately when you create the Tween?
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.
Oh right, if you used that with delayed tweens. you wouldn't need a separate Timer
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?
That's probably a no go. A similar issue was already reported and fixed so that would be a regression. You need to pass &mut Mut<T>. And yes I know it's ugly.
Or use the new bypass mechanism but that's dangerous because you don't know what the lens callback will do with target.
There's an example Lens in the first commit I linked.
Maybe calling it each loop and passing in the loop count would allow for most flexibility?
I thought Mut was just a smart pointer and using it would cause a deref and trigger change-detection regardless.
btw. when is the underlying component/resource not mutated when lerping it? Not questioning it, just curious.
Could you elaborate/point me in the right direction to read up on this?
When lerping it, never. But in the past the Animator was marking the target component or resource as changed even if the animator was inactive.
I don't understand why you need the target as mutable. You're only mutating the lens, no?
If you really have a good use for passing that target as mutable yet not wanting to trigger change detection on the target, then you can look at https://docs.rs/bevy/latest/bevy/ecs/change_detection/trait.DetectChangesMut.html#tymethod.bypass_change_detection
Types that implement reliable change detection.
U R right, It shouldn't be mutable. In fact the callback takes just a shared reference and only the Lens is mutated.
The way I updated it my local fork was just a quick way to make this work for me in the upcoming jam, since I don't mind this issue very much, but it's def not a good approach.
I asked about the bypass simply 'cause I was curious.
Hi! I'm new to bevy/gamedev and have a couple questions:
- 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?
- Is there a way to rotate a 2d element around a non-center point (like the mouse)?
Thanks for the library!
Hi Dan-
- 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
Animatorforever, just pause it (change it'sstate). 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 anAnimatorwhen 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. - Not with a built-in
Lens, but the library very much encourages you too create your ownLens(don't forget to register the animator system).
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?
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.
Hi, it's after the jam, so I might finally have a bit of time to look into this properly
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?
The only place which accesses the target is tick(), called from the animator
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?
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.
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);
}
//...
}
What does enabled mean? When it goes from paused to playing combined with the elapsed check?
my bad, sorry
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?
That's a good point.
Though can the delta ever be == 0. so this could actually happen?
On a related note - it would be neat, if the plugin had a configurable timescale (for slowmo and pausing and whatnot), but I digress.
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
how wuld you have multiple tweens that execute in parallel that change different components?
How add waiter for start Tween?
Add one Animator<T> per component and try to synchronize then manually. There's no functionality for that unfortunately, the Animator only handles one component at once.
Add a Delay then your tween. Wrap them in a Sequence (or use .then())
Delay have problem with this code :c
Delay::new(max_duration).then(
Tween::new(
brand.ease_function,
brand.duration,
SplashTextColorLens {
start: brand.tint.with_a(0.),
end: brand.tint,
},
)
.with_repeat_strategy(RepeatStrategy::MirroredRepeat)
.with_repeat_count(RepeatCount::Finite(2))
.with_completed_event(i as u64),
),
With repeat sequence, Any suggestions?
And if you know how I can make a lens for the BackgroundColor it would help me a lot
Solved
# Cargo.toml
[patch.crates-io]
bevy_tweening = { git = "https://github.com/sibsibsib/bevy_tweening", branch = "mirrored_repeat_fix" }
This still needs help
I don't understand what you're trying to do. Do you want the delay once or repeated?
Delay one, and repeat the next tween
But is solved with this patch
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.
I have trouble to run the examples on linux. It tells me that the platform is not supported...
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
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
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?
Not sure. The existing lenses are more examples than anything else. Users are very much encouraged to write their own lenses. Although I suppose the background color (which used to be Color so was covered) being its own type and reasonably common, maybe can be an exception where the crate provides a lens out of the box.
There's a few tests using it I think.
See also this maybe? https://github.com/djeedai/bevy_tweening/blob/3c6b10e8b8745935e0bd25990924f977a1a6fb33/src/tweenable.rs#L1202
Hey,
I added a setting to always fire the tween done event (or rather a default user data value) using a settings resource).
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.
the added settings resource could also be used for the configurable timescale mentioned above.
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?
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.
My bad. I thought it would be available because the compatibility table was updated.
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.
No worries! And ty for your work!
Published yesterday evening, I'll make an announcement later but it's available already.
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.
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
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?
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.
Hmm, actually i think i agree with u here.
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));
Have you added a component system for the Velocity component?
https://github.com/djeedai/bevy_tweening#custom-component-support
Bah this was it, don't know how I missed it. Thanks!
Yeah that's a very common mistake. Not sure how we could detect it and emit a warning.
I don't think that's necessary, maybe just include a code snippet in the Custom component support section in the readme, it was my bad that I missed it since it's actually described there
How to change direction of a Tween from a system?
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 😦
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);
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.
Can you please open a bug on GitHub with more details and the code if possible? It's hard to tell just like this, I've never heard of a bug like that.
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?
The library only adds the systems for the components it provides lenses for. It can't add them all, that would be hundreds of systems. Unfortunately I don't know a generic way to fetch a component, so it has to be one system per component to tick the animators.
ahhh okay, I misinterpreted the readme then. thank you 👍
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.
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…
It is the explanation – the type of the tween is Tween<Transform> in both cases (and I have to admit that that was not what I expected 😅), so that question is solved.
can i add a custom lens for a built-in bevy component? i want to animate Text changing its font size
seems like recreating pausing from bevy_easings would be pretty hard
yes, yes, i can
wow this is super good
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
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.
(For the records: https://github.com/hmeine/zing-rs/blob/5231b361ebce94b9ca643ac75e6d6bfd5d6e572c/zing-ui-lib/src/zing_layout.rs#L512)
thanks for the link, i've yet to use Tracks. now to figure out how to use Delay
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
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.
Label enum for the systems relating to animations
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.
Ok, thanks. In the meantime I cleaned that up, and it is now more elegant and not much more code, indeed.
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.
the tweening should be absolute - aren't you setting the scale/overriding the scale/tween someplace else?
btw. you can use Vec3::splat(EXPLOSION_RADIUS)
https://docs.rs/bevy/latest/bevy/prelude/struct.Vec3.html#method.splat
to replace Vec3::new(EXPLOSION_RADIUS, EXPLOSION_RADIUS, EXPLOSION_RADIUS)
A 3-dimensional vector.
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.
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)
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
If you remove the sprite before the animation end time then yes indeed the "final" size at the time you remove is less than the tween endpoint, and depends on the easing curve.
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.
Glad it worked
i wonder if there's a way to tween/interpolate camera's projection fov. i tried this https://pastebin.com/qZZMhEnH and it doesn't work
Have you scheduled the animator system component_animator_system::<Projection> ?
https://github.com/djeedai/bevy_tweening#custom-component-support
i have not. i thought it's not needed if i'm working with bevy's components. i will give that a try
The custom part of the readme is a bit of a misnomer - looking at the plugin only the components for the provided lenses are added.
https://github.com/djeedai/bevy_tweening/blob/main/src/plugin.rs#L42
@eager trout Maybe that description could be updated a little to reflect this?
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.
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
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..
Let me know if you get oxidized_navigation! I'm using it as well and the github page seems a big, eh, dead 😅
bevy_tweening is up to date now
Didn't announce yet but published a release yesterday
Announced on #crates now
So I wanna run a one-shot system when a tween completes (without relying on events). Is this doable?
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?
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.
Right, but ignoring one-shot systems for a moment...is there an example showing how i might use any commands inside the callback? Currently the borrow checker doesnt let me. Im kinda new to rust tho so maybe i missed something with how closures work.
If you want access to some Bevy stuffs, you probably need a system, and so you should use events instead of the callback. See the sequence.rs example: https://github.com/djeedai/bevy_tweening/blob/5f06069926548027600e69b35f57896ea6ab6d12/examples/sequence.rs#L138C14-L138C34
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?
Yes, that seems to make sense.
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.
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.
Fair, perhaps some doc notes that only rgba is accepted should be in order. And I agree lerping colors makes little sense in some formats
Could you please open a GitHub item about it? Thanks
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
My gut feeling would be the shortest path rotation is kicking in? See if this doc paragraph helps:
https://docs.rs/bevy_tweening/latest/bevy_tweening/lens/index.html#rotations
Collection of predefined lenses for common Bevy components and assets.
It seems to have been related to switching the projection with too high FoV? Not sure, using default settings for the perspective projection fixed the issue
Sorry i can’t provide a better answer 
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.
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 ?
See https://github.com/djeedai/bevy_tweening/issues/8, https://github.com/djeedai/bevy_tweening/issues/16, and https://github.com/djeedai/bevy_tweening/issues/79. There's a fundamental design question which blocks any implementation for this. In the meantime, just repeating the .then() seems like a good workaround, especially if that's only twice this is annoying but manageable I think.
There is literally an issue named Make Sequence loopable ... How did I miss that one ... Anyway thanks 🙂
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.
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.
does this still work when you need to tween two separate components?
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
Huh, hold on..
Oh yeah that makes sense. It specifically wants T: Component. So we couldnt do that
Tracks should work fine as long as u dont want it to repeat forever (or at all?)
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
Well let me know what error or other obstacle u run into and I might be able to help
Tracks take a T: Component and doesn't like when I use two i believe
yeah I forgot how i got around this, but i remember running into this before
i would hugely appreciate the solution
because my other solution was just manually updating the transform part myself lmao
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 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.
Oh interesting, let me try it out
I think my case was more annoying than that because they were both using Transform.
it works!!! ily so much u are my savior and i would do anything to repay you
in that case a custom lens would be a simple fix i think
Im glad it works! haha, np 🙂
or a track
Nope, because I wanted to loop them. A track would have worked if I wanted a oneshot animation.
hence the custom lens
yeah, then probably would need lens
i feel this should really be documented
Yeah there are a few situations that should be documented imo.
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 🥲
I imagine u had to explain this a million times already 🥲 I am also very much looking forward to dynamic queries, as it makes the embedded scripting story way better.
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.
Tbh im using it for all my animations right now, waiting for a reason to stop as I have not been developing for long, lol
oh that makes a lot of sense, i really appreciate the transparency!
@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.
Sorry @frozen moss I was a bit busy. CI is running, I'll merge after if green. Thanks for the contribution!
No worries dude, and my pleasure. 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.
Oh and some of the tests failed, il look into it..
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.
We should be good now 🙂 Sorry im still learning but Il try to remember to run that locally before giving the green light.
That's fine, I don't mind, I also forget regularly to run locally 😉 CI is doing most of the work anyway so no bother really
How can I animate Transform its rotate_around using the bevy_tweening crate?
@willow sierra create a custom type implementing the Lens<Transform> trait, and in the implementation use rotate_around
@eager trout Any rough timeline on 0.14 support? Thanks in advance!
As usual, waiting for bevy-inspector-egui, and generally within 2 days after that or less
There's a PR up already
@rapid zinc 🍃 Bevy Tweening v0.11.0 supporting Bevy v0.14 was just released
@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 🙂
I don't understand what you're asking. What does "trigger" mean here, if not "send"?
For an observer to trigger, someone has to call commands.trigger() or trigger_targets(). Simply using an event writer wont work.
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));
}
}```
I haven't looked at observers yet sorry. Feel free to open an issue on GitHub and describe exactly what you'd like.
I'm not sure what you're trying to achieve. There's a number of unexpected things in your code. First you enumerate() but ignores the index; this is useless. Second you wrap a Tracks into a Sequence for no reason that I can think of, since the sequence will have a single element (the tracks) so the wrapping is useless I think.
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.
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.)
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.
Thanks a lot!
@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?
ColorMaterial is indeed not a component as the error is pointing out, but an asset meaning you need to use AssetAnimator 😉 .
Keep in mind it's gonna mutate the material, so if it's shared between entities, then all of those are gonna change colour.
BTW. all the listed features are on by default.
Oh so the type of animator i was using was wrong. Gotcha. Thanks!
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.
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.
I just conceded to querying the current value and setting it as the start value. Would be cool if the lenses worked like that tho. I almost always want the animation to start from where it currently is, not to jump to something else. Another thing the crate could possibly do is animate to the start instead of just jumping there. I feel like the way it works now is the worst option.
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.
I think Tracks might be useful for that, but I've never used that, so I might be wrong there.
https://docs.rs/bevy_tweening/latest/bevy_tweening/struct.Tracks.html
A collection of Tweenable executing in parallel.
I do that in my fork, I just never got around to making a PR for that 😅 (The lens then sets the start value during the start callback)
i MIGHT be wrong here, but i dont think it works if the same component is being changed? I remember running into a foot gun using tracks but i forgot the details 😅
oh i need to look into that 🙂
here're some lenses
most of them are created using macros, sry about that 🙂
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.
The animator and all its tweenables work on a single component. Obviously though if you have tracks touching the same field (e.g. translation) they will overwrite each other. But otherwise it should work
I guess it depends what you animate. Most tweenings on e.g. UI have well defined positions so you know the start. If you use it instead to animate dynamic entities with a world position, then yes probably you want to avoid jumps
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
Ah, in that case the start wouldnt be used by default? Maybe the start can be an option, so if its None u can just ignore it?
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
I've been rereading this part a couple times and I'm afraid I don't get the point.
Why is the time shared? Isn't it t0=some duration + t1=diff duration?
Each tween would have an absolute end position and the transform should hit the final position at t1=0 whether the start position is set at tween creation or tween start.
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
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.
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.
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
You first u need to get the handle for the material, then u can call get_mut() on ResMut<Assets<MyMaterial>> with the handle to change the params. I am not aware of an alternative method.
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
With Rust's type system i dont see another way, so ur definitely not wrong in doing it that way.
No. But I hope that from 0.15 we have all the tools to do exactly that internally so you don't have to as a user. My goal is to try and remove the component type generic from Animator, make it untyped.
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.
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.
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.
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.
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!
This will release in the upcoming v0.14, and there's a migration guide for it here : https://github.com/djeedai/bevy_tweening/blob/main/docs/migration-guide-0.14.md
@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
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.
did you have time to look into this?
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.
@eager trout awesome, i switched to your main branch and using UiTransformScaleLens works! thank you!
Now only TransformRotationLens equivalent for UiTransform is missing.
@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?
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!
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)?
Yeah, theres an example somewhere that does this but basically u put it inside a Sequence first.
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.
Oh but I tried using a sequence but it doesn’t work when you work with two different components
U mean 2 different lenses? I was able to get different lenses to work, that shouldnt be an issue.
Could be, but I think it gave me an error saying component not sure now though
Hmm, well tbh im not an expert with this crate (still getting a hang of the new API changes) but if u post the code here with the error, im sure someone will help eventually.
It was a TODO error when trying to sequence different components something like that
Yeah maybe, so far to fix it kinda I just created a different entity to use to target the other entity.
https://github.com/djeedai/bevy_tweening/blob/8df9dadd25dd10b03d3543713aba9ab6dbcfa31a/examples/sequence.rs#L157 this is the example i found today that helped me get parallel animations to work