Реализуя функцию ослабления
Я пытаюсь портировать и реализовать функцию ослабления, которую я нашел
РЕДАКТИРОВАТЬ
: Я вставил неправильную функцию замедления, извините! Вот правильный:
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.time - это целое число, равное I, m.duration - это то, что я предполагаю как количество времени, которое требуется для выполнения изменения, m.spriteposx - текущая позиция. объекта я двигаюсь. [i] текущий спрайт.
Каким должно быть значение приращения для времени, какой должна быть длительность, если я хочу переместить 345 пикселей за полсекунды?
Во всех моих экспериментах я либо сильно отклоняюсь, либо двигаюсь только на несколько пикселей.
В настоящее время значение m.time увеличивается на 1 для каждой итерации, а значение m.duration равно 100. Я пробовал все виды значений, и ни одно из них не работает согласованно.
3 ответа
Почему вы не скопировали логику через 1-1? Твин - это простой алгоритм, он просто отображает координаты из b
в b+c
в причудливой форме, т.е. b + c*t^4
где t
получает значения в интервале [0,1]
, Вы можете увидеть, заменив, что когда t=0
значение является начальным значением, b
, и в качестве t->1
положение является обязательным b+c
,
Это причина для линии t \= d
, так d
произвольная продолжительность и t
время, прошедшее с начала анимации, получает значение в вышеуказанном диапазоне. Но вы сделали t=t-1
и взятые негативы и т. д. Почему?
Например, перемещая 345px за 0,5 с, вы получите начальную позицию, b
а также c=345
предполагая, что px - это единицы измерения. d=0.5
и вы разделяете анимацию на интервалы длины по вашему выбору (в зависимости от мощности компьютера, на котором будет выполняться анимация. Мобильные устройства не так мощны, как настольные ПК, поэтому вы выбираете разумную частоту кадров в сложившихся обстоятельствах). Допустим, мы выбрали 24 кадра в секунду, поэтому мы разбили интервал на 0.5*24 = 12
кадры и вызывать функцию один раз каждые 1/24 секунды, каждый раз с t
принимая значения 1/24, 2/24 и т. д. Если удобнее работать не в секундах, а в кадрах, то d=12
а также t
принимает значения 1,2,...,12. Расчеты в любом случае одинаковы.
Вот хороший пример (щелкните поле, чтобы запустить демонстрацию), не стесняйтесь возиться со значениями:
Функции Безье
Заимствовано из 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 && 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]
}
Должно быть легко сделать свои собственные кривые...
Спасибо, Джонни!
Вот как реализовать функции смягчения Безье: 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;
}