Search Unity

Scaling AnimationCurve X value

Discussion in 'Scripting' started by Digital_Seven, Apr 22, 2020.

  1. Digital_Seven

    Digital_Seven

    Joined:
    Aug 20, 2015
    Posts:
    15
    So I've got a bit of a difficult math problem I need some help with.

    I have a character's attack broken up into 3 animations. Anticipation, Connect, Recovery. I'm using animation params to modify the speed of each animation to match the tuning for the character.

    For example. A simple enemy has 0.8 on Anticipation and 0.5 on Connect. This slows down the animations so the player has time to react when the enemy uses the attack. This is shared with the player, but the player's animations are unscaled.

    Now I have a script that is moving my character forward over the duration of the whole animation. For my player this is 0.583s and for the enemy, it's 0.741s.

    Now the problem comes in because I'm using an animation curve to move my characters over time. A simple curve.Evaluate(time/duration) makes the enemy move at inappropriate times when synced with the animation. This is because the animation times are not uniformly scaled, as the players are.

    I'd like to use the same curve for the player and the enemy so avoid having a couple of dozen curves to update when tuning changes.

    I could solve this is multiple curves, as I could then assume a uniform scale per animation, but again if a perfect world I'm able to create a formula for the curve.Evaluate function that will yield the desired results.

    So, I'm looking for help with the equation. curve.Evalaute(getScaledX)

    I've attached an image as I feel it might help illustrate the problem better than my words.

    The scale is not uniform. The end of the Connect animation for the player is ~39.96% of the total animation time whereas the end of the Connect animation for the player represents ~52.76% of the animations.

    I'd like the characters to move forward the correct amount, at the correct time to match my character's "step" animations.

    Animation Synbc with curve.jpg
     
    Last edited: Apr 22, 2020
  2. Digital_Seven

    Digital_Seven

    Joined:
    Aug 20, 2015
    Posts:
    15
    I've updated my post, to be more clear... I hope
     
  3. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    One thing that may be helpful is taking advantage of the fact that you can animate ANY serialized value with an AnimationClip. Specifically, you might have a value named animDuration on your script which on your animation has a single keyframe in each animation, set to 0.583 in one animation or 0.741 in the other in your examples. Or, you might have a value named animProgress that animates from 0 to 1 across the course of each animation.

    It's worth considering that the normal way this "syncing movement with animation" issue is resolved in animation is through root motion. If you have a specific reason not to use root motion fair enough, but if you just haven't heard about it, look it up.
     
  4. Digital_Seven

    Digital_Seven

    Joined:
    Aug 20, 2015
    Posts:
    15
    My current toolset doesn't seem to allow root motion. the movement controlled by another script. With root motion enabled the mesh moves around but the controller and colliders don't.
     
  5. Digital_Seven

    Digital_Seven

    Joined:
    Aug 20, 2015
    Posts:
    15
    I solved the problem.

    The solution was to treat the scaled timeline in segments as if they weren't scaled at all. Then offset for the time since the start of the animation lets you get the correct point in the curve. Assuming, of course, the curve is from 0-1 on the x scale

    Code (CSharp):
    1.  
    2.            
    3. float unscaledAnticipation = 0.1f;
    4. float unscaledConnect = 0.133f;
    5. float unscaledRecovery = 0.35f;
    6. float unscaledTotal = unscaledAnticipation + unscaledConnect + unscaledRecovery;
    7.  
    8. float scaledAnticipation = 0.125f;
    9. float scaledConnect = 0.266f;
    10. float scaledRecovery = 0.35f;
    11.  
    12. float percentOfAnticipation = unscaledAnticipation / unscaledTotal;
    13. float percentConnect = unscaledConnect / unscaledTotal;
    14. float percentRecovery = unscaledRecovery / unscaledTotal;
    15.  
    16. var percentCompleteThisSegment = 0f;
    17. var sampleCurvePoint = 0f;
    18.  
    19. if (TimeSinceStart <= scaledAnticipation)
    20. {
    21.     percentCompleteThisSegment = TimeSinceStart / scaledAnticipation;
    22.     sampleCurvePoint = percentCompleteThisSegment * percentOfAnticipation;
    23. }
    24. else if (TimeSinceStart <= (scaledAnticipation + scaledConnect))
    25. {
    26.     percentCompleteThisSegment = (TimeSinceStart - scaledAnticipation) / scaledConnect;
    27.     sampleCurvePoint = (percentCompleteThisSegment * percentConnect) + percentOfAnticipation;
    28. }
    29. else
    30. {
    31.     percentCompleteThisSegment = (TimeSinceStart - (scaledAnticipation + scaledConnect)) / scaledRecovery;
    32.     sampleCurvePoint = (percentCompleteThisSegment * percentRecovery) + (percentOfAnticipation + percentConnect);
    33. }
    34.  
    35. AnimationCurve.Evaluate(sampleCurvePoint);
    36.