用Tweeny实现丝滑动效
刘慈欣:“好的程序员不去造轮子。”
刘慈欣:“我没说过这句话。”
刘慈欣:“我说过这句话。”
说得简单一些……因为我不知道怎么说得专业些
Tweeny
简单来说,Tweeny
可以用来存储对象transition
属性的起始状态、末状态、过渡时间、过渡方式等。
我这里是为了单片机开发,在github上找了个Tweeny的C++库。
Download
1 | git clone https://github.com/mobius3/tweeny.git |
Start
1 |
|
在上面的代码中,我们实现了这样一个功能:
- 输出
Hello
Hello
中的每一个字母开始不停地变化- 最终,
Hello
变成了World
首先,我们创建了一个tween
对象(它叫什么无所谓,auto就完事了_(:з」∠)_),并告诉他:这个过渡效果有5个元素,最开始分别是'H' 'e' 'l' 'l' 'o'
,最终的值分别是'W' 'o' 'r' 'l' 'd'
,整个过渡的过程使用整数10
来度量。1
auto twe = tweeny::from('H', 'e', 'l', 'l', 'o').to('W', 'o', 'r', 'l', 'd').during(10);
让我们跳过cout<<
下面那段被注释掉的代码。cout<<"Hello"
将Hello
打印到了屏幕上。
接下来,我们希望通过差值步进
的方式打印每一次步进后的结果。1
2
3
4for (char c : twe.step(1))
{
cout << c;
}
这样的步进一共有10次,所以在外面加上一个循环1
2
3
4
5
6
7for (int i = 0; i < 10; ++i)
{
for (char c : twe.step(1))
{
cout << c;
}
}
再搭配上Sleep()
和gotoxy()
,就能实现想要的效果啦。
不过,通过cout<<"Hello"
的方式实在是太奇怪了,所以我们可以选择每次步进为0,输出最开始的结果,也就是被注释掉的那段代码1
2
3
4
5for (char c : twe.step(0))
{
cout << c;
Sleep(20);
}
Step Further
选择过渡函数
一个简单的线性函数可这样实现1
2
3
4int linear(float p, int a, int b)
{
return (b - a) * p + a;
}
使用via
将它添加到Tweeny对象1
auto twe = tweeny::from(0).to(100).during(1000).via(linear);
Tweeny库提供了多种内置过渡函数,但我也不知道从哪儿查看,应该是下面这个网站中的不少吧
好康的缓动曲线动画可在http://easings.net查看。
为每个元素单独设置属性
你只需要在函数里分别一一对应地给出。如果每个元素的属性值都相同,你可以只写一个值。1
2auto twe1 = tweeny::from(0, 10, 100).to(10, 100, 1000).during(10, 20, 30).via(easing::exponentialIn, easing::exponentialInOut, easing::backOut);
auto twe2 = tweeny::from(0, 10, 100).to(10, 100, 1000).during(100).via(easing::exponentialInOut);
添加多段过渡
多段过度(multipoint)
To allow for that, each call to tween::to adds a new tweening point. Calls to tween::during and tween::via always refer to the last added point:
1 | auto tween = tweeny::from(0) |
stepping & seeking & jumping
step
就像刚才演示的那样。
Passing a integral quantity (integers) to tween::step will step it in duration units. Passing a float value will step it by a percentage (ranging from 0.0f to 1.0f).
后撤步
后撤步,7777
使用tween::backward
前进步
使用tween:forward
seek
让你跳转到任意你想到达的插值处1
2auto tween = tweeny::from(0).to(100).during(1000);
tween.seek(0.5f);
jump
当你使用了多段过度(multipoint),jump可以让你跳转到任意关键点(specific tween point)上1
2auto tween = tweeny::from(0).to(100).during(100).to(200).during(100);
tween.jump(1);
返回值说明
tweeny::step()
、tweeny::seek()
、tweeny::jump()
都有返回值。
- 如果你用的是单值(single value),那么它直接该返回什么就返回什么
- 如果有多个同类型的值(multiple values of the same type),那么它会返回一个
std::array
,例如1
2auto tween = tweeny::from(0, 1).to(2, 3).during(100);
std::array<int, 2> v = tween.step(10); - 如果是不同的类型(multiple types),那么它会安徽一个
std::tuple
,例如1
2auto tween = tweeny::from(0, 1.0f).to(2, 3.0f).during(100);
std::tuple<int, float> v = tween.step(10);
总而言之,如果是多个元素,那么它的返回值一定可迭代。
Callbacks
Tweeny允许用户为step
添加回调函数(Callbacks),为特殊点配置可运行的程序。比如,当你播放视频时想要自动跳过片头片尾。
回调函数有三种形式:
- 如果既需要当前值,又需要操控tween对象
1
2bool stepped(tween<int, int> & t, int x, int y);
auto tween = tweeny::from(0, 0).to(100, 200).during(100).onStep(stepped); - 如果只需要操控tween
1
2bool stepped(tween<int, int> & t);
auto tween = tweeny::from(0, 0).to(100, 200).during(100).onStep(stepped); - 如果只需要获取当前值回调函数的返回类型通常是布尔型,若返回true,则该函数将从回调函数表中移除(callback list);若返回false,则保留在队列(queue)中。(我也不知道为什么是队列(queue),上边没提这事儿,估计和“回调函数列表”是一回事儿)
1
2bool stepped(int x, int y);
auto tween = tweeny::from(0, 0).to(100, 200).during(100).onStep(stepped);The return type of a callback is always boolean. If it returns true, it will be dismissed and removed from the callback list. Returning false keeps the callback in the queue.
例如:1
2
3
4
5
6
7
8bool stepped(int x, int y)
{
printf("x: %d, y: %d\n", x, y);
if (x == y)
return true;
return false;
}
auto tween = tweeny::from(0, 0).to(100, 200).during(100).onStep(stepped);
Any functions usable
只要与接口一致,哪里来的回调函数都能用。1
2
3
4
5
6
7
8
9
10struct ftor
{
bool operator()(int x, int y)
{
return false;
}
};
auto tween = tweeny::from(0, 0).to(100, 200).during(100);
tween.onStep([](int, int) { return false; }); // lambdas
tween.onStep(ftor()); // functors
Final
I hope you have fun using Tweeny.
附议。