#math #time #distance #easing-functions
#математика #время #расстояние #упрощение-функции
Вопрос:
Я пытаюсь перенести и реализовать функцию смягчения, которую я нашел
Редактировать
: Я вставил неправильную функцию смягчения, извините! Вот правильный:
Math.easeOutQuart = function (t, b, c, d) {
t /= d;
t--;
return -c * (t*t*t*t - 1) b;
};
Язык, который я использую, не является Flash или Actionscript. Вот мой код:
ease:{outquart:{function(t as float,b as float,c as float,d as float) as float
t=t/d
t=t-1
return -c * (t*t*t*t - 1) b
end function}}
Я вызываю функцию в цикле с:
EDIT2 — вызывающая функция.
m.move устанавливается равным 1 или -1 для направления перемещения или -5 5 для перемещения на 5 длин. setspritemoves вызывается как можно чаще, в настоящее время он выполняется так быстро, как только может вызвать система, но я мог бы вызвать вызов по миллисекундному таймеру.
setspritemoves:function()
if m.move=1 then
m.duration=1
if m.ishd then
for i=0 to m.spriteposx.count()-1
m.moveto[i]=m.spriteposx[i] m.move*324
next i
else
for i=0 to m.spriteposx.count()-1
m.moveto[i]=m.spriteposx[i] m.move*224
next i
end if
else if m.move=5 then
m.duration=5
if m.ishd then
for i=0 to m.spriteposx.count()-1
m.moveto[i]=m.spriteposx[i] m.move*324
next i
else
for i=0 to m.spriteposx.count()-1
m.moveto[i]=m.spriteposx[i] m.move*224
next i
end if
else if m.move=-1 then
m.duration=1
if m.ishd then
for i=0 to m.spriteposx.count()-1
m.moveto[i]=m.spriteposx[i]-m.move*324
next i
else
for i=0 to m.spriteposx.count()-1
m.moveto[i]=m.spriteposx[i]-m.move*224
next i
end if
else if m.move=-5 then
m.duration=5
if m.ishd then
for i=0 to m.spriteposx.count()-1
m.moveto[i]=m.spriteposx[i]-m.move*324
next i
else
for i=0 to m.spriteposx.count()-1
m.moveto[i]=m.spriteposx[i]-m.move*224
next i
end if
end if
end function
m.moveto [i] — это координата x назначения, m.время — это целое число, которое я увеличиваю, m. длительность — это то, что я предполагаю, это время, которое я хочу, чтобы изменение завершилось, m.spriteposx — это текущее положение объекта, который я перемещаю. [i] — текущий спрайт.
Каким должно быть значение приращения для времени, какой должна быть продолжительность, если я хочу переместить 345 пикселей за 1/2 секунды?
Во всех моих экспериментах я либо перекрываю огромный коэффициент, либо перемещаю только несколько пикселей.
в настоящее время m.время увеличивается на 1 на каждой итерации, а m.продолжительность равна 100. Я перепробовал все виды значений, и ни одно из них, похоже, не работает стабильно.
Ответ №1:
Почему вы не скопировали логику через 1-1? Tween — это простой алгоритм, он просто отображает координаты от b
до b c
в виде квадрата, то b c*t^4
есть где t
получает значения в интервале [0,1]
. Путем подстановки вы можете видеть, что, когда t=0
значение является начальным значением, b
, и поскольку t->1
позиция является требуемой b c
.
Это причина для строки t = d
, так d
что это произвольная длительность, и t
время, прошедшее с начала анимации, получает значение в вышеупомянутом диапазоне. Но вы сделали t=t-1
и приняли негативы и т. Д. Почему?
Например, переместив 345 пикселей за 0,5 с, вы получите начальную позицию, b
и c=345
предполагая, что пиксели — это единицы измерения. d=0.5
и вы разбиваете анимацию на интервалы выбранной вами длины (в зависимости от мощности машины, на которой будет выполняться анимация. Мобильные устройства не такие мощные, как настольные, поэтому вы выбираете разумную частоту кадров в данных обстоятельствах). Допустим, мы выбираем 24 кадра в секунду, поэтому мы разбиваем интервал на 0.5*24 = 12
кадры и вызываем функцию один раз каждые 1/24 секунды, каждый раз t
принимая значения 1/24, 2/24 и т.д. Если удобнее работать не в секундах, а в кадрах, то d=12
и t
принимает значения 1,2, …,12. Вычисления одинаковы в любом случае.
Вот хороший пример (щелкните по окну, чтобы запустить демонстрацию), не стесняйтесь возиться со значениями:
Комментарии:
1. Я обновил свой вопрос, чтобы показать правильную исходную функцию смягчения. Я не копировал полную логику, потому что она является частью действительно очень большой функции, полной анонимных функций, она будет занимать несколько страниц, а логика разбита на несколько частей. t = t-1 — это моя интерпретация t — в (теперь обновленной) функции выше. Я предполагаю, что мне нужно обновить position с помощью результата функции и вернуть его обратно на следующей итерации, это правда?
Ответ №2:
Функции Безье
Заимствовано из http://blog.greweb.fr/2012/02/bezier-curve-based-easing-functions-from-concept-to-implementation /
/**
* KeySpline - use bezier curve for transition easing function
* is inspired from Firefox's nsSMILKeySpline.cpp
* Usage:
* var spline = new KeySpline(0.25, 0.1, 0.25, 1.0)
* spline.get(x) => returns the easing value | x must be in [0, 1] range
*/
function KeySpline (mX1, mY1, mX2, mY2) {
this.get = function(aX) {
if (mX1 == mY1 amp;amp; mX2 == mY2) return aX; // linear
return CalcBezier(GetTForX(aX), mY1, mY2);
}
function A(aA1, aA2) { return 1.0 - 3.0 * aA2 3.0 * aA1; }
function B(aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; }
function C(aA1) { return 3.0 * aA1; }
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
function CalcBezier(aT, aA1, aA2) {
return ((A(aA1, aA2)*aT B(aA1, aA2))*aT C(aA1))*aT;
}
// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
function GetSlope(aT, aA1, aA2) {
return 3.0 * A(aA1, aA2)*aT*aT 2.0 * B(aA1, aA2) * aT C(aA1);
}
function GetTForX(aX) {
// Newton raphson iteration
var aGuessT = aX;
for (var i = 0; i < 4; i) {
var currentSlope = GetSlope(aGuessT, mX1, mX2);
if (currentSlope == 0.0) return aGuessT;
var currentX = CalcBezier(aGuessT, mX1, mX2) - aX;
aGuessT -= currentX / currentSlope;
}
return aGuessT;
}
}
Псевдонимы для общих кривых:
{
"ease": [0.25, 0.1, 0.25, 1.0],
"linear": [0.00, 0.0, 1.00, 1.0],
"ease-in": [0.42, 0.0, 1.00, 1.0],
"ease-out": [0.00, 0.0, 0.58, 1.0],
"ease-in-out": [0.42, 0.0, 0.58, 1.0]
}
Должно быть легко создавать свои собственные кривые…
Ответ №3:
Спасибо, Джонни!
Вот как реализовать функции упрощения Безье: C или Objective-C для iOS
// APPLE ORIGINAL TIMINGS:
// linear (0.00, 0.00), (0.00, 0.00), (1.00, 1.00), (1.00, 1.00)
// easeIn (0.00, 0.00), (0.42, 0.00), (1.00, 1.00), (1.00, 1.00)
// easeOut (0.00, 0.00), (0.00, 0.00), (0.58, 1.00), (1.00, 1.00)
// easeInEaseOut (0.00, 0.00), (0.42, 0.00), (0.58, 1.00), (1.00, 1.00)
// default (0.00, 0.00), (0.25, 0.10), (0.25, 1.00), (1.00, 1.00)
(double)defaultEase_Linear:(double)t
{
return t;
}
// Замедление в начале
(double)defaultEase_In:(double)t
{
return [AnimationMath easeBezier_t:t
point0_x:0
point0_y:0
point1_x:0.42
point1_y:0
point2_x:1
point2_y:1
point3_x:1
point3_y:1];
}
// Замедление в конце
(double)defaultEase_Out:(double)t
{
return [AnimationMath easeBezier_t:t
point0_x:0
point0_y:0
point1_x:0
point1_y:0
point2_x:0.58
point2_y:1
point3_x:1
point3_y:1];
}
(double)defaultEase_InOut:(double)t
{
return [AnimationMath easeBezier_t:t
point0_x:0
point0_y:0
point1_x:0.42
point1_y:0
point2_x:0.58
point2_y:1
point3_x:1
point3_y:1];
}
(double)defaultEase_default:(double)t
{
return [AnimationMath easeBezier_t:t
point0_x:0
point0_y:0
point1_x:0.25
point1_y:0.1
point2_x:0.25
point2_y:1.0
point3_x:1
point3_y:1];
}
// For *better understanding* there is p1 and p2, because it is a Bezier curve from 0,0 to 1,0. So, you can remove p1 and p2 from this method, it is just for better understanding what's going on here
double ease_bezier_A(double aA1, double aA2) { return 1.0 - 3.0 * aA2 3.0 * aA1; }
double ease_bezier_B(double aA1, double aA2) { return 3.0 * aA2 - 6.0 * aA1; }
double ease_bezier_C(double aA1) { return 3.0 * aA1; }
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
double ease_bezier_calc(double aT, double aA1, double aA2) {
return ((ease_bezier_A(aA1, aA2)*aT ease_bezier_B(aA1, aA2))*aT ease_bezier_C(aA1))*aT;
}
// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
double ease_bezier_get_slope(double aT, double aA1, double aA2) {
return 3.0 * ease_bezier_A(aA1, aA2)*aT*aT 2.0 * ease_bezier_B(aA1, aA2) * aT ease_bezier_C(aA1);
}
double ease_bezier_get_t_for_x(double aX, double mX1, double mX2) {
// Newton raphson iteration
double aGuessT = aX;
for (int i = 0; i < 4; i) {
double currentSlope = ease_bezier_get_slope(aGuessT, mX1, mX2);
if (currentSlope == 0.0) return aGuessT;
double currentX = ease_bezier_calc(aGuessT, mX1, mX2) - aX;
aGuessT -= currentX / currentSlope;
}
return aGuessT;
}
// Objective-C
// For ***better understanding*** there is p1 and p2, because it is a Bezier curve from 0,0 to 1,0. So, you can remove p1 and p2 from this method, it is just for better understanding what's going on here
// p1_x always = 0
// p1_y always = 0
// p2_x always = 1.0
// p2_y always = 1.0
(double)easeBezier_t:(double)t
point0_x:(double)point0_x point0_y:(double)point0_y
point1_x:(double)point1_x point1_y:(double)point1_y
point2_x:(double)point2_x point2_y:(double)point2_y
point3_x:(double)point3_x point3_y:(double)point3_y
{
if (point0_x != 0 || point0_y != 0 || point3_x != 1 || point3_y != 1) {
[NSException raise:@"Error! Your bezier is wrong!!!" format:@""];
}
double v = ease_bezier_calc(ease_bezier_get_t_for_x(t, point1_x, point2_x), point1_y, point2_y);
return v;
}