-
Notifications
You must be signed in to change notification settings - Fork 80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Better animation system #834
Comments
overall good idea, fully support; just a few points:
|
Yes there would be some kind of generic version for doing arbitrary animations, as well as extension methods on common Celeste/Monocle types as shown in that example. Also considering a reflection or DynamicData variant that will just animate any property of any object. The XML could put object names on the animation targets, and then you assign those in the Animator before playing.
|
As posted in Discord: https://discord.com/channels/403698615446536203/429775439423209472/1297904964932337738 // create an animation clip in code, this could also be GFX.AnimationBank["foo"].Create();
clip = AnimationBuilder.Instance
.Add(new LerpAnimation<float>((v, _) => LineLength = v, 0f, 1f, 0.5f, Ease.CubeOut))
.DelayAdd(0.5f, new LerpAnimation<float>((v, _) => LineLength = v, 1f, 0f, 1f, Ease.BounceOut))
.BuildClip();
// triggered on key press, "true" means autoplay
Add(new Animator(clip, true));
// (and some rendering code based on LineLength) |
This is a rough example of how I'd expect an <animations>
<!--
// Animate an arbitrary property using DynamicData
var player = Scene.Tracker.GetEntity<Player>();
var clip = AnimationBuilder.Instance
.Add(new LerpPropertyAnimation<Vector2>(player, nameof(Player.Position), new Vector2(100, 100), new Vector2(200, 200), 2))
.BuildClip();
// Results in:
// 0.....1.....2
// |position...|
-->
<propertyExample>
<!-- Define the targets the Animator should accept -->
<target name="player" />
<!-- Animations -->
<property target="player" property="Position" from="100,100" to="200,200" duration="2" />
</propertyExample>
<!--
// Animate using named helper extensions for supported targets
var player = Scene.Tracker.GetEntity<Player>();
var sprite = player.Sprite;
var clip = AnimationBuilder.Instance
.Add(player.AnimatePosition(new Vector2(100, 100), new Vector2(200, 200), 2))
.DelayAdd(1f, sprite.AnimateScale(new Vector2(1, 1), new Vector2(2, 2), 1))
.BuildClip();
// Results in:
// 0.....1.....2.....3.....4
// |position...| |scale|
-->
<extensionsExample>
<!-- Define the targets the Animator should accept -->
<target name="player" />
<target name="sprite" />
<!-- Animations default to series if a top-level group is not specified -->
<position target="player" from="100,100" to="200,200" duration="2" />
<scale target="sprite" from="1,1" to="2,2" duration="1" delay="1" />
</extensionsExample>
<!--
// More complex example
var player = Scene.Tracker.GetEntity<Player>();
var sprite = player.Sprite;
var clip = AnimationBuilder.Instance
.PushParallel()
.DelayAdd(1f, sprite.AnimateScale(new Vector2(1, 1), new Vector2(2, 2), 4f))
.PushSeries()
.Add(player.AnimatePosition(new Vector2(100, 100), new Vector2(100, 200), 3f))
.DelayAdd(1f, player.AnimatePosition(new Vector2(100, 200), new Vector2(100, 300), 1f))
.Pop()
.Pop()
.BuildClip();
// Results in:
// 0.....1.....2.....3.....4.....5
// |scale..................|
// |pos1.............| |pos2.|
-->
<complexExample>
<!-- Define the targets the Animator should accept -->
<target name="player" />
<target name="sprite" />
<!-- Animations -->
<parallel>
<scale target="sprite" from="1,1" to="2,2" duration="4" delay="1" />
<series>
<position target="player" from="100,100" to="100,200" duration="3" />
<position target="player" from="100,200" to="100,300" duration="1" delay="1" />
</series>
</parallel>
</complexExample>
<!--
// executing the above
var clip = GFX.AnimationBank["complexExample"].Create();
var animator = new Animator(clip);
var player = Scene.Tracker.GetEntity<Player>();
animator.Targets["player"] = player;
animator.Targets["sprite"] = player.Sprite;
Add(animator);
animator.Rate = 0.5f; // run at half speed
animator.Play();
// example of waiting for animation to finish in a coroutine
while (animator.Playing) yield return null;
-->
</animations> |
I've been looking through Unity's AnimationClips for some inspiration, and their clips are essentially a serial group per property of a single target object (or its children), all running in parallel. I'm trying to think of a way to cleanly introduce this in code, as well as having the ability to do arbitrary lambda tweens. This is what I'm currently thinking: XML:
<animations>
<myclip duration="4">
<!-- simple curves, most common ones that people will use -->
<position target="player" offset="0" duration="2" from="0,0" to="100,100" easer="cubeout" />
<scale target="sprite" offset="1" duration="3" from="1,1" to="2,2" easer="elasticout" />
<!-- advanced curve, most people will never use but it's cool -->
<property target="sprite" name="rotation" offset="0" duration="4">
<keyframe time="0" value="0" easer="cubeout" />
<keyframe time="0.25" value="180" easer="linear" />
<keyframe time="0.5" value="0" easer="elasticout" />
<keyframe time="1" value="360" />
</property>
</myclip>
</animations> Runtime:
Player player = Scene.Tracker.GetEntity<Player>();
AnimationClip clip = GFX.AnimationBank["myclip"].Create();
Animator animator = new Animator(clip);
animator.AddCurve(0, 4, Ease.BounceOut, t => { /* do something with t, which will be (0-1) */ });
animator.SetTarget("player", player);
animator.SetTarget("sprite", player.Sprite);
animator.Rate = 2f;
Add(animator); This should cover most cases I think, and leave it open enough without the complexity of animation groups. A builder class would be unnecessary since the coder can just write a bunch of animator.SetTarget("player", () => Scene.Tracker.GetEntity<Player>()); |
I am planning on implementing this myself
Yes
Describe your request
The
Tween
class is nice and all, but it would be great to have a Unity-styleAnimationClip
containing multiple tweens with the option for rewinding, etc.My rough idea is to have a builder that creates animation clips, but these could also be defined in XML for reuse and performance.
Example of what a programmatic version could potentially look like:
Creates the following animations:
And executes them over 5 seconds like so:
Additional context
No response
The text was updated successfully, but these errors were encountered: