接上一篇内容,新建文字层,输入“text”,添加Expression Selector,添加Position
给Expression Selector下的Amount添加表达式:
starValue = 100; endValue = 0; v = ease(time, textIndex - 1, textIndex, starValue, endValue); v
添加随机值
上面的效果,每个字母动画是按照从左到右的顺序的,我们希望给每个字母动画的时间随机值,让字母随机开始动画
starValue = 100; endValue = 0; r = (Math.floor(random(0,textTotal-1))+1)/textTotal; v = ease(time, textIndex-1+r, textIndex + r, starValue, endValue)
我们让random()在“0 ~ 字母总数减1”的范围内取随机值,比如这个例子里“text”只有4个字母,所以会在0~3之间取随机值,然后向下取整,也就是会得到0~3之间的整数,然后加1,得到1~4之间的整数,再除以textTotal。
直接用Math.ceil()效果是一样的:
starValue = 100; endValue = 0; r = Math.ceil(random(0,textTotal))/textTotal; v = ease(time, textIndex-1+r, textIndex + r, starValue, endValue)
这是一个很奇怪的效果,因为每一帧random都会随机取一次值,所以运动并不是连续的。
将随机数限定为一个字母计算一次
表达式写为:
starValue = 100; endValue = 0; seed = 1; i=0; v=starValue; last = 60; arr=[]; for (n=0;n<textTotal;n++){ arr.push(n+1); } rf=timeToFrames(time-inPoint); while(rf>=i){ l=arr.length; i++; if (l>0){ seedRandom(seed++,true); r = Math.floor(random(0, l - 1)); a=arr[r]; if (a==textIndex){ rt=framesToTime(rf-i-6); v = ease(rf, i, i + last, starValue, endValue) } arr.splice(r,1); } } v
计数数组的建立与随机取值
这里计数数组的建立是如下代码
arr=[]; for (n=0;n < textTotal;n++){ arr.push(n+1); }
arr = []声明一个数组,也可以写作:arr = Array();
然后利用for循环往里面添加元素:
for(初始化语句;条件1;增量语句){ //代码块1 }
for语句解释:先执行初始语句,接着条件1的判断为true,在执行代码块1,然后执行增量语句,然后条件1的判断,如此循环直到条件1为false。
push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度。
在这个例子里,n的初始值是0,满足n < textTotal 的条件,执行arr.push(n+1),也就是给数组arr[]添加元素“n + 1”,即“1”。
此时数组arr[]为[1]。
然后执行增量语句 n++ 得到结果为: n = 1
继续判断条件:n < textTotal
执行push,为arr[]添加元素“ 2 ”
继续执行增量语句 n++ 得到结果为: n = 2
再次判断条件:n < textTotal
执行push,为arr[]添加元素“ 3 ”
继续执行增量语句 n++ 得到结果为: n = 3
继续判断条件:n < textTotal
执行push,为arr[]添加元素“ 4 ”
继续执行增量语句 n++ 得到结果为: n = 4
继续判断条件:n < textTotal (这个例子里textTotal为 4 )
条件判断false,不再继续执行条件语句,循环结束
得到数组[1,2,3,4]
接着,利用random到数组[1,2,3,4]里去取随机值,如下语句:
seedRandom(seed++,true); r = Math.floor(random(0, arr.length - 1)); a = arr[r];
因为数组的索引index是从0开始计算的,本例中arr[0]为“1”,arr[2]为“3”,index最大值为3,也就是arr.length - 1
random()取值的时候,只能取0~3 ,也就是( 0 ~ arr.length - 1)的范围,然后括起来,在前面添加Math.floor()向下取整,本例中也就是返回0~3范围内的随机整数。
a = arr[r] 得到的就是[1,2,3,4]数组中的一个随机位置的值。
seedRandom则是让random()每一次计算取一次值,而不是每帧都去取一次值。
取完一次之后,就把取出来的这个数在arr中删去,利用aplice()方法,这里表达式写为:arr.splice(r,1);
splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目。
其语法为:
arrayObject.splice(index,howmany,item1,.....,itemX)
index 必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
howmany 必需。要删除的项目数量。如果设置为 0,则不会删除项目。
item1, ..., itemX 可选。向数组添加的新项目。
这样就能够保证下个”字母”取值完全不会重复。
这时候表达式写作:
starValue = 100; endValue = 0; seed = 1; arr = Array(); for (n = 0; n < textTotal; n++){//需将全角<改为半角 arr.push(n + 1); } seedRandom(seed++,true); r = Math.floor(random(0, arr.length - 1)); a = arr[r]; v = ease(time, textIndex, textIndex + 1, starValue, endValue); arr.splice(r,1); v
这时候的表达式并不会报错,但是并没有随机效果。
我的理解是,这个表达式只取出来一个随机值,需要添加一个循环语句,让表达式不断循环运算。
在此之前,利用timeToFrames将单位从秒改为帧。
添加whlie循环,将随机数限定为一个字母计算一次
starValue = 100; endValue = 0; seed = 1; i = 0; v = starValue; last = 60; arr = Array(); for (n = 0; n < textTotal; n++){ arr.push(n + 1); } rf=timeToFrames(time - inPoint); while(rf >= i){ i++; if (arr.length > 0){ seedRandom(seed++,true); r = Math.floor(random(0, arr.length - 1)); a = arr[r]; if (a == textIndex){ v = ease(rf, i, i + last, starValue, endValue) } arr.splice(r,1); } } v
我的理解是,用while循环运算,并限定a == textIndex时候,返回一次结果。
镜像曲线,添加反向动画
在rf = timeToFrames(time - inPoint)后面添加:
if (time > outPoint / 2 - inPoint / 2) { rf=-rf+timeToFrames(outPoint-inPoint); }
优化运动
添加一个弹性效果:
if (rf > i + 6) { v-= rate * Math.sin(2 * rt * 2 * Math.PI) / Math.exp(3 * rt); }
最后写成:
starValue = 100; endValue = 0; seed = 1; rate = 40; t = text.sourceText; if (time < outPoint/2-inPoint/2) { arr=Array(); for (n=0;n=i) { l=arr.length; i++; if (l>0) { seedRandom(seed++,true); r = Math.floor(random(0, l - 1)); a=arr[r]; if (a==textIndex) { rt=framesToTime(rf-i-6); v = ease(rf, i, i + 6, starValue, endValue) if (rf > i + 6) { v-= rate * Math.sin(2 * rt * 2 * Math.PI) / Math.exp(3 * rt); } } arr.splice(r,1); } } } if (time >= outPoint/2-inPoint/2) { i = 0; arr=Array(); for (n=0;n =i) { l=arr.length; i++; if (l>0){ seedRandom(seed++,true); r = Math.floor(random(0, l - 1)); a=arr[r]; if (a==textIndex) { rt=framesToTime(rf-i-6); v = ease(rf, i, i + 6, starValue, endValue) ; if (rf > i + 6) { v-=rate * Math.sin(2 * rt * 2 * Math.PI) / Math.exp(3 * rt); } } arr.splice(r,1); } } } v
只有上面之前添加的position,将其y轴改为300,效果为:
再添加scale,将值改为0;
添加rotation,将值改为45;
该文参考了贴吧“秋风_小径”的文章“AE文字层->表达式选择器的基础及进阶”
作者在另外一个帖子里有注释:
starValue = 100; //开始值 endValue = 0; //结束值 seed = 1; //随机种子,在下面使用speed++,每用一次自加一次,保证随机性 t = text.sourceText; //t为文字层文字 arr = Array(); //定义新数组 for (n = 0; n < t.length; n++) { arr.splice(n, 0, n + 1) //数组 删除从 n 处开始的零个元素,添加新的元素n+1,这里说白了就是往arr里面塞1 2 3 4.....一直塞到t.length...建立计数数组,这种方法很少见 } i = 0; v = starValue; //100 tv = 0; //0 rf = timeToFrames(time - inPoint); //获得层帧数 while (rf >= i) { //循环次数为文字个数,大于文字个数则跳出循环,为每个文字产生不同的缓入曲线 l = arr.length; i++; if (l > 0) { seedRandom(seed++, true); //设置随机种子 r = Math.floor(random(0, l - 1)); //将随机数求整 a = arr[r]; //从数组里取出随机数指定的元素 if (a == textIndex) { //若此元素与textIndex相等 textIndex取决于Based On选择的项目,比如当时Characters的时候,第一个字母的index就为0 rt = framesToTime(rf - i - 6); //则,将帧数减去i的次数减六.转换为时间, v = ease(rf, i, i + 6, starValue, endValue) //产生缓入缓出曲线,从100到0,时间从i到i+6,共七帧 if (rf > i + 6) { //若帧数大于i+6 tv = 20 * Math.sin(2 * rt * 2 * Math.PI) / Math.exp(3 * rt) //产生震荡曲线,与v共同控制产生最后的曲线,这个曲线持续时间比较长 } } arr.splice(r, 1); //arr删除r处的元素 } }//当层帧数大于循环次数,结束循环 if (time >= outPoint - 2) { //时间在层结束时间的前二秒内 i = 0; arrend = Array(); for (n = 0; n < t.length; n++) { arrend.splice(n, 0, n + 1) //同样建立从1到t.length的计数数组 } rfend = timeToFrames(time - outPoint + 2); //获得时间到层结束时间的前二秒之间的帧数.,在这个时间内完成结束曲线 while (rfend >= i) { //同样,为每一个字母都产生不同的曲线,完毕则跳出循环 l = arrend.length; i++; if (l > 0) { seedRandom(seed++, true); r = Math.floor(random(0, l - 1)); a = arrend[r]; //取出随机计数 if (a == textIndex) { //若等于textIndex rtend = framesToTime(rfend - i - 6); //则先帧数减去i减去6转换为时间 v = ease(rfend, i + 2, i + 6, endValue, starValue + 20) //产生缓入缓出曲线,时间为i+2到i+6共五帧,从0到120 tv = 20 * Math.sin(90 + 2 * rtend * Math.PI) / Math.exp(3 * rtend) //产生震荡曲线,与v共同控制产生最后的曲线 } arrend.splice(r, 1); //删去r元素 } } } v - tv //v-tv产生最终缓入缓出曲线,在层结尾有很大毛病
另外作者给了一个改良版,
改良版
starValue = 100; endValue = 0; seed = 1; t = text.sourceText; arr=Array(); for (n=0;n=i) { l=arr.length; i++; if (l>0){ seedRandom(seed++,true); r = Math.floor(random(0, l - 1)); a=arr[r]; if (a==textIndex) { rt=framesToTime(rf-i-6); v = ease(rf, i, i + 6, starValue, endValue) if (rf > i + 6) { tv = 20 * Math.sin(2 * rt * 2 * Math.PI) / Math.exp(3 * rt); } } arr.splice(r,1); } } if (time >= outPoint/2-inPoint/2) { i = 0; arr=Array(); for (n=0;n =i) { l=arr.length; i++; if (l>0){ seedRandom(seed++,true); r = Math.floor(random(0, l - 1)); a=arr[r]; if (a==textIndex) { rt=framesToTime(rf-i-6); v = ease(rf, i, i + 6, starValue, endValue) ; if (rf > i + 6) { tv = 20 * Math.sin(2 * rt * 2 * Math.PI) / Math.exp(3 * rt); } } arr.splice(r,1); } } } v-tv;
请登录以参与评论
现在登录