- Home /
AnimationCurve - Provide the value to find the time?
Hi, I think the question is pretty straightforward
Is it possible to find the time of an AnimationCurve that correspond to a known value between 0 and 1 ?
Albeit there is no documented functions to do that, maybe some maths can help but I can't figure out how
Thanks
AnimationCurves are not functions. Them may be infinite, multiple, one or none positions that match your criteria. Animation curves are made up of an array of keyframes. You would need to test for your value between each pair of $$anonymous$$eyframes. The math to plot the points has been posted several times including:
http://answers.unity3d.com/questions/464782/t-is-the-math-behind-animationcurveevaluate.html
But going the opposite way could be a struggle.
As an alternate suggestion, you could evaluate the curve at many, regular points. That is evaluate 100 even 1000 points. For any two points that bracket your value, you could either assume a line between the points and calculate the approximate 't' value, or you could so a series of evaluations between the two points to refine the projection of 't'.
Note if you were going to be doing this calculation alot, it would pay to evaluate the points once and store them in an array.
ah, i see i misunderstood the question. i gave you the opposite of what you want.
Thank you for your answers. I have a better understanding of it thanks to yours robertbu.
Answer by SuperPingu · Sep 13, 2019 at 07:30 AM
Your curve need to be strictly monotonic to be able to do that. Otherwise, there could be multi times with the same value. But if it is the case and that your curve is juste piecewise line, you can reverse the curve :
static AnimationCurve ReverseCurve(AnimationCurve c)
{
// TODO: check c is strictly monotonic and Piecewise linear, log error otherwise
var rev = new AnimationCurve();
for(int i=0;i<c.keys.Length;i++) {
var kf=c.keys[i];
var rkf = new Keyframe(kf.value,kf.time);
if(kf.inTangent < 0) {
rkf.inTangent = 1/kf.outTangent;
rkf.outTangent = 1/kf.inTangent;
} else {
rkf.inTangent = 1/kf.inTangent;
rkf.outTangent = 1/kf.outTangent;
}
rev.AddKey(rkf);
}
return rev;
}
It will not work with non piecewise linear curve. In that case, I guess you'll have to use something like a simple bisection method or a fancier Newton's method. Here is the code for bisection method :
static float TimeFromValue(AnimationCurve c, float value, float precision = 1e-6f)
{
float minTime = c.keys[0].time;
float maxTime = c.keys[c.keys.Length-1].time;
float best = (maxTime + minTime) / 2;
float bestVal = c.Evaluate(best);
int it=0;
const int maxIt = 1000;
float sign = Mathf.Sign(c.keys[c.keys.Length-1].value -c.keys[0].value);
while(it < maxIt && Mathf.Abs(minTime - maxTime) > precision) {
if((bestVal - value) * sign > 0) {
maxTime = best;
} else {
minTime = best;
}
best = (maxTime + minTime) / 2;
bestVal = c.Evaluate(best);
it++;
}
return best;
}
Answer by zombience · Nov 01, 2013 at 05:06 PM
If you are using an animation curve in your script, you can just access it through the Evaluate() method.
like so:
public AnimationCurve anim;
public float curveIndex;
public float curveValue;
void Update()
{
curveIndex = Mathf.Clamp(curveIndex, 0, curve.Length);
curveValue = anim.Evaluate(curveIndex);
}
the above code will give you a value "curveValue" in the inspector that is the value of the curve at time "curveIndex".
@Zombience - he wants to go the other way...given a value, get back 't' (curveIndex);
Answer by Cod3X · Jul 10, 2015 at 08:34 AM
I had faced similar Problem, I was using the curve with 2 key frames
one starts at the 0th location of Graph
next at 20 towards y axis(Value) "20". 100,000 towards X axis(Time)
the in build API in animation curve Evaluate only based on time to value and this simple trick will help you to find the data other way around
Just loop the time and use the Evaluate until you find your desired Value.
code Example for my problem
float time = 0;
float value = 10.0f;
public AnimationCurve levelCurve;
IEnumerator RequiredTime(){
while(true){
time +=100;
var sceond = levelCurve.Evaluate(time);
if(sceond > value + 1f) {
Debug.Log(time+" the Timerequired to next level up"); break;
}
}
yield return null;
}
my value was 10 and i want to find the time taken to reach value 11. so that I can use it in my game as a feed back to player the time or progress required to reach next Stage or so.
this is just the sample code for the logic.
Answer by govladi · Apr 29 at 07:18 AM
I'm also on this topic as of now I have something that works, but feel that it's not as optimal as I'd like it to be, here is my simple code so far. (btw I have only to keys and only care about the second one so its hard coded like that feel free to change it as you need)
private int GetLevelByXP(float experience)
{
int level = 1;
for (int i = 0; i < xpReqruirmentPerLevel.keys[1].time; i++)
{
if (Expirience < xpReqruirmentPerLevel.Evaluate(i))
{
level = i;
break;
}
}
return level;
}
Your answer
Follow this Question
Related Questions
preventing animation from tweening 1 Answer
Undocumented property: Keyframe.tangentMode 3 Answers
Animating multiple 2D box colliders 1 Answer