本人微信公众号:CPP进阶之旅
如果觉得这篇文章对您有帮助,欢迎关注 “CPP进阶之旅” 学习更多技术干货
1、简介
在实际的项目开发中,遇到需要通过算法为程序提供流畅的显示效果的时候,我们通常需要借助计时器和位置计算的算法来实现。这里的Tween就是一个缓动数据计算的类,有了tween算法,我们就可以在此基础上,根据具体的业务调整数据实现流畅的缓动效果了。
2、代码
#pragma once
// Algorithm Reference:
//http://www.cnblogs.com/cloudgamer/archive/2009/01/06/Tween.html
#ifndef PI
#define PI 3.1415926f
#endif
const float EPSINON = 0.000001f;
#define EQUAL_ZERO(x) ((x >= - EPSINON) && (x <= EPSINON)) ? true : false
/*
缓动函数介绍:
easeIn:速度从0开始加速的缓动
easeOut:减速到0的缓动
easeInOut:速度的前半段从0开始加速,后半段减速到0的缓动。
*/
class CPPTween
{
public:
CPPTween(void);
~CPPTween(void);
// Linear 匀速
float Linear_easeIn(float t, float b, float c, float d);
float Linear_easeOut(float t, float b, float c, float d);
float Linear_easeInOut(float t, float b, float c, float d);
// Quadratic 二次方的缓动(t^2)
float Quad_easeIn(float t, float b, float c, float d);
float Quad_easeOut(float t, float b, float c, float d);
float Quad_easeInOut(float t, float b, float c, float d);
// Cubic三次方的缓动(t^3)
float Cubic_easeIn(float t, float b, float c, float d);
float Cubic_easeOut(float t, float b, float c, float d);
float Cubic_easeInOut(float t, float b, float c, float d);
// Quartic四次方的缓动(t^4)
float Quart_easeIn(float t, float b, float c, float d);
float Quart_easeOut(float t, float b, float c, float d);
float Quart_easeInOut(float t, float b, float c, float d);
// Quintic五次方的缓动
float Quint_easeIn(float t, float b, float c, float d);
float Quint_easeOut(float t, float b, float c, float d);
float Quint_easeInOut(float t, float b, float c, float d);
// Sinusoidal正弦曲线的缓动(sin(t))
float Sine_easeIn(float t, float b, float c, float d);
float Sine_easeOut(float t, float b, float c, float d);
float Sine_easeInOut(float t, float b, float c, float d);
// Exponential指数曲线的缓动(2^t)
float Expo_easeIn(float t, float b, float c, float d);
float Expo_easeOut(float t, float b, float c, float d);
float Expo_easeInOut(float t, float b, float c, float d);
// Circular圆形曲线的缓动sqrt(1-t^2)
float Circ_easeIn(float t, float b, float c, float d);
float Circ_easeOut(float t, float b, float c, float d);
float Circ_easeInOut(float t, float b, float c, float d);
// Elastic指数衰减的正弦曲线缓动
float Elastic_easeIn(float t, float b, float c, float d, float a = 0.0f, float p = 0.0f);
float Elastic_easeOut(float t, float b, float c, float d, float a = 0.0f, float p = 0.0f);
float Elastic_easeInOut(float t, float b, float c, float d, float a = 0.0f, float p = 0.0f);
// Back超过范围的三次方缓动((s+1)*t^3 - s*t^2)
float Back_easeIn(float t, float b, float c, float d, float s = 0.0f);
float Back_easeOut(float t, float b, float c, float d, float s = 0.0f);
float Back_easeInOut(float t, float b, float c, float d, float s = 0.0f);
// Bounce指数衰减的反弹缓动
float Bounce_easeOut(float t, float b, float c, float d);
float Bounce_easeIn(float t, float b, float c, float d);
float Bounce_easeInOut(float t, float b, float c, float d);
public:
//t: current time(当前时间);
//b: beginning value(初始值);
//c: change in value(变化量);
//d: duration(持续时间)。
float t, b, c, d, p;
};
#include "CPPTween.h"
#include <math.h>
CPPTween::CPPTween(void)
{
}
CPPTween::~CPPTween(void)
{
}
// Linear
float CPPTween::Linear_easeIn(float t, float b, float c, float d)
{
return c * t / d + b;
}
float CPPTween::Linear_easeOut(float t, float b, float c, float d)
{
return c * t / d + b;
}
float CPPTween::Linear_easeInOut(float t, float b, float c, float d)
{
return c * t / d + b;
}
// Quadratic
float CPPTween::Quad_easeIn(float t, float b, float c, float d)
{
return c * (t /= d) * t + b;
}
float CPPTween::Quad_easeOut(float t, float b, float c, float d)
{
return -c * (t /= d) * (t - 2) + b;
}
float CPPTween::Quad_easeInOut(float t, float b, float c, float d)
{
if ((t /= d / 2) < 1)
return c / 2 * t * t + b;
return -c / 2 * ((--t) * (t - 2) - 1) + b;
}
// Cubic
float CPPTween::Cubic_easeIn(float t, float b, float c, float d)
{
return c * (t /= d) * t * t + b;
}
float CPPTween::Cubic_easeOut(float t, float b, float c, float d)
{
return c * ((t = t / d - 1) * t * t + 1) + b;
}
float CPPTween::Cubic_easeInOut(float t, float b, float c, float d)
{
if ((t /= d / 2) < 1)
return c / 2 * t * t * t + b;
return c / 2 * ((t -= 2) * t * t + 2) + b;
}
// Quartic
float CPPTween::Quart_easeIn(float t, float b, float c, float d)
{
return c * (t /= d) * t * t * t + b;
}
float CPPTween::Quart_easeOut(float t, float b, float c, float d)
{
return -c * ((t = t / d - 1) * t * t * t - 1) + b;
}
float CPPTween::Quart_easeInOut(float t, float b, float c, float d)
{
if ((t /= d / 2) < 1)
return c / 2 * t * t * t * t + b;
return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
}
// Quintic
float CPPTween::Quint_easeIn(float t, float b, float c, float d)
{
return c * (t /= d) * t * t * t * t + b;
}
float CPPTween::Quint_easeOut(float t, float b, float c, float d)
{
return c * ((t = t / d - 1)* t * t * t * t + 1) + b;
}
float CPPTween::Quint_easeInOut(float t, float b, float c, float d)
{
if ((t /= d / 2) < 1)
return c / 2 * t * t * t * t * t + b;
return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
}
// Sinusoidal
float CPPTween::Sine_easeIn(float t, float b, float c, float d)
{
return -c * cos(t / d * (PI / 2)) + c + b;
}
float CPPTween::Sine_easeOut(float t, float b, float c, float d)
{
return c * sin(t / d * (PI / 2)) + b;
}
float CPPTween::Sine_easeInOut(float t, float b, float c, float d)
{
return -c / 2 * (cos(PI * t/ d) - 1) + b;
}
// Exponential
float CPPTween::Expo_easeIn(float t, float b, float c, float d)
{
return (t == 0) ? b : c * pow(2, 10 * (t / d - 1)) + b;
}
float CPPTween::Expo_easeOut(float t, float b, float c, float d)
{
return (t == d) ? b + c : c * (-pow(2, -10 * t / d) + 1) + b;
}
float CPPTween::Expo_easeInOut(float t, float b, float c, float d)
{
if (t == 0)
return b;
if (t == d)
return b+c;
if ((t /= d / 2) < 1)
return c / 2 * pow(2, 10 * (t - 1)) + b;
return c / 2 * (-pow(2, -10 * --t) + 2) + b;
}
// Circular
float CPPTween::Circ_easeIn(float t, float b, float c, float d)
{
return -c * (sqrt(1 - (t /= d) * t) - 1) + b;
}
float CPPTween::Circ_easeOut(float t, float b, float c, float d)
{
return c * sqrt(1 - (t = t / d - 1) * t) + b;
}
float CPPTween::Circ_easeInOut(float t, float b, float c, float d)
{
if ((t /= d / 2) < 1)
return -c / 2 * (sqrt(1 - t * t) - 1) + b;
return c / 2 * (sqrt(1 - (t -= 2) * t) + 1) + b;
}
// Elastic
float CPPTween::Elastic_easeIn(float t, float b, float c, float d, float a/* = 0.0f*/, float p/* = 0.0f*/)
{
float s = 0;
if (t == 0)
return b;
if ((t /= d) == 1)
return b + c;
if (!p)
p = d * .3f;
if (!a || a < fabsf(c))
{
a = c;
s = p/4;
}
else
s = p / (2 * PI) * asin (c / a);
return -(a * pow(2, 10 * (t -= 1)) * sin((t * d - s) * (2 * PI) / p)) + b;
}
float CPPTween::Elastic_easeOut(float t, float b, float c, float d, float a/* = 0.0f*/, float p/* = 0.0f*/)
{
float s = 0;
if (t == 0)
return b;
if ((t /= d) == 1)
return (b + c);
if (!p)
p = d *.3f;
if (!a || a < fabsf(c))
{
a = c;
s = p / 4;
}
else
s = p / (2 * PI) * sin((float)c / a);
return (a * pow(2.0f, (int) - 10 * t) * sin((t * d - s) * (2 * PI) / p) + c + b);
}
float CPPTween::Elastic_easeInOut(float t, float b, float c, float d, float a/* = 0.0f*/, float p/* = 0.0f*/)
{
float s = 0;
if (t == 0)
return b;
if ((t /= d / 2) == 2)
return b + c;
if (!p)
p = d * (.3f * 1.5f);
if (!a || a < fabsf(c))
{
a = c;
s = p/4;
}
else
s = p / (2 * PI) * asin (c / a);
if (t < 1)
return -.5f * (a * pow(2, 10 * (t -= 1)) * sin( (t * d - s) * (2 * PI) / p )) + b;
return a * pow(2, -10 * (t -= 1)) * sin((t * d - s) * (2 * PI) / p ) * .5f + c + b;
}
// Back
float CPPTween::Back_easeIn(float t, float b, float c, float d, float s/* = 0.0f*/)
{
if (EQUAL_ZERO(s))
s = 1.70158f;
return c * (t /= d) * t * ((s + 1) * t - s) + b;
}
float CPPTween::Back_easeOut(float t, float b, float c, float d, float s/* = 0.0f*/)
{
if (EQUAL_ZERO(s))
s = 1.70158f;
return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
}
float CPPTween::Back_easeInOut(float t, float b, float c, float d, float s/* = 0.0f*/)
{
if (EQUAL_ZERO(s))
s = 1.70158f;
if ((t /= d / 2) < 1)
return c / 2 * (t * t * (((s *= (1.525f)) + 1) * t - s)) + b;
return c / 2 * ((t -= 2) * t * (((s *= (1.525f)) + 1) * t + s) + 2) + b;
}
// Bounce
float CPPTween::Bounce_easeOut(float t, float b, float c, float d)
{
if ((t /= d) < (1 / 2.75))
{
return c * (7.5625f * t * t) + b;
}
else if (t < (2 / 2.75))
{
return c * (7.5625f * (t -= (1.5f / 2.75f)) * t + .75f) + b;
}
else if (t < (2.5 / 2.75))
{
return c * (7.5625f * (t -= (2.25f / 2.75f)) * t + .9375f) + b;
}
else
{
return c * (7.5625f * (t -= (2.625f / 2.75f)) * t + .984375f) + b;
}
}
float CPPTween::Bounce_easeIn(float t, float b, float c, float d)
{
return c - Bounce_easeOut(d - t, 0, c, d) + b;
}
float CPPTween::Bounce_easeInOut(float t, float b, float c, float d)
{
if (t < d / 2)
return Bounce_easeIn(t * 2, 0, c, d) * .5f + b;
else return Bounce_easeOut(t * 2 - d, 0, c, d) * .5f + c * .5f + b;
}
3、重要说明
欢迎大家关注我的个人微信公众号,查看专业的客户端/服务端开发知识、笔试面试题目、程序员职场经验与心得分享。
参考博文:
https://www.cnblogs.com/cloudgamer/archive/2009/01/06/Tween.html