Search Unity

Can I override keyframe values from code?

Discussion in 'Animation' started by ScytheNM, Jul 31, 2014.

  1. ScytheNM

    ScytheNM

    Joined:
    Jul 15, 2014
    Posts:
    3
    Hello!

    I am trying to figure out if I can do the following:

    I want to set up an animation that has special keyframes whose values I could then override from code.

    As an example let's say I've got a sprite jump animation so I animate the transform so the Y = 1 at the peak of the jump.

    Now let's say I want to use this animation on other sprites too but I want to vary the height of the jump.

    What I am trying to do is write a little component where I can define a keyframe to be overriden in the editor and a value to override it with and then at component initialisation do that override on the specific animation defined by this component.

    I've been looking at the documentation and this feels like it should be possible as based on this it looks like you can index to keyframes on curves and get to their value from code

    http://docs.unity3d.com/ScriptReference/Keyframe-value.html

    But that's as far as I am getting. Not sure how I can reference a specific animation track (or curve) from code or better yet meaningfully expose it in the inspector.

    Has anyone done something like this and have you got any suggestions to share?

    Many thanks!
     
    seul_kk131 likes this.
  2. TMPxyz

    TMPxyz

    Joined:
    Jul 20, 2012
    Posts:
    766
  3. ScytheNM

    ScytheNM

    Joined:
    Jul 15, 2014
    Posts:
    3
    Thanks TMPxyz. Yup, that's the thread I have mostly been following too whilst trying to get this to work.

    I actually got it some portion of the way there but not all the way sadly and I actually don't think it's possible now based on my experience.

    Based on what I've been seeing, it seems to be impossible to modify the "in memory" animation curve. After some effort I did manage to override keyframes on a curve but what seems to be happening at least in my case is that I am actually editing the "source" animation clip. Which is no good obviously as I need that to be left untouched as that is supposed to act as a template (almost as a base class animation) so that it can be overriden from individual gameobjects that need to use/override it. So what happens now is that if I have a key that is let's say Y=1 in the source anim and then I set it to Y=4, this will change in the source anim too, so anything that uses this animation will also take this change (which is not the intended behaviour).

    This actually kinda makes sense because the only way I was able to get this far is by following these steps in my code:

    - Get the animation curve using AnimationUtils.GetAllCurves() (if I remember correctly)
    - Create a new animation curve using the data from the one that contains the keyframe I am looking to override
    - Change the keyframe value in the new curve to the one I am looking to override with
    - Then completely remove the old curve and add the new one

    Seems convoluted, but any other way (including the seemingly obvious way of just doing curve[keyframe_index].value = value_override) didn't work at all (it just fails silently. What I'd see in the debugger would be the assignment just not working and curve[keyframe_index].value would continue having the same value as before the assignment...which was fun!)

    But yeah I suppose if I am doing this I am ending up editing the source animation data, rather than what I am intending to edit (which is the in memory animation data during runtime), however I just can't see of a way where you can do the latter. Which is a massive shame as it feels like exposing this kind of functionality would be a very powerful thing to be able to have access to.

    I ended up doing this in a different way, which feels a lot more hacky and not really very data driven, but I do hope long term I can either figure out how this is done in the way I was originally intending to implement it or, if it's indeed not possible, that Unity will support this one day.
     
  4. TMPxyz

    TMPxyz

    Joined:
    Jul 20, 2012
    Posts:
    766
    Hi, ScytheNM,

    Haven't done such things before, but It seems that, in order to let each sprite has different clips, it needs to create the clips at runtime.
    But as AnimationClip doesn't have runtime api to enumerate curves, it might be kind of troublesome to copy a clip .

    Just a guess,
    1. maybe you could make a copy of the jump animation and store one y-axis curve for each type of your sprite, at edit-time;
    Then in runtime you change the y-axis movement curve and call clip.SetCurve() to modify its own clip.
    Yeah, this will duplicate many clips.

    2. Or you could just break the clip into many curves, and assemble them into clips on the fly.

    P.S.:
    curve[idx] is read-only, it works like transform.position. You should use curve.keys = newCopyOfKeys,