AE 脚本入门 2:产生更多随机平移的重复对象
Original...About 2 min
AE 脚本入门 2:产生更多随机平移的重复对象
需求
一个合成中放置 个相同的图片素材,每个图片在随机一段时间内从左端平移到右端。
本次动画内容和上期 其实差不多。
根据名称获取 item
首先,我们要获取合成和素材,它都属于 Item
类。但是 AE 的 API 似乎只提供了根据下标或内置 id 获取 item,因此我们来自己实现一个 findItemByName
。
这里有个 trick:app.project
和 FolderItem
的对象都是 ItemCollectionLike 的,即拥有 items[]
/item()
获取 item 的方法和 numItems
属性。这样就能遍历当前集合了。
由于存在文件夹分组,需要进行递归。如何判断?API 很蠢,它把所有的 item 分成了 3 类:合成,文件夹,素材。但是没有统一的标识符来,而是用了一个本地语言相关的 typeName
来表示它的 i18n 命名。
不过好在它下面提供了一个样例,用正则表达式暴力判断,可以直接复制过来用。
if (/Composition|Komposition|Composición|Composizione|コンポジション|컴포지션|Composição|Композиция|合成/.test(app.project.item(index).typeName)) {
// item is a composition
} else if (/Folder|Ordner|Carpeta|Dossier|Cartella|フォルダー|폴더|Pasta|Папка|文件夹/.test(app.project.item(index).typeName)) {
// item is a folder
}
如何知道当前 item 是想要的呢?用 item.name
判断即可。不过这样有个小问题,如果有重名就不行。所以如果想支持复杂点的查找,建议加上路径限定,如 path/to/item.ext
。
完整代码如下:
function findItemByName(name) {
// cur: either Item or ItemCollection, which is a collection of items
function impl(cur, name) {
for (var i = 1; i <= cur.numItems; i++) {
var it = cur.item(i);
if (it.name == name) {
return it;
}
if (/Folder|Ordner|Carpeta|Dossier|Cartella|フォルダー|폴더|Pasta|Папка|文件夹/.test(it.typeName)) {
var res = impl(it, name);
if (res) {
return res;
}
}
}
return undefined;
}
return impl(app.project, name);
}
这里注意一下,图片素材是带扩展名的,比如我的素材名叫 jdwl.png
,那么需要调用 findItemByName("jdwl.png")
。
加入图片吧
上一期中,我们直接使用 app.project.activeItem
作为当前操作的合成,这样容易误操作。现在我们有了 findItemByName
,便可以换个方法:
var comp = findItemByName("课程表"); // The comp item we want
var proto = findItemByName("jdwl.png");
考虑到操作的幂等性,操作前需要清空合成的所有图层:
function clearLayers(comp) {
while (comp.numLayers > 0) {
comp.layer(1).remove();
}
}
下面就是重复很多次创建图层了,相比上期没什么技术含量。
function addLayer(comp, proto) {
var layer = comp.layers.add(proto);
var w = comp.width,
h = comp.height;
var y1 = randf(h * 0.1, h * 0.9),
y2 = y1 + randf(-h * 0.1, h * 0.1);
// Set time
layer.inPoint = randf(0, comp.duration - 2);
layer.outPoint = layer.inPoint + randf(1.0, 2.0);
// Set position
clearKeys(layer.position);
layer.position.setValueAtTime(layer.inPoint, [-w * 0.15, y1]);
layer.position.setValueAtTime(layer.outPoint, [w * 1.15, y2]);
// Set rotation
layer.rotation.setValue((Math.atan2(y2 - y1, w * 1.3) * 180) / Math.PI);
}
完工!最终效果如下: