2つ前の記事で初めて作ったエクスプレッションを効率的に記述できないか、について触れました。
できます。「変数」を使います。
After Effectsの「変数」
After EffectsのエクスプレッションはJavaScriptというプログラム言語ですので、変数(variable)が使用できます。判定の甘いJavaScriptなら尚更とっつきやすいことでしょう。
ただし、After Effectsがあらかじめ用意した変数もあるのです。これは予約された単語なので、改めて同じ単語を独自の変数として使えないという制限があります。
前々回使用した「index」などがそれです。ソフト側で用意された変数があり、例えばテキストレイヤーのソーステキストに
var index=9999;
index; // 正しいインデックス番号になってしまう。
と打ち込んでも、そのレイヤー番号が「1」なら、「1」と表示されてしまうのです。つまり、エラーは出ず、意図しない結果が返ってきますので、注意しましょう。
長いプログラムを書く中で、同じ変数を宣言して上書きしてしまうなど、エラーの温床となることも多いので、コメントを活用したり、「a=」などでなく重複しづらい変数を使ったりとしっかりと管理してエラーを予防する必要があります。
ちなみに…
そんな中、2015年から「JavaScript自体」には上記のような宣言がユルユルなところに、もっと厳格な宣言が必要だということで「var」「let」「const」と3種類に増えました。そのため教材を新しいwebサイトで得ようとすると、これらが出てきますが、少なくともAfter Effects2020.5日本語版ではエラーとなり上手く動作しません。
「var」は省略してもエラーとなりません。ただし、省略した場合扱いが微妙に異なりますので、違いを知った上で省略して問題のないちょっとしたプログラムの場合は、「var」を省略して書いています。
もちろん、これからAdobe製品以外のJavaScriptを覚える方には、再代入や再宣言をエラーで教えてくれる「const」を基本的に使うよう推奨します。あくまでこのサイトでは、After Effectsでは「var」を使う、もしくは省略するかたちで昔から作ったプログラムを紹介しますのでご了承ください。
エクスプレッションが見やすくなった
さて、本題に戻ります。
After Effects 2020の場合、エクスプレッションが演算式やカッコ、意味を持つ単語を書くと色分けされるようになっており、エディタとしてとても見やすくなっています。
といっても、他のJavaScriptを認識するエディタを完全に使わなくなるワケではありません。確かにAfter Effects内でエクスプレッションを記述する場合、After Effects独自のプロパティを色分けしてくれる利点はあるのですが、なにせ狭い。
長いエクスプレッションを全画面で俯瞰するには、私はエディタが必要です。スクリプトを作るためのExtendscript Toolkitか、ATOMを使用して、書いてはすぐAfter Effectsにコピペするのです。
After Effectsバージョン2020時点では、After Effects上にエクスプレッションを打ち込んで、黄色になるテキストが自分で使用できない変数です。どう考えても正しい計算結果が得られない時、この予約された変数を使っていないか確認しましょう。
前々回作成したエクスプレッション
(thisComp.layer("root").index-thisLayer.index)/
(thisComp.layer("root").index-thisComp.layer("goal").index)*
(thisComp.layer("goal").transform.position-
thisComp.layer("root").transform.position)+
thisComp.layer("root").transform.position;
※サイト上で見やすいように改行していますが、JavaScript上では改行は処理の区切りとみなされエラーが起こります。実際は全て1行に書くか、改行は四則演算もしくは=の直後に行うルールになっています。
この中で、「(thisComp.layer(“root”)」「(thisComp.layer(“goal”)」が複数回登場します。これを変数に仕舞えれば短くできそうです。
実際に変数を使う
それでは長くて見にくい、複数回出てくるプロパティを変数に入れてみます。まずは自分がわからなくならない名称を付けて短くしてみましょう。
数値も文字列も配列も入れられる
JavaScriptの柔軟性として、変数には数値も文字列も配列も特に宣言方法を変えず「var」で格納することができます。宣言時にデータの型を区別しなくていいというメリットがある反面、デメリットとしては、使用時には変数内の型に合った処理しかできないため、データの型を自身で覚えておいて、正しく呼び出す必要がある点です。
var a=1;
var b="1";
var c=[20,30];
a+1; // 2
b+1; // 11
c+1; // 21,30
配列を3つ用意しました。aに数値、bに文字列、cに配列を代入し、それぞれ+1してみました。
数値と文字列の違い
aは数値の1なので、+1すると「2」、
bは「” “」で囲まれると文字列なので、+1は文字列”1″と1を連結という意味になり、「11」、
cは配列なので、配列の1つ目に+1と自動的に判断し、「21」と「30」の2つの数値を配列として持っている状態になります。
このように、数値+数値は「足し算」、文字列を含むと「連結」、配列は通常「c[0]」で「20」、もしくは「c[1]」で「30」と、何番目の値か指定して取り出してから計算させるのがルールです。
四則演算がエラーになる場合、どこかに文字列がないか確認してください。
文字列となってしまった数字を明示的に数値に変換したい場合は「Number()」関数を使います。
var b="1";
Number(b)+1; // 2
これで「2」にすることができます。
Number()でも数字以外を数字に変換することはできません。
var b="あいうえお";
Number(b)+1; // NaNエラー
文字列”あいうえお”はどう頑張っても数字にならないので、”NaN”(Not a Number)つまり「数字じゃねぇですよ」とエラーが返ってきます。
プロパティを変数に入れる
文字列も変数に入れられると分かったところで、「(thisComp.layer(“root”)」は「root」、「(thisComp.layer(“goal”)」は「goal」変数に入れます。JavaScriptのルールとして、「これから書く単語を変数として登録します」と宣言してから入れます。これが「var」です。
宣言は無くても動くのがJavaScriptの柔軟性です。しかし宣言を省略しない場合とした場合では扱いが微妙に変わりますので、仕様を学ぶまでは、きちんと書いていくことにします。
- 「var」でこれから変数を作ることを宣言(省略してもエラーは出ない)
- 「変数(root or goal)」(必要)
- 「=」で繋ぎ
- 代入する値「thisComp.layer(“root or goal”)」を指定
- 式の終わりはルールで「;」で締めます。
var root=thisComp.layer("root");
var goal=thisComp.layer("goal");
出来ました。この記述より下では、「root」は「thisComp.layer(“root”)」と同じ意味に、「goal」は「thisComp.layer(“goal”)」と同じ意味になります。つまり、以降実行されるプログラムでは、「thisComp.layer(“root”)」「thisComp.layer(“goal”)」を「root」「goal」で呼び出せるようになったのです。
「=」と代入する値はなしで、変数の宣言だけをすると、空(undefined)の変数を作ることが出来、エラーは出ません。通常宣言した変数はなにかを代入する際に必要なので、空の変数を宣言することはあまりないでしょう。
また、複数の宣言を「,」でまとめられます。1つのカゴに複数の値を入れる「配列」とは異なり、1つの変数の宣言を連続して行うことです。
上記の「var」は1つにできます。
var root=thisComp.layer("root"),
goal=thisComp.layer("goal");
この場合「,」は宣言の連結となり、1つの「var」で「root」と「goal」をまとめて宣言したことになります。プログラムを書き終えたら、まとめられる宣言があればプログラムの初めにまとめたほうが、全体で使われている変数を把握しやすくなるためおすすめします。
他の方のプログラムを見ると、初めにいくつもの変数をまとめて宣言しているのをよく見ます。
変数で置き換える
ではせっかく入れた変数と、長ったらしいプロパティを置き換えていきます。
var root=thisComp.layer("root"),
goal=thisComp.layer("goal");
(root.index-thisLayer.index)/(root.index-goal.index)*
(goal.transform.position-
root.transform.position)+
root.transform.position;
短くなった上、自分が見やすい名前を付けられるので、大分読みやすくなったと思いませんか?
もちろん、もっと短い単語を使用することもできます。「thisLayer」も省略できます。そして実はこの場合の「.transform」も省略できるプロパティです。どれが省略できてどれができないのかは決まっていますので、必要になったらスクリプトであれば斉藤 寛氏のリファレンスを漁ってみてください。
root=thisComp.layer("root");
goal=thisComp.layer("goal");
center=(goal.position-root.position);
(root.index-index)/(root.index-goal.index)*center+root.position;
このように、数字以外も変数に入れられるので、読みやすくエラーが少ないプログラムを書くことが可能です。変数に使う単語も、自分がわかりやすい名前を付けられるので、自分なりの名前付けのルールを持っておくと、混乱しづらくなります。
例えば「thisComp.layer(“root”)」なら「rLyr」にするなどです。
変数を短くするメリット・デメリット
変数を短くするメリットとしては、短いほうが自分が把握している内は見やすく、デメリットとしては逆に意味はわかりづらくなりますので、ある程度熟練するまでは意味の推測しやすい英単語を使用することをおすすめします。
とにかく短くしたほうがわかりやすいというのであれば、ある程度JavaScriptが書けるようになれば(変数を重複して上書きしないよう管理できる範囲なら)「a=thisComp.layer(“root”)」もアリです。
変数を短くするその他のメリット
また、変数が短いと、計算式本体が見やすくなるメリットがあります。
r=thisComp.layer("root");
g=thisComp.layer("goal");
ri=r.index;
gi=g.index;
rPos=root.position;
center=(goal.position-rPos);
例えばこのように変数側を頑張って準備してやると、計算式本体は
(ri-index)/(ri-gi)*center+rPos;
のように書けます。
変数はスペースを含むことが出来ませんので、「ルートのポジション」は「rPos」のように、単語の頭を大文字にする「キャメルケース」で名付けることが多いです。他には、
/* スネークケース */
r_pos
root_position
/* ケバブケース */
r-pos
root-position
このようにアンダーバーで単語を繋ぐスネークケース、ハイフンで繋ぐケバブケースと名前が付いた命名ルールがあります。どれを使っても良いですが、ルール統一しておくと、これは変数だとすぐに分かるようになります。美しいコードとは、無駄な処理がないことだけでなく、読みやすい記述ルールが定められているものです。
また、変数の宣言をまるまるすっ飛ばして(グローバル変数)いますが、エクスプレッションの場合は問題になることは少ないです。エクスプレッションは毎フレーム計算され、毎フレーム計算結果も変数も捨てているからです。一つのエクスプレッション内で変数宣言が重複した際に問題が出ることがほとんどなので、私見で恐縮ですが、「let」「const」が使えるまで、またはちょっとしたエクスプレッションでは「var」は省いて構いません。
その代わり、スクリプトであれば宣言なしで定義した変数は、次に初期化(var)されるまで残り続け、宣言していない変数が使えることがある挙動があります。スクリプトを作りたい方はこれだけ覚えておいてください。これを知ってさえいれば、その状況になったときに長時間悩まずに済むはずです。
その時々で適した書き方がありますので、使い分けられるようになるとプログラムの幅がぐっと広がります。
次回予告
さて、今回まででエクスプレッションでのアニメーションを例に、変数を使ってプログラム自体の効率化を実践しました。
次回はAfter Effects独自の関数、wiggle()で簡単にレイヤーを揺らしてみましょう。
スクリプト記事を追っている方はこちらから、
また、エクスプレッション記事を追っている方は下記リンクからどうぞ。
この記事へのコメントはありません。