Implementando Efeitos de Easing em C# com Base em Fórmulas Matemáticas

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.

Tags: C# Animação easing fórmulas matemáticas efeitos visuais

Publicado em 7-13 14:07