RoughEase.as
9.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/**
* VERSION: 0.6
* DATE: 1/19/2010
* AS3
* UPDATES AND DOCUMENTATION AT: http://www.GreenSock.com/roughease/
**/
package com.greensock.easing {
/**
* Most easing equations give a smooth, gradual transition between the start and end values, but RoughEase provides
* an easy way to get a rough, jagged effect instead. You can define an ease that it will use as a template (like a
* general guide - Linear.easeNone is the default) and then it will randomly plot points that wander from that template.
* The strength parameter controls how far from the template ease the points are allowed to go (a small number like
* 0.1 keeps it very close to the template ease whereas a larger number like 2 creates much larger jumps). You can
* also control the number of points in the ease, making it jerk more or less frequently. And lastly, you can associate
* a name with each RoughEase instance and retrieve it later like RoughEase.byName("myEaseName"). Since creating
* the initial RoughEase is the most processor-intensive part, it's a good idea to reuse instances if/when you can.<br /><br />
*
* <b>EXAMPLE CODE</b><br /><br /><code>
* import com.greensock.TweenLite;<br />
* import com.greensock.easing.RoughEase;<br /><br />
*
* TweenLite.from(mc, 3, {alpha:0, ease:RoughEase.create(1, 15)});<br /><br />
*
* //or create an instance directly<br />
* var rough:RoughEase = new RoughEase(1.5, 30, true, Strong.easeOut, "none", true, "superRoughEase");<br />
* TweenLite.to(mc, 3, {y:300, ease:rough.ease});<br /><br />
*
* //and later, you can find the ease by name like:<br />
* TweenLite.to(mc, 3, {y:300, ease:RoughEase.byName("superRoughEase")});
* </code><br /><br />
*
* <b>Copyright 2010, GreenSock. All rights reserved.</b> This work is subject to the terms in <a href="http://www.greensock.com/terms_of_use.html">http://www.greensock.com/terms_of_use.html</a> or for corporate Club GreenSock members, the software agreement that was issued with the corporate membership.
*
* @author Jack Doyle, jack@greensock.com
*/
public class RoughEase {
/** @private **/
private static var _all:Object = {}; //keeps track of all instances so we can find them by name.
/** @private **/
private static var _count:uint = 0;
/** @private **/
private var _name:String;
/** @private **/
private var _first:EasePoint;
/** @private **/
private var _last:EasePoint;
/**
* Constructor
*
* @param strength amount of variance from the templateEase (Linear.easeNone by default) that each random point can be placed. A low number like 0.1 will hug very closely to the templateEase whereas a larger number like 2 will allow the values to wander further away from the templateEase.
* @param points quantity of random points to plot in the ease. A larger number will cause more (and quicker) flickering.
* @param restrictMaxAndMin If true, the ease will prevent random points from exceeding the end value or dropping below the starting value. For example, if you're tweening the x property from 0 to 100, the RoughEase would force all random points to stay between 0 and 100 if restrictMaxAndMin is true, but if it is false, a x could potentially jump above 100 or below 0 at some point during the tween (it would always end at 100 though).
* @param templateEase an easing equation that should be used as a template or guide. Then random points are plotted at a certain distance away from the templateEase (based on the strength parameter). The default is Linear.easeNone.
* @param taper to make the strength of the roughness taper towards the end or beginning, use "out" or "in" respectively here (default is "none") .
* @param randomize to randomize the placement of the points, set randomize to true (otherwise the points will zig-zag evenly across the ease)
* @param name a name to associate with the ease so that you can use RoughEase.byName() to look it up later. Of course you should always make sure you use a unique name for each ease (if you leave it blank, a name will automatically be generated).
*/
public function RoughEase(strength:Number=1, points:uint=20, restrictMaxAndMin:Boolean=false, templateEase:Function=null, taper:String="none", randomize:Boolean=true, name:String="") {
if (name == "") {
_count++;
_name = "roughEase" + _count;
} else {
_name = name;
}
if (taper == "" || taper == null) {
taper = "none";
}
_all[_name] = this;
var a:Array = [];
var cnt:uint = 0;
var x:Number, y:Number, bump:Number, invX:Number, obj:Object;
var i:uint = points;
while (i--) {
x = randomize ? Math.random() : (1 / points) * i;
y = (templateEase != null) ? templateEase(x, 0, 1, 1) : x;
if (taper == "none") {
bump = 0.4 * strength;
} else if (taper == "out") {
invX = 1 - x;
bump = invX * invX * strength * 0.4;
} else {
bump = x * x * strength * 0.4;
}
if (randomize) {
y += (Math.random() * bump) - (bump * 0.5);
} else if (i % 2) {
y += bump * 0.5;
} else {
y -= bump * 0.5;
}
if (restrictMaxAndMin) {
if (y > 1) {
y = 1;
} else if (y < 0) {
y = 0;
}
}
a[cnt++] = {x:x, y:y};
}
a.sortOn("x", Array.NUMERIC);
_first = _last = new EasePoint(1, 1, null);
i = points;
while (i--) {
obj = a[i];
_first = new EasePoint(obj.x, obj.y, _first);
}
_first = new EasePoint(0, 0, _first);
}
/**
* This static function provides a quick way to create a RoughEase and immediately reference its ease function
* in a tween, like:<br /><br /><code>
*
* TweenLite.from(mc, 2, {alpha:0, ease:RoughEase.create(1.5, 15)});<br />
* </code>
*
* @param strength amount of variance from the templateEase (Linear.easeNone by default) that each random point can be placed. A low number like 0.1 will hug very closely to the templateEase whereas a larger number like 2 will allow the values to wander further away from the templateEase.
* @param points quantity of random points to plot in the ease. A larger number will cause more (and quicker) flickering.
* @param restrictMaxAndMin If true, the ease will prevent random points from exceeding the end value or dropping below the starting value. For example, if you're tweening the x property from 0 to 100, the RoughEase would force all random points to stay between 0 and 100 if restrictMaxAndMin is true, but if it is false, a x could potentially jump above 100 or below 0 at some point during the tween (it would always end at 100 though).
* @param templateEase an easing equation that should be used as a template or guide. Then random points are plotted at a certain distance away from the templateEase (based on the strength parameter). The default is Linear.easeNone.
* @param taper to make the strength of the roughness taper towards the end or beginning, use "out" or "in" respectively here (default is "none") .
* @param randomize to randomize the placement of the points, set randomize to true (otherwise the points will zig-zag evenly across the ease)
* @param name a name to associate with the ease so that you can use RoughEase.byName() to look it up later. Of course you should always make sure you use a unique name for each ease (if you leave it blank, a name will automatically be generated).
* @return easing function
*/
public static function create(strength:Number=1, points:uint=20, restrictMaxAndMin:Boolean=false, templateEase:Function=null, taper:String="none", randomize:Boolean=true, name:String=""):Function {
return new RoughEase(strength, points, restrictMaxAndMin, templateEase, taper, randomize, name).ease;
}
/**
* Provides a quick way to look up a RoughEase by its name.
*
* @param name the name of the RoughEase
* @return easing function from the RoughEase associated with the name
*/
public static function byName(name:String):Function {
return _all[name].ease;
}
/**
* Easing function that interpolates the numbers
*
* @param t time
* @param b start
* @param c change
* @param d duration
* @return Result of the ease
*/
public function ease(t:Number, b:Number, c:Number, d:Number):Number {
var time:Number = t / d;
var p:EasePoint;
if (time < 0.5) {
p = _first;
while (p.time <= time) {
p = p.next;
}
p = p.prev;
} else {
p = _last;
while (p.time >= time) {
p = p.prev;
}
}
return b + (p.value + ((time - p.time) / p.gap) * p.change) * c;
}
/** name of the RoughEase instance **/
public function get name():String {
return _name;
}
public function set name(s:String):void {
delete _all[_name];
_name = s;
_all[s] = this;
}
}
}
internal class EasePoint {
public var time:Number;
public var gap:Number;
public var value:Number;
public var change:Number;
public var next:EasePoint;
public var prev:EasePoint;
public function EasePoint(time:Number, value:Number, next:EasePoint) {
this.time = time;
this.value = value;
if (next) {
this.next = next;
next.prev = this;
this.change = next.value - value;
this.gap = next.time - time;
}
}
}