`
jindw
  • 浏览: 509816 次
  • 性别: Icon_minigender_1
  • 来自: 初到北京
社区版块
存档分类
最新评论

运动曲线研究(缓动效果)

阅读更多
刚刚学习了一下网页动画中上的缓动效果,分享一下学习心得。

缓动曲线的概念:

缓动曲线是一个0为起点的连续函数曲线,x轴表示时间变化,y轴表示位移变化。曲线的斜率反映出运动的数度。

缓动效果在Flash动画中比较常见,用于模拟一些现实中常见的运动轨迹,或者制造一些超绚的效果。
而且新版本的Flash中,内置了一些常用的缓动曲线函数。

可惜,Flash的这些曲线函数不是开源的,我们不知道内部如何实现,也就无法将其移植到JS中。感受其绚丽的同时,未免有一丝遗憾。

于是乎,自己琢磨琢磨。

首先,我对Flash的渐变函数接口非常不满。
搞那么多参数干吗?
要描述一个区间的渐变运动特征,只需一个y = f(x)足已。那么一大堆参数,真够罗嗦。
//原理:我们以终点位移为参考,只需要知道中间个点相对于最终位移,我们就能确定运动的规律。
y= f(x)
//约定
//x ∈ [0,1] #将x变化换算成[0,1]是最简单不过的操作
//f(0) = 0 #运动是连续的嘛^_^.
//f(1) != 0 #如果f(1) = 0了,那不就没有运动嘛,中间即使有位移,我也无法计算中间的位移相对于总体位移的比例。

曲线转换
每种类型的渐变都有三种变形

渐入(in)

在过渡的开始提供缓动效果。

渐出(out)

在过渡的结尾提供缓动效果。

渐入渐出(inOut/Both)

在过渡的开始和结尾提供缓动效果。


其中,我们只要知道一个的曲线,其他两个都可以转换生成:
知道渐入曲线之后,将其相对于(0.5,0.5)点绘制镜像,就是一个缓出运动,分段叠加就是一个完整的缓入缓出运动。



首先,常见的加速/减速运动:
初中物理就能搞定。
加速渐变函数为(easeIn):
y=x*x; //y轴比例常数无需考虑

这是一个简单的2次曲线,表现一个渐入运动。
简单的变换一下:y = 1-(1-x)*(1-x) 减速运动(easeOut)
复杂一点:
y = x>0.5? 1-2(1-x)*(1-x) :
2*x*x :
先加速后减速运动(easeBoth)




既然有二次曲线,很自然就想到三次、四次曲线。是的,这些曲线都有类似特征,区别在中间更陡峭,两头平缓(缓入缓出)

接下来,我就想实现一下弹动效果:

这类效果就好像一个甲虫飞到蜘蛛网上,在网上抖动两下,静下来听天由命。
抖动,周期运动,好,我们很快就想到正弦曲线。
方法基本正确,不过我起初还是走弯路了,我自作聪明的想着延长开始的半周期(x轴边形处理,振动让周期先大后小)。
但最终发现效果非常不理想,最后查看yui的实现。模仿一下,走出了这个误区。
我们通常看到的振荡移位效果,都是开始移动了较长位移,给人一种开始的振动周期更长的错觉,振动周期是不需要变化的。
纠正这个错误后,实现曲线函数如下:

y = Math.pow(1024,x-1)*Math.sin(x*((2*(period||1)+0.5)*Math.PI));

利用指数函数的第二象限的渐变特征变形,取处理正弦波形的振幅,达到一个衰减的效果。



趁热打铁,看看yui的其他几类渐变效果:

回退起步效果。
喜欢看动画片的话,你一定记得这个常见的场面,当一个家伙想快跑的时候,一点要先回撤一段距离,能后如突然加速前进。ok要的就是这个效果。
实现其实也很简单,一个二次曲线就可以搞定

y = x*(x-(backDistance||0.1)*4)



撞墙效果

这个名字可能不太合适吧,应该叫撞地效果更合适,鉴于撞墙这个名词更常见一些,也就标题党一回好了:)
玩过弹球吧,弹球的运动规律一定还记得。
对就是这种轨迹。
运功轨迹就是若干条二次曲线的分段拼接。改写一个yui里面的模拟实现。

this.bounceOut = function (x) {
if (x < (1/2.75)) {
return x*x;
} else if (x < (2/2.75)) {
return (x-=(1.5/2.75))*x + .75/7.5625;
} else if (x < (2.5/2.75)) {
return (x-=(2.25/2.75))*x + .9375/7.5625;
}
return (x-=(2.625/2.75))*x + .984375/7.5625;
};
这里手动指出了一大堆参数,其实,这些参数都可以通过计算得出,偷个懒,就这么地吧,^_^
分享到:
评论
9 楼 jindw 2007-10-15  
hax 写道
jindw 写道
hax 写道

如果运动方程使用自定义函数的话,函数f(x)应该在[0,1]区间上有定义,并满足f(0)=0, f(1)=1。


这个f(1)=1约束还是可以省去的.
只要f(1) != 0就可以了,我们要的只是一个比例.如果强制f(1)=1,那又多出了一处比例换算.

不过,加上这个约束也有一个好处,那就是方程变换的时候简单一些.



是可以省去,直接f'(x) = f(x) / f(1)用f'就可以了。实际上甚至f(0)=0也不必满足,因为总是可以换算到[0,1]区间上。不过做好规约比较严谨一点,你可以提供一个额外的换算函数来协助用户进行方程变换。

function map01(f, x0, x1) {
  x0 = x0 || 0
  x1 = x1 || 1
  x10 = x1 - x0
  f0 = f(x0)
  f1 = f(x1)
  f10 = f1 - f0
  return function (x) {
    return (f(x * x10 + x0) - f0) / f10
  }
}


从实现来看,省略f(1) =1的约束是可以简化程序的,而省略f(0) =0,回增加代码。

反正我们需要的是一个高度的相对比例。

我们只要再动画开始计算出 var end = f(1)
能后每点的位移是
y = f(x)*max/end;


如果我们要强制f(1) =1。
那么:  f(x) = f(x)/end;
y=(f(x)/end)*max;

看似代码一样,但是一般的实现来说,最终的换算是在统一的地方,我们完全可以吧这个换算放再这个统一的地方。而让繁多的曲线函数的代码简单一些。

但是,如果我们允许 f(0) !=0.
那么程序就繁杂多了。
var begin = f(0)
y=((f(x)-begin )/(end-begin))*max;


写到这里,都有点怀疑自己的立场了,呵呵,不过,还是坚持我的观点,为什么?呵呵,一个有点差强的理由,省略f(1) ==1 不会影响程序效率,而省略 f(0) ==0则有点
8 楼 fins 2007-10-15  
我以前做过一些类似的东西(但不是js的)
利用的就是 物理里面的运动学基础知识.

我把楼主说的那些网页特效当作是一个3维空间内的运动.
如 移动可以看作是  X Y轴上的变化.
淡入淡出可以看作是Z轴上的变化.

常规运动可以分为:
匀速运动
匀加速运动
匀减速运动
"加速度匀速变大"的变加速(加速度<0时为变减速)运动
"加速度匀速减小"的变加速(加速度<0时为变减速)运动

具体是那种运动,由初速度 加速度 时间 当前位置 这4者来决定.

把网页效果用运动学的知识来模拟.

例如弹球运动, 传入位置(高度) 重力加速度, 每次碰撞损失的动能(忽略空气阻力等,只记录碰撞损耗)

程序自动演算出运动情况.

平抛运动 传入位置, XY初速度,  重力加速度, X加速度(<0),

很多复杂的运动 如类似正弦曲线那种 都可以通过对加速度的控制来实现.

7 楼 hax 2007-10-15  
jindw 写道
hax 写道

如果运动方程使用自定义函数的话,函数f(x)应该在[0,1]区间上有定义,并满足f(0)=0, f(1)=1。


这个f(1)=1约束还是可以省去的.
只要f(1) != 0就可以了,我们要的只是一个比例.如果强制f(1)=1,那又多出了一处比例换算.

不过,加上这个约束也有一个好处,那就是方程变换的时候简单一些.



是可以省去,直接f'(x) = f(x) / f(1)用f'就可以了。实际上甚至f(0)=0也不必满足,因为总是可以换算到[0,1]区间上。不过做好规约比较严谨一点,你可以提供一个额外的换算函数来协助用户进行方程变换。

function map01(f, x0, x1) {
  x0 = x0 || 0
  x1 = x1 || 1
  x10 = x1 - x0
  f0 = f(x0)
  f1 = f(x1)
  f10 = f1 - f0
  return function (x) {
    return (f(x * x10 + x0) - f0) / f10
  }
}
6 楼 笨笨狗 2007-10-14  
可以参考一下script.aculo.us的曲线函数,内置了不少呢
5 楼 jindw 2007-10-14  
hax 写道

如果运动方程使用自定义函数的话,函数f(x)应该在[0,1]区间上有定义,并满足f(0)=0, f(1)=1。


这个f(1)=1约束还是可以省去的.
只要f(1) != 0就可以了,我们要的只是一个比例.如果强制f(1)=1,那又多出了一处比例换算.

不过,加上这个约束也有一个好处,那就是方程变换的时候简单一些.

4 楼 hax 2007-10-14  
我以前曾经写过Tween类,用来达到类似flash的补间效果。

用法如下:
new Tween(div.style, 'left', new Measure(div.style.left), new Measure('0px'), 3000, 40, Math.sqrt);
表示产生一个补间动画,让div.style.left在3秒内从当前的值变到0px。刷新间隔为40毫秒,运动方程是Math.sqrt。

最后两个参数可以省略,默认间隔是40毫秒,默认方程是Tween.linear,此外Tween上还提供了Tween.quadic方程。

如果运动方程使用自定义函数的话,函数f(x)应该在[0,1]区间上有定义,并满足f(0)=0, f(1)=1。



代码如下:
(代码仅供参考,因为没有包括所有用到的方法,所以不能直接运行)
	Tween.prototype.start = function () {
		this.startTime = new Date().getTime();
		this.before();
		this._task = setTimeout(refresh, this.tick);
		var self = this;
		function refresh() {
			self.refresh();
		}
	}

	Tween.prototype.stop = function () {
		//clearInterval(this._task);
		this.after();
		this.startTime = null;
	}

	Tween.prototype.refresh = function () {
		var offset = new Date().getTime() - this.startTime;
		var x = offset / this.time;
		if (x >= 1) {
			this.stop();
		} else {
			var y = this.f(x);
			var v = this.toValue.minus(this.fromValue).multiply(y).plus(this.fromValue);
			this.assign(v);
			this._task = setTimeout(refresh, this.tick);
		}
		var self = this;
		function refresh() {
			self.refresh();
		}
	}

	Tween.linear = function linear(x) { return x; }
	Tween.quadric = function quadric(x) { return 1 - Math.sqrt(1 - x * x); }

	function Tween(target, field, fromValue, toValue, time, tick, f) {
		
		this.fromValue = fromValue;
		this.toValue = toValue;
		this.time = time;
		this.tick = tick || 40;
		this.f = f || Tween.linear;
		
		this.before = new EventHandler();
		this.after = new EventHandler();

		this.before.add(function () {
			this.assign(this.fromValue);
		});
		this.after.add(function () {
			this.assign(this.toValue);
		});
		
		if (isFunction(field)) {
			this.assign = function (value) {
				field.call(target, value);
			}
		} else if (isFunction(target[field])) {
			this.assign = function (value) {
				target[field](value);
			}
		} else {
			this.assign = function (value) {
				target[field] = value;
			}
		}

	}
	Number.prototype.plus = function (x) {
		assert (isNumber(x));
		return this + x;
	}

	Number.prototype.minus = function (x) {
		assert (isNumber(x));
		return this - x;
	}

	Number.prototype.multiply = function (x) {
		if (isNumber(x))
			return this * x;
		if (x.multiply)
			return x.multiply(this);
		assert (false);
	}

	Number.prototype.divide = function (x) {
		assert (isNumber(x));
		return this / x;
	}
	Measure.prototype.plus = function measure_plus(x) {
		if (this.unit == x.unit)
			return new Measure(this.qt + x.qt, this.unit);
		assert (false, String.concat(this, ' is incompatible with ', x));
	}

	Measure.prototype.minus = function measure_minus(x) {
		if (this.unit == x.unit)
			return new Measure(this.qt - x.qt, this.unit);
		assert (false, String.concat(this.unit, ' is incompatible with ', x.unit));
	}

	// TODO: composite unit
	Measure.prototype.multiply = function measure_multiply(x) {
		if (isNumber(x))
			return new Measure(this.qt * x, this.unit);
		assert (false, String.concat(x));
	}

	Measure.prototype.divide = function measure_divide(x) {
		if (isNumber(x))
			return new Measure(this.qt / x, this.unit);
		else if (Measure.isInstance(x) && this.unit == x.unit)
			return this.qt / x.qt;
		assert (false);
	}

	Measure.prototype.toString = function measure_toString(x) {
		return String.concat(this.qt, this.unit);
	}

	function Measure(qt, unit) {
		if (!isNumber(qt)) {
			var s = /[0-9.+-]*/(qt)[0];
			unit = String.substring(qt, s.length);
			qt = parseFloat(s);
		}
		this.qt = qt;
		this.unit = unit;
	}
3 楼 outrace 2007-10-14  
google的code网站里面
搜索tweener项目。ou
里面有很多曲线函数
2 楼 afcn0 2007-10-14  
以前也写过加速减速动画代码,也发上来
1 楼 jindw 2007-10-14  
<font size='7'><strong><a>演示url </a>(</strong><strong><font color='#ff0000'>IE</font></strong><strong><font color='#ff0000'>不支持)</font></strong></font>

相关推荐

    动画缓动效果

    标题中的“动画缓动效果”是指在数字艺术和交互设计中,通过精心设计的时间变化曲线,使得动画过渡更加平滑自然的技术。缓动效果通常应用于网页、游戏、应用程序和其他交互式媒体,为用户提供更优质的视觉体验。缓动...

    greensock-js,js网页动画用到的缓动类库

    缓动是动画中一种重要的技术,它指的是物体在运动过程中的速度变化。在真实世界中,物体的加速和减速并非瞬间完成,而是有一个渐变的过程。缓动函数就是模拟这种物理现象,使动画看起来更加自然和流畅。GreenSock JS...

    flash水波制作与缓动的源文件

    在本文中,我们将深入探讨Flash中的水波制作与缓动技术。...通过深入研究提供的源文件,初学者不仅可以学习到如何创建水波动画,还能掌握如何运用缓动技术,从而在自己的作品中实现更加生动和流畅的运动效果。

    防妙味课堂运动框架

    2. **缓动函数**:为了使动画看起来更加自然,运动框架通常会提供各种缓动函数。这些函数可以改变动画的速度曲线,例如从慢到快,或者从快到慢,让动画过渡更加平滑。 3. **帧动画**:通过在每一帧更新元素的样式,...

    tweener包 flash缓动

    - Tweener支持多种缓动函数,如Linear、Quad、Cubic、Quart、Quint、Sine、Expo、Circ、Elastic、Back、Bounce等,每种函数都有其独特的运动轨迹,可以创造出各种动态效果。 3. **链式调用**: - Tween类的方法...

    IOS应用源码——贝塞尔曲线demo:一个运动的物体:PathMove for iOS.zip

    在源码中,可能会有对`CAKeyframeAnimation`的初始化、设置动画时长、动画曲线(如线性、缓进缓出等)以及添加到目标层的相关代码。 此外,为了实现动态效果,可能还会涉及到定时器(NSTimer或CADisplayLink)来...

    超级缓动-模块+示例源码分享-易语言

    "超级缓动-模块+示例源码分享-易语言"这个资源提供了一个专用于易语言的缓动效果实现模块,以及相关的示例源代码,这对于学习和理解易语言中的动画和过渡效果的处理是非常有价值的。 首先,让我们来深入了解一下"缓...

    TweenMax.js实现超逼真的蜘蛛网与彩色蜘蛛爬行动画效果源码.zip

    3. **缓动函数**(Easing Functions):TweenMax.js包含各种缓动函数,可以创建出各种动态效果。比如,蜘蛛爬行时可能会使用缓入缓出效果,使得动作看起来更真实。 4. **事件监听**:通过添加事件监听器,可以在...

    购物车类的抛物线动画(支持上抛或者下抛) && 阻尼动画(弹球动画).zip

    在实际应用中,我们可以使用物理引擎如Box2D,或者通过自定义的缓动函数来实现这种效果。 **开源项目** 这个开源项目提供了实现购物车抛物线和阻尼动画的代码,对于开发者来说,这是一个很好的学习资源。通过研究...

    智能仓储系统RGV柔性运动控制的研究.pdf

    结果表明,仿真测试速度曲线与理论模型相吻合,加减速速度曲线变化趋势平滑稳定,缓启缓停效果明显,各阶段介入减速模式均能以设计波形曲线完成减速过程。 本文对RGV柔性运动控制的研究,为智能仓储系统提供了一种...

    轮播图缓动例子分享-易语言

    1. **动画原理**:缓动效果的核心在于通过动画来模拟真实世界中的物理运动,如物体的加速、减速过程。这通常涉及到时间函数,如线性、二次、三次贝塞尔曲线等,它们可以改变动画的速度曲线,使过渡更加自然。 2. **...

    TweenMax.js+svg实现的小蜜蜂振翅飞行动画效果源码.zip

    它可能会定义时间轴,设置动画的开始、结束状态,以及选择合适的缓动函数来模拟真实世界的物理运动。 3. CSS样式:可能包含了一些基础的样式定义,如元素的位置、大小、颜色等,这些属性也可能会被JavaScript动画所...

    HTML5_JavaScript动画基础(高清带目录)

    例如,线性运动、缓动运动、弹性运动等。 4. 动画的触发:动画可以通过事件触发,如鼠标点击、触屏操作、计时器事件等。理解这些事件监听和处理是创建交互式动画的基础。 5. CSS动画和过渡:虽然重点是HTML5和...

    纯CSS3实现的山谷日落风车动画效果源码.zip

    5. **Timing Functions**:时间函数决定了动画速度变化的曲线,比如线性(linear)、缓入(ease-in)、缓出(ease-out)等。通过定制时间函数,我们可以让动画看起来更加自然或突然。 6. **Pseudo-elements (`::...

    Flash氏量金鱼动画 水泡特效.rar

    3. **运动路径与缓动效果**:水泡上升的路径不是直线,而是曲线,这需要利用Flash的“引导层”和“运动路径”功能。同时,通过添加缓动函数(Ease Effect),可以使水泡的上升速度有快有慢,增加视觉的流畅感。 4. ...

    线条动画flash

    7. **动画原理**:理解基本的动画原理,如缓动、物理规律和视觉欺骗,有助于创作流畅自然的线条动画。例如,缓动函数可以使动画的起始和结束部分看起来更平滑。 8. **预览与发布**:完成动画后,可以使用Flash的...

    Flash随机生成的气泡动画.rar

    此外,可能还涉及到动画的缓动效果(easing),使得气泡的上升或下降速度在过程中有所变化,增加真实感。缓动函数在ActionScript中有多种实现,如easeIn、easeOut和easeInOut,可以根据需求选择合适的缓动类型。 在...

    ios-金币弹出动画.zip

    9. **动画的缓动函数(Timing Functions)**:可以自定义动画的速度曲线,比如线性、Ease In、Ease Out、Ease In Ease Out等,使得动画的开始和结束速度不同,增加真实感。 10. **动画的延迟和重复**:通过设置`...

Global site tag (gtag.js) - Google Analytics