Efeitos de easing são cruciais para criar animações fluidas e naturais, simulando a forma como os objetos interagem e se movem no mundo real. Embora frameworks como WPF ofereçam um conjunto robusto de funções de easing pré-definidas, a compreensão das fórmulas matemáticas subjacentes permite a implementação desses efeitos em qualquer ambiente de desenvolvimento, como em aplicações C# sem a necessidade do WPF.
Este artigo detalha as fórmulas matemáticas para diversos efeitos de easing e demonstra como implementá-los em C#. O objetivo é fornecer uma base para criar animações mais expressivas e intuitivas, comparando os resultados com as implementações padrão quando possível.
Fórmulas e Implementações de Easing
A animação pode ser vista como uma variação na velocidade de um objeto ao longo do tempo. A relação entre o tempo e a distância percorrida define a curva de animação. Curvas mais íngremes indicam maior velocidade, enquanto curvas mais suaves indicam menor velocidade. As fórmulas de easing nos fornecem o valor de 'distância' (normalizado entre 0 e 1) em um determinado 'tempo' (também normalizado entre 0 e 1).
As fórmulas apresentadas operam em um intervalo de tempo de 0 a 1. Para aplicar a uma animação com duração específica (por exemplo, 2000ms), um ponto no tempo 't' (em ms) seria representado como t / 2000 na fórmula.
1. Back
O efeito Back 'empurra' o objeto ligeiramente para trás antes de começar a animação, dando uma sensação de antecipação ou inércia.
Fórmula em C#
public enum EaseMode { EaseIn, EaseOut, EaseInOut }
public static class EasingFunctions
{
private const double BackFactor = 1.70158;
public static double Back(double time, EaseMode mode)
{
switch (mode)
{
case EaseMode.EaseIn:
return time * time * ((BackFactor + 1) * time - BackFactor);
case EaseMode.EaseOut:
return 1 + time * time * ((BackFactor + 1) * (time - 1) + BackFactor);
case EaseMode.EaseInOut:
return time < 0.5
? time * time * (2 * (BackFactor + 1) * time - BackFactor) * 2
: 1 + (time - 1) * (time - 1) * ((BackFactor + 1) * (time - 1) + BackFactor) * 2;
default:
return time;
}
}
}
2. Bounce
O efeito Bounce simula um objeto quicando, perdendo energia a cada quique até parar.
Fórmula em C#
private static double BounceOutImpl(double time)
{
time /= 1.0;
if (time < 1 / 2.75) return 7.5625 * time * time;
if (time < 2 / 2.75) return 7.5625 * (time -= 1.5 / 2.75) * time + 0.75;
if (time < 2.5 / 2.75) return 7.5625 * (time -= 2.25 / 2.75) * time + 0.9375;
return 7.5625 * (time -= 2.625 / 2.75) * time + 0.984375;
}
public static double Bounce(double time, EaseMode mode)
{
switch (mode)
{
case EaseMode.EaseIn:
return 1 - BounceOutImpl(1 - time);
case EaseMode.EaseOut:
return BounceOutImpl(time);
case EaseMode.EaseInOut:
return time < 0.5
? (1 - BounceOutImpl(1 - 2 * time)) / 2
: (1 + BounceOutImpl(2 * time - 1)) / 2;
default:
return time;
}
}
3. Circle
O efeito Circle cria um movimento que se acelera e desacelera suavemente, semelhante a um arco de círculo.
Fórmula em C#
public static double Circle(double time, EaseMode mode)
{
switch (mode)
{
case EaseMode.EaseIn:
return 1 - Math.Sqrt(1 - time * time);
case EaseMode.EaseOut:
return Math.Sqrt(1 - (time - 1) * (time - 1));
case EaseMode.EaseInOut:
return time < 0.5
? (1 - Math.Sqrt(1 - (2 * time) * (2 * time))) / 2
: (Math.Sqrt(1 - (-2 * time + 2) * (-2 * time + 2)) + 1) / 2;
default:
return time;
}
}
4. Power (Quadratic, Cubic, Quartic, Quintic)
Estes efeitos generalizam a aceleração baseada em potências. O Quadratic usa tempo2, Cubic usa tempo3, Quartic usa tempo4 e Quintic usa tempo5.
Fórmula em C#
public static double Power(double time, EaseMode mode, int power)
{
switch (mode)
{
case EaseMode.EaseIn:
return Math.Pow(time, power);
case EaseMode.EaseOut:
return 1 - Math.Pow(1 - time, power);
case EaseMode.EaseInOut:
return time < 0.5
? Math.Pow(2, power - 1) * Math.Pow(time, power)
: 1 - Math.Pow(-2 * time + 2, power) / 2;
default:
return time;
}
}
public static double Quadratic(double time, EaseMode mode) => Power(time, mode, 2);
public static double Cubic(double time, EaseMode mode) => Power(time, mode, 3);
public static double Quartic(double time, EaseMode mode) => Power(time, mode, 4);
public static double Quintic(double time, EaseMode mode) => Power(time, mode, 5);
5. Elastic
O efeito Elastic simula uma mola, esticando e voltando com oscilações amortecidas.
Fórmula em C#
public static double Elastic(double time, EaseMode mode)
{
const double PI = Math.PI;
const double HalfPI = PI / 2.0;
const double TwoPI = PI * 2.0;
const double ElasticA = 0.3; // Amplitude (influencia o quão "esticado" é)
const double ElasticP = ElasticA / 4.0; // Período (influencia a frequência)
switch (mode)
{
case EaseMode.EaseIn:
if (time == 0) return 0;
if (time == 1) return 1;
return -Math.Pow(2, 10 * (time -= 1)) * Math.Sin((time - ElasticP) * TwoPI / ElasticA);
case EaseMode.EaseOut:
if (time == 0) return 0;
if (time == 1) return 1;
return Math.Pow(2, -10 * time) * Math.Sin((time - ElasticP) * TwoPI / ElasticA) + 1;
case EaseMode.EaseInOut:
if (time == 0) return 0;
if (time == 1) return 1;
time /= 0.5;
if (time < 1)
{
return -0.5 * (Math.Pow(2, 10 * (time -= 1)) * Math.Sin((time - ElasticP) * TwoPI / ElasticA));
}
return 0.5 * Math.Pow(2, -10 * (time -= 1)) * Math.Sin((time - ElasticP) * TwoPI / ElasticA) + 1;
default:
return time;
}
}
6. Exponential
O efeito Exponential cresce ou decresce exponencialmente, criando uma aceleração ou desaceleração muito rápida.
Fórmula em C#
public static double Exponential(double time, EaseMode mode)
{
switch (mode)
{
case EaseMode.EaseIn:
return time == 0 ? 0 : Math.Pow(2, 10 * time - 10);
case EaseMode.EaseOut:
return time == 1 ? 1 : 1 - Math.Pow(2, -10 * time);
case EaseMode.EaseInOut:
if (time == 0) return 0;
if (time == 1) return 1;
return time < 0.5
? Math.Pow(2, 20 * time - 10) / 2
: (2 - Math.Pow(2, -20 * time + 10)) / 2;
default:
return time;
}
}
7. Sine
O efeito Sine utiliza a função seno para criar uma curva de aceleração e desaceleração suave e ondulante.
Fórmula em C#
public static double Sine(double time, EaseMode mode)
{
const double PI = Math.PI;
switch (mode)
{
case EaseMode.EaseIn:
return 1 - Math.Cos((time * PI) / 2);
case EaseMode.EaseOut:
return Math.Sin((time * PI) / 2);
case EaseMode.EaseInOut:
return -(Math.Cos(PI * time) - 1) / 2;
default:
return time;
}
}
É importante notar que a fidelidade exata de alguns efeitos, como Bounce e Elastic, pode variar ligeiramente dependendo da implementação de referência. As fórmulas aqui apresentadas são baseadas em implementações comuns e bem estabelecidas, visando replicar a essência desses comportamentos.