三角函数与缓入缓出动画及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-& ...
随机推荐
- 如何利用Xpath抓取京东网商品信息
前几小编分别利用Python正则表达式和BeautifulSoup爬取了京东网商品信息,今天小编利用Xpath来为大家演示一下如何实现京东商品信息的精准匹配~~ HTML文件其实就是由一组尖括号构成的 ...
- Spring基础之AOP
一.AOP能解决什么问题 业务层每个service都要管理事务,在每个service中单独写事务,就会产生很多重复性的代码,而且修改事务时,需要修改源码,不利于维护.为此,把横向重复的代码,纵向抽取形 ...
- Unity 游戏框架搭建 2019 (五十、五十一) 消息机制小结&MonoBehaviourSimplify 是框架?
我们花了 5 篇文章学习了消息机制的方方面面.并且完成了一个简易消息机制,之后集成到了我们的 MonoBehaviourSimplify 里. 现在 MonoBehaviourSimplify 有一点 ...
- Rocket - util - Annotations
https://mp.weixin.qq.com/s/7C8ZmPpwAqFqyKjL9K40Fg 介绍util中定义的注解(Annotations). 1. Annotation ...
- 大型可视化项目用什么工具好呢?——不如了解一下阿里云DataV尊享版
随着信息化的发展和进步,可视化大屏开始为社会各行业提供全面应用.目前越来越多的需求显示希望大屏能够更直观的还原出所要展示数据可视化的真实场景,让整个项目更立体.更有科技感,让项目在面对复杂操作时能灵活 ...
- java eclipse tomcat
Port 8080 required by Tomcat v9.0 Server at localhost is already in use. The server may already be r ...
- Shell 脚本(五) Shell 工具 及 企业面试题
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 十.Shell工具(重点) 1.cut cut 的工作就是“剪”,具体的说就是在文件中负责剪切数据用的. ...
- Java实现 第十一届 蓝桥杯 (本科组)省内模拟赛
有错误的或者有问题的欢迎评论 计算机存储中有多少字节 合法括号序列 无向连通图最少包含多少条边 字母重新排列 凯撒密码加密 反倍数 正整数的摆动序列 螺旋矩阵 小明植树 户户通电 计算机存储中有多少字 ...
- Java实现 LeetCode 414 第三大的数
414. 第三大的数 给定一个非空数组,返回此数组中第三大的数.如果不存在,则返回数组中最大的数.要求算法时间复杂度必须是O(n). 示例 1: 输入: [3, 2, 1] 输出: 1 解释: 第三大 ...
- Java实现 LeetCode 380 常数时间插入、删除和获取随机元素
380. 常数时间插入.删除和获取随机元素 设计一个支持在平均 时间复杂度 O(1) 下,执行以下操作的数据结构. insert(val):当元素 val 不存在时,向集合中插入该项. remove( ...