三角函数与缓入缓出动画及C#实现(图文讲解)
日常经常能看到缓入缓出的动画效果,如:
1,带缓入缓出效果的滚动条:

2,带缓入缓出效果的呼吸灯:

像上面这种效果,就是用到了三角函数相关的知识,下面将从头开始一步步去讲解如何实现这种效果。
一、基础知识
(一)三角函数
常用的三角函数有正弦函数(sin)、余弦函数(cos)、正切函数(tan)。在动画效果中常用的是正弦函数和余弦函数,由于两者可以互相转化,所以本文将以正弦函数来进行讲解。
如下图所示直角三角形ABC:

则:
sin(A)=a/c
即:角A的正弦值=角A的对边/斜边
(二)正弦曲线
将三角函数与动画桥接起来的便是三角函数曲线。
以正弦函数为例,其正弦曲线公式为:y = A*sin(B*x + C) + D
其中y、x分别是纵坐标、横坐标。
1,在默认状态时,即:y=sin(x) 时,其曲线如下图所示:

2,正弦曲线公式中的参数 “A” 控制曲线的振幅,A 值越大,振幅越大,A 值越小,振幅越小。
如:y=2*sin(x),其曲线如下图所示(蓝线为 y=sin(x)):

3,参数 “B" 控控制曲线的周期,B 值越大,那么周期越短,B 值越小,周期越长。
如:y=sin(2x),其曲线如下图所示(蓝线为 y=sin(x)):

4,参数 “C" 控控制曲线左右移动,C 值为正数,曲线左移,C 值为负数,曲线右移;
如:y=sin(x+1),其曲线如下图所示(蓝线为 y=sin(x)):

5,参数 “D" 控控制曲线上下移动。D 值为正数,曲线上移,D 值为负数,曲线下移;
如:y=sin(x)+1,其曲线如下图所示(蓝线为 y=sin(x)):

(三)角度与弧度
因为在使用代码去计算正弦值时,其单位一般是弧度,像C#中的”Math.Sin()“函数,而直观的效果却是角度,所以需要讲解一下角度与弧度。
1,角度
定义:两条射线从圆心向圆周射出,形成一个夹角和夹角正对的一段弧。当这段弧长正好等于圆周长的360分之中的一个时,两条射线的夹角的大小为1度。
示意图如下:

2,弧度
定义:弧度:两条射线从圆心向圆周射出,形成一个夹角和夹角正对的一段弧。当这段弧长正好等于圆的半径时,两条射线的夹角大小为1弧度。
示意图如下:
其中:AB=OA=r

3,角度与弧度的差别
最基本的差别在于角所对的弧长大小不同。度的是等于圆周长的360分之中的一个,而弧度的是等于半径。
4,角度与弧度的转换
因为:弧度角=弧长/半径
所以:
a,周角(360度)=周长/半径=2πr/r=2π
b,平角(180度)=π
由b可知:180度=π弧度
所以:
c,1度=π/180 弧度(≈0.017453弧度)
d,1弧度=180/π 度(≈57.3度)
可得转换公式:
弧度=度*π/180
度=弧度*180/π
三、动画实现
实现的思路简单而言便是利用正弦曲线的”y“和”x“值的变化。对于缓入缓出动画,就是速度的变化。
速度的定义和公式:速度在数值上等于物体运动的位移跟发生这段位移所用的时间的比值。速度的计算公式为v=Δs/Δt
控制速度,无非是”距离“与”时间“这两个量的变化。
在实现应用中,往往不会同时变化两个量,而是固定一个量,变化一个量。
在实际程序实现时,一般是固定“时间”,只变化“距离”。此处的”时间“可以理解为”时间间隔“。即在时间间隔不变的情况下,需要考虑每个时间间隔内运行的距离。
那么在正弦曲线上的体现便是等x间隔下,y的取值。
(一)简单实现
(1)实现思路:
1,通过y=sin(x)的曲线可知:y值的范围是(-1~+1)
2,将曲线上移,上移距离为1,即:y=sin(x)+1,此时y值的范围:(0~2)
3,为使y值范围变为(0~1),对函数除2,即:y=(sin(x)+1)/2
如图(蓝线为 y=sin(x)):

4,将y值乘以缓入缓出动画的摆动距离
(2)C#实现:
1,控件布局及属性

2,核心代码

void pShowD()
{
//i是度数,不是弧度
int i = ;
//移动距离要减去滑块本身的宽度
double dMoveDistance = panel_Board.Width - panel_Slider.Width;
while (true)
{
i++;
if (i > )
{
//一个周期是360度
i = ;
}
//固定时间间隔
Thread.Sleep();
//通过公式:弧度=度*π/180,将度数i转为Math.Sin()所需要的弧度数
double dz = dMoveDistance * ( + Math.Sin(i * Math.PI / )) / ;
pSetLeft(Convert.ToInt32(dz)); }
} void pSetLeft(int i)
{
if (panel_Slider.InvokeRequired)
{
panel_Slider.Invoke(new Action<int>(pSetLeft), new object[] { i });
}
else
{
panel_Slider.Left = i;
}
}
简单实现
3,运行效果

(二)简单实现优化
通过观察上面的实现,可以发现虽然实现了缓入缓出效果,但是其”滑块“(panel_Slider)的起始位置却不是最左侧,而是从中间开始。
根据上面的公式也可以看出来,当x=0时,y=(sin(x)+1)/2=1/2,即:整个摆动距离的二分之一。
(1)优化思路
为了让滑块从最左侧开始,则需要将曲线向右移动,移动距离是π/2。
其曲线公式变为:y=(sin(x-π/2)+1)/2
如图(蓝线为 y=sin(x)):

(2)C#实现
1,布局同上。
2,核心代码

void pShowD2()
{
//i是度数,不是弧度
int i = ;
//移动距离要减去滑块本身的宽度
double dMoveDistance = panel_Board.Width - panel_Slider.Width;
while (true)
{
i++;
if (i > )
{
//一个周期是360度
i = ;
}
//固定时间间隔
Thread.Sleep();
//通过公式:弧度=度*π/180,将度数i转为Math.Sin()所需要的弧度数
//因为i是度数,所以是(i-90)
double dz = dMoveDistance * ( + Math.Sin((i-) * Math.PI / )) / ;
pSetLeft(Convert.ToInt32(dz)); }
} void pSetLeft(int i)
{
if (panel_Slider.InvokeRequired)
{
panel_Slider.Invoke(new Action<int>(pSetLeft), new object[] { i });
}
else
{
panel_Slider.Left = i;
}
}
简单实现(优化)
3,运行效果

(三)扩展实现
在实际应用中,动画往往需要在”固定时间“内完成。
以前面实现为例,使滑块从左端滑到右端的时长固定为1秒。该怎么实现呢?
(1)实现思路
整体思路与之前的并没有什么大的区别,仍是固定”时间“,变化”距离“。
在前面的”简单实现(优化)“的基础上,需要增加下面的一些修改和补充:
1,假设”时间间隔“为:Interval,那么,在指定的1秒内,共会变化(Step=1/Interval)次。
2,那么,每次变化时度数的变化便不再是”1“,又一个周期是滑块一个来回,所以,第次变化的度数便是:Per=2π/2*Step=180/Step。
(2)C#实现
在实现时加入了匀速的对比。
1,布局及属性

2,核心代码

void pShowD2()
{
//当前滑块的位置
double d = ;
//true/false:向右滑/向左滑
bool bToRight = true;
//时间间隔,单位:ms
int iInterval = ;
//从左到右所需要的总时间,单位:ms
int iAnimateTime = ;
//移动距离要减去滑块本身的宽度
double dMoveDistance = panel_Board.Width - panel_Slider.Width;
//需要变化的次数
double dStep = Convert.ToDouble(iAnimateTime) / iInterval;
//每次变化所增加的距离
double dPerX = dMoveDistance / dStep;
while (true)
{
d = bToRight ? d + dPerX : d - dPerX;
if (d > dMoveDistance)
{
bToRight = false;
}
if (d < )
{
bToRight = true;
} Thread.Sleep(iInterval);
int iZ = Convert.ToInt32(d);
pSetLeft2(iZ); }
}
void pSetLeft2(int i)
{
if (panel_S2.InvokeRequired)
{
panel_S2.Invoke(new Action<int>(pSetLeft2), new object[] { i });
}
else
{
panel_S2.Left = i;
}
}
1,匀速

void pShowD()
{
//d是度数,不是弧度
double d = ;
//时间间隔,单位:ms
int iInterval = ;
//从左到右所需要的总时间,单位:ms
int iAnimateTime = ;
//移动距离要减去滑块本身的宽度
double dMoveDistance = panel_Board.Width - panel_Slider.Width;
//需要变化的次数
double dStep = Convert.ToDouble(iAnimateTime) / iInterval;
//每次变化所增加的度数
double dPer = 180.0 / dStep;
while (true)
{
d += dPer;
if (d > )
{
//一个周期是360度
d = ;
}
//固定时间间隔
Thread.Sleep(iInterval);
//通过公式:弧度=度*π/180,将度数i转为Math.Sin()所需要的弧度数
double dz = dMoveDistance * ( + Math.Sin((d - ) * Math.PI / )) / ;
pSetLeft(Convert.ToInt32(dz)); }
} void pSetLeft(int i)
{
if (panel_Slider.InvokeRequired)
{
panel_Slider.Invoke(new Action<int>(pSetLeft), new object[] { i });
}
else
{
panel_Slider.Left = i;
}
}
2,缓入缓出
3,运行效果

四、结束语
本篇主要讲的是三角函数与缓入缓出动画,但三角函数在动画中的作用不仅仅如此,比如直接使用正弦曲线的形状来绘制波浪效果——在充电、进度条等地方可以使用该效果。
而且即然知道在曲线在动画中的作用,那么便可以通过不同的函数曲线实现不同的动画效果,比如另一个非常好用的”贝塞尔曲线“,可以实现更复杂、更优雅的动画效果。
如有错误和不足之处欢迎大家批评指正。
三角函数与缓入缓出动画及C#实现(图文讲解)的更多相关文章
- JQuery动画之滑入滑出动画
1. 滑入动画(类似于商店的卷帘门) $(selector).slideDown(speed, 回调函数); 解释: 此语句实现的功能为, 在XX时间内, 下拉动画, 显现元素. 当 slideDow ...
- 在 jQuery 中使用滑入滑出动画效果,实现二级下拉导航菜单的显示与隐藏效果
查看本章节 查看作业目录 需求说明: 在 jQuery 中使用滑入滑出动画效果,实现二级下拉导航菜单的显示与隐藏效果 用户将光标移动到"最新动态页"或"帮助查询" ...
- scrollReveal(页面缓入效果插件)
scrollReveal(页面缓入效果插件)实现页面滚动时动画加载元素效果 前面我去了解了元素距页面视图距离,想实现页面滚动是动画加载元素(https://www.cnblogs.com/chengh ...
- 【jquery隐藏、显示事件and提示callback】【淡入淡出fadeToggle】【滑入滑出slideToggle】【动画animate】【停止动画stop】
1.jquery隐藏and显示事件 $("p").hide(); //隐藏事件$("p").hide(1000); //1秒内缓慢隐藏$(" ...
- jQuary总结7:动画操作,显示与隐藏 淡入淡出, 滑入滑出
1 jquery提供了三组基本动画,这些动画都是标准的.有规律的效果,jquery还提供了自定义动画的功能. 2 显示与隐藏: show([speed],[easing],[callback]) 显示 ...
- css transition 实现滑入滑出
transition是css最简单的动画. 通常当一个div属性变化时,我们会立即看的变化,从旧样式到新样式是一瞬间的,嗖嗖嗖!!! 但是,如果我希望是慢慢的从一种状态,转变成另外一种状态,怎么办? ...
- 包学会之浅入浅出Vue.js:结业篇(转)
蔡述雄,现腾讯用户体验设计部QQ空间高级UI工程师.智图图片优化系统首席工程师,曾参与<众妙之门>书籍的翻译工作.目前专注前端图片优化与新技术的探研. 在第一篇<包学会之浅入浅出Vu ...
- 包学会之浅入浅出Vue.js:结业篇
在第一篇<包学会之浅入浅出Vue.js:开学篇>和上一篇<包学会之浅入浅出Vue.js:升学篇>的学习中,我们首先了解了Vue环境的搭建以及两个重要思想——路由和组件的学习,通 ...
- mac关闭渐隐和弹出动画效果
苹果系统应用程序的窗口和对话框每次使用的时候都有华丽的特效,但是如果你感觉这种特效显得有点慢(MacGG闲的蛋疼),那该如何取消掉他呢? 方法很简单,打开"终端"(Finder-& ...
随机推荐
- SpringBoot外部化配置使用Plus版
本文如有任何纰漏.错误,请不吝指正! PS: 之前写过一篇关于SpringBoo中使用配置文件的一些姿势,不过嘛,有句话(我)说的好:曾见小桥流水,未睹观音坐莲!所以再写一篇增强版,以便记录. 序言 ...
- pytest跟unittest的优势跟劣势
一.用例编写规则 1.使用unittest编写测试用例必须遵循以下规则: 1.必须首先 导入 import unittest 2.测试类必须要继承 unittest.TestCase 3.测试方法必须 ...
- 跳出初学MySQL知识的原理整理(一)
一.基础架构 MySQL 可以分为 Server 层和存储引擎层两部分. Server 层包括连接器.查询缓存.分析器.优化器.执行器等,所有跨存储引擎 的功能都在这一层实现,比如存储过程.触发器.视 ...
- Rocket - debug - TLDebugModuleInner - DMSTATUS
https://mp.weixin.qq.com/s/GyGriFyeq_7Z3xOjKn56Mg 简单介绍TLDebugModuleInner中DMSTATUS寄存器的实现. 1. DMSTATUS ...
- Chisel3 - util - MixedVec
https://mp.weixin.qq.com/s/mO648yx4_ZRedXSWX4Gj2g 可以容纳不同类型的变量的向量. 参考链接: https://github.com/freec ...
- Java实现 LeetCode 590 N叉树的后序遍历(遍历树,迭代法)
590. N叉树的后序遍历 给定一个 N 叉树,返回其节点值的后序遍历. 例如,给定一个 3叉树 : 返回其后序遍历: [5,6,3,2,4,1]. 说明: 递归法很简单,你可以使用迭代法完成此题吗? ...
- Java实现 LeetCode 306 累加数
306. 累加数 累加数是一个字符串,组成它的数字可以形成累加序列. 一个有效的累加序列必须至少包含 3 个数.除了最开始的两个数以外,字符串中的其他数都等于它之前两个数相加的和. 给定一个只包含数字 ...
- Java实现 LeetCode 130 被围绕的区域
130. 被围绕的区域 给定一个二维的矩阵,包含 'X' 和 'O'(字母 O). 找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充. 示例: X X X X X O O ...
- Java实现 蓝桥杯 算法提高 套正方形
试题 算法提高 套正方形 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 给定正方形边长width,如图按规律输出层层嵌套的正方形图形. 注意,为让选手方便观看,下图和样例输出均使用 ...
- Java实现LeetCode_0026_RemoveDuplicatesFromSortedArray
package javaLeetCode.primary; public class RemoveDuplicatesFromSortedArray_26 { public static void m ...