Расскажу одну историю, которая приключилась со мной недавно. Если говорить "с начала", тогда стоит упомянуть, что недавно я познакомился с tween'ингом во flash. Понравились удобство, красота и прозрачность исполнения. Захотелось чего-то подобного в Delphi. Мне подсказали, что существует вот этот проект, в котором добрый человек как раз и реализовал анимацию между заданными значениями. Супер! О чем еще мечтать?! Но меня оттолкнули следующие вещи:
|
class function TAnimateEasing.elasticEaseOut(p: Extended; firstNum: integer; diff: integer): Extended; var c, period, s, amplitude: Extended; begin c := diff; if diff = 0 then Exit(c); //Divide by zero protect if p = 0 then Exit(firstNum); if p = 1 then Exit(c); period := 0.25; amplitude := c; if (amplitude < abs(c)) then begin amplitude := c; s := period / 4; end else begin s := period/(2*PI) * Math.ArcSin(c/amplitude); end; result := -(amplitude*Math.Power(2, -10*p) * sin( (p*1-s)*(2*PI)/period)) + c + firstNum; end;
и начал копировать по частям к себе. И здесь для всяких копи-пастеров заготовлена бомба! Если бы я бездумно копировал код из Интернета, то попался бы на вот какие расставленные капканы:
- при выполнении первого условия возвращается неверное значение (нужно вернуть firstNum)
- третье условие также возвращает неверное значение (нужно вернуть diff + firstNum)
- идем по коду дальше: мы сначала присваиваем amplitude := c; а потом при выполнении условия делаем это еще раз, зачем?
- если последнее условие не выполняется, тогда мы присваиваем s := period/(2*PI) * Math.ArcSin(c/amplitude); но ведь чуть раньше мы указали amplitude := c; получается, под арксинусом у нас единица, а результат такого арксинуса равен PI/2, итого присвоение сводится к s := period / 4; так зачем нам вообще условие if-then-else? неясно...
В итоге в моем модуле этот код сократился до такого:
class function TBaseEasingFunctions.elasticEaseIn(aStartValue, aDiffValue, aUnitValue: Single): Single; begin if (aDiffValue = 0) or (aUnitValue = 0) or (aUnitValue = 1) then begin if (aDiffValue = 0) then result := aStartValue; //Divide by zero protect if (aUnitValue = 0) then result := aStartValue; if (aUnitValue = 1) then result := aStartValue + aDiffValue; exit; end; result := (aDiffValue * Power(2, -10 * aUnitValue) * Sin((aUnitValue - 0.25/4)*(2*3.14)/0.25)) + aDiffValue + aStartValue; end;
Без ошибок, удобней читать, выше производительность и вообще все здорово...
Остальные функции пока не переводил к себе, так как tween'инг elasticEaseIn самый широкоиспользуемый и я начал именно с него. Так что наше дело движется...В общем, осталось собрать демку с анимационными движениями, описать здесь и выложить на всеобщее обозрение! Как вам такая идея?