I\'m trying to emulate an animation effect in code (almost any language would do as it appears to be math rather than language). Essentially, it is the emulation of a mass-sprin
I was thinking along the same lines as @tom10. (I also considered an IEasingFunction
which took an IList
, but it would be tricky to hack the desired behaviour out of the existing ones).
// Based on the example at
// http://msdn.microsoft.com/en-us/library/system.windows.media.animation.easingfunctionbase.aspx
namespace Org.CheddarMonk
{
public class OtakuEasingFunction : EasingFunctionBase
{
// The time proportion at which the cutoff from linear movement to
// bounce occurs. E.g. for a 4 second movement followed by a 16
// second bounce this would be 4 / (4 + 16) = 0.2.
private double _CutoffPoint;
public double CutoffPoint {
get { return _CutoffPoint; }
set {
if (value <= 0 || value => 1 || double.IsNaN(value)) {
throw new ArgumentException();
}
_CutoffPoint = value;
}
}
// The size of the initial bounce envelope, as a proportion of the
// animation distance. E.g. if the animation moves from 900 to 150
// and you want the maximum bounce to be no more than 35 you would
// set this to 35 / (900 - 150) ~= 0.0467.
private double _EnvelopeHeight;
public double EnvelopeHeight {
get { return _EnvelopeHeight; }
set {
if (value <= 0 || double.IsNaN(value)) {
throw new ArgumentException();
}
_EnvelopeHeight = value;
}
}
// A parameter controlling how fast the bounce height should decay.
// The higher the decay, the sooner the bounce becomes negligible.
private double _EnvelopeDecay;
public double EnvelopeDecay {
get { return _EnvelopeDecay; }
set {
if (value <= 0 || double.IsNaN(value)) {
throw new ArgumentException();
}
_EnvelopeDecay = value;
}
}
// The number of half-bounces.
private int _Oscillations;
public int Oscillations {
get { return _Oscillations; }
set {
if (value <= 0) {
throw new ArgumentException();
}
_Oscillations = value;
}
}
public OtakuEasingFunction() {
// Sensible default values.
CutoffPoint = 0.7;
EnvelopeHeight = 0.3;
EnvelopeDecay = 1;
Oscillations = 3;
}
protected override double EaseInCore(double normalizedTime) {
// If we get an out-of-bounds value, be nice.
if (normalizedTime < 0) return 0;
if (normalizedTime > 1) return 1;
if (normalizedTime < _CutoffPoint) {
return normalizedTime / _CutoffPoint;
}
// Renormalise the time.
double t = (normalizedTime - _CutoffPoint) / (1 - _CutoffPoint);
double envelope = EnvelopeHeight * Math.Exp(-t * EnvelopeDecay);
double bounce = Math.Sin(t * Oscillations * Math.PI);
return envelope * bounce;
}
protected override Freezable CreateInstanceCore() {
return new OtakuEasingFunction();
}
}
}
This is untested code, but it shouldn't be too bad to debug if there are problems. I'm not sure what attributes (if any) need to be added to the properties for the XAML editor to handle them properly.