L'objectif d'une première fonction appelée Exponant était de renvoyer une valeur entre AStart et AEnd modifiée par la puissance AExp utilisée. Quelle que soit la valeur de AExp, nous obtenions une valeur comprise entre 0 et (AEnd - AStart).
Par exemple, si la puissance valait 1, nous étions en présence d'une progression linéaire : en effet, la différence entre AStart et AEnd était alors multipliée par le pas à la puissance 1 (elle était donc inchangée) puis divisée par 100 à la même puissance (donc par 100 inchangé encore une fois). Vous aurez reconnu la formule qui permet de calculer le simple pourcentage d'une valeur ! Pour des puissances supérieures à 1, nous nous retrouvions dans les cas étudiés dans le billet précédent.
Pseudo-code :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | AStart entier (valeur initiale de l'interpolation) AEnd entier (valeur finale de l'interpolation) AStep entier (pas/étape en cours) fonction Exponant paramètre en entrée : AExp entier sortie : Result entier Result = Valeur arrondie de (AStart - AEnd) multipliée par (AStep à la puissance AExp) divisée par (100 à la puissance AExp) |
Code delphi : | Sélectionner tout |
1 2 3 4 | function Exponant(AExp: Byte): Integer; begin Result := Round((AEnd - AStart) * Power(AStep, AExp) / Power(100, AExp)); end; |
Une autre fonction nommée DownExponant permettait de donner l'illusion d'un ralentissement. Pour cela, il suffisait d'inverser les calculs de l'accélération positive par deux soustractions. En partant de (AEnd - AStart), nous arrivions progressivement à 0 :
Code delphi : | Sélectionner tout |
1 2 3 4 | function DownExponant(AExp: Byte): Integer; begin Result := AEnd - AStart - Round((AEnd - AStart) * Power(100 - AStep, AExp) / Power(100, AExp)); end; |
Ces deux fonctions formaient la base des fonctions d'interpolation utilisées dont l'écriture se trouvait grandement simplifiée.
Les fonctions d'interpolation étaient elles-mêmes définies dans une énumération :
Code delphi : | Sélectionner tout |
1 2 3 4 5 | type TInterpolation = (intLinear, intQuadratic, intCubic, intQuartic, intQuintic, intSinus, intSpring, intExpo, intSqrt, intSlowDownQuadratic, intSlowDownCubic, intSlowDownQuartic, intSlowDownQuintic, intBounceCos, intStepsCos); |
Enfin, elles étaient traitées dans une méthode dont la structure comportait essentiellement un case of (choix...parmi) :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | function ComputeInterpolation(AStart, AEnd: Integer; AStep: Integer; AInter: TInterpolation; ABack: Boolean): Integer; // *** calcul des interpolations *** begin case AInter of intLinear: Result := Exponant(1); intQuadratic: Result := Exponant(2); intCubic: Result := Exponant(3); intQuartic: Result := Exponant(4); intQuintic: Result := Exponant(5); // [...] intSlowDownQuadratic: Result := DownExponant(2); intSlowDownCubic: Result := DownExponant(3); intSlowDownQuartic: Result := DownExponant(4); intSlowDownQuintic: Result := DownExponant(5); // [...] end; // [...] end; |
Simplement, pour permettre un retour de AEnd vers AStart, un paramètre de type booléen ABack était utilisé à la toute fin de la même méthode :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 | intSlowDownQuintic: Result := DownExponant(5); // [...] end; if ABack then Result := AEnd - Result; end; |
D'autres fonctions ont ensuite été ajoutées pour obtenir des effets variés.
Comme nous pouvions nous y attendre, la racine carrée ou les puissances de 2 produisaient des effets proches des puissances déjà vues. Elles les modulaient seulement avec leur propre progression.
Leur emploi dans le case of s'appuyait aussi sur la fonction Exponant :
Code delphi : | Sélectionner tout |
1 2 | intExpo: Result := Round(Exponant(1) * (Power(2, AStep / 100) - 1)); intSqrt: Result := Round(Exponant(1) * (Sqrt(AStep) / 10)); |
Nous avions aussi adjoint des formules à base de fonctions trigonométriques. Leurs cycles permettaient en particulier d'envisager des effets de rebonds :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | case AInter of // [...] intSinus: Result := Round(Exponant(1) * sin(pi * AStep / 200)); intSpring: Result := Round(Exponant(1) * (Power(cos(pi * AStep / 100), 2))); // [...] intBounceCos: Result := Exponant(1) + Round((cos(AStep * pi / 100) + 1) * Exponant(1)); intStepsCos: Result := Exponant(1) + Round(Power((cos(AStep * pi / 100) + 1), 2) * 100); intCos: Result := Round(Exponant(1) * (1 - cos(AStep / 100 * pi)) / 2); intHalfCos: Result := Round(Exponant(1) * ((1 - cos(AStep /100 * Pi)) / 4 + AStep / 200)); end; // [...] end; |
Pour le moment, contentons-nous d'avoir un aperçu de ce que produisaient ces interpolations appliquées à de simples boutons :
Ce billet n'a fait que rappeler les outils créés de manière empirique pour l'écriture d'un composant particulier. Cependant, il montre qu'avec peu de moyens, nous pouvons créer des animations déjà sympathiques et variées.
Par la suite, il s'agira de formaliser cette approche en la rendant compatible avec celle qu'offrent CSS ou JavaScript par exemple (souvent via des bibliothèques complémentaires). A très bientôt !