BLOG ブログ

2024-11-18

エクスプレッションと和解したい! AfterEffectsエクスプレッション基礎(1)「配列と変数と関数と・・・・・・」

エクスプレッションと和解したい! AfterEffectsエクスプレッション基礎(1)「配列と変数と関数と・・・・・・」

お初にお目にかかります。遊技機チーム デザイナーのAです。
入社してから1年と半年ほど、私にも遂にブログを書く機会が回ってきました。
まだまだデザイナーとして未熟者ではございますが、何卒よろしくお願いいたします。

さて、近頃は急に冷え込み、秋服で外に出てみれば体の震えも止まりません。
「震え」「振動」といえばAfterEffectsのエクスプレッション「wiggle」が頭に浮かびます。

・・・・・・・浮かびませんか? いいえ、浮かべてください。

みなさんはエクスプレッションを使っていますでしょうか。
前述した「wiggle」を始め、「random」や「time」など様々な場面で作業を効率化する心強い味方となってくれます。
ところがどっこい、少しでも記述を誤ればエラーを吐いて裏切ってくるのがエクスプレッション君です。
今回はそんなエクスプレッション君との付き合い方について基礎からお話できればと思います。

そもそもエクスプレッションとは、簡易的なプログラミングでパラメータを制御しよう、というものです。
言語はJavaScriptをベースとしています。
例えば一定速度で変動するパラメータなんかも、時間経過で数値が上昇していく「time」と組み合わせてあげれば簡単です。

なるほど!
つまり顔文字が拡大していく動きを組みたい場合はこんな感じで・・・・・・


なんでや(´・ω・`)
比率を変えないまま拡大したかったのに顔が横に伸びてしまいました。
どうしてこのような惨劇が起きてしまうかといいますと、スケールのパラメータが2次元配列だからです。

ニジゲン、ハイレツ・・・・・・?

要するにスケールというパラメータは「スケールの幅」と「スケールの高さ」という2つの値で構成されているということです。

プログラム的に書くとこんな感じ・・・・・・

スケール = [スケールの幅, スケールの高さ];

配列はこのように大括弧[]の中にふたつの値を並べることで記述することができます。区切りはコンマ「,」で行います。

ちなみに配列を構成する値を「要素」なんて呼んだりします。

エクスプレッションエラーで「〇次元である必要があります」なんて警告された場合も、配列の要素の数が不足していることが原因だったり。
「random」などは1次元な値を返してくるので、この辺りの注意が必要です。

なお、文末にあるセミコロン「;」は付け忘れるとエラーの元となるので必ず付けるようにしましょう。

閑話休題。
配列であるスケールのパラメータに1次元の値を足してしまうと、エクスプレッション君は困惑しながら「スケールの幅」の方に加算してしまうわけですね。

配列は[番号]を後ろに付けることで指定の要素を取り出すことができます。
上の例で書いたスケールの幅を取り出したい場合はscale[0]みたいな感じ。この番号は0番から始まるので要注意です。

ではこれを応用して、各要素ごとに「time*200」を加算してあげれば良さそうです。

[transform.scale[0] + time*200, transform.scale[1] + time*200];

うーん。確かにこれでも問題はありませんが、各要素ごとに記述しなければならないのがなんとも面倒ですね。
今は短く済んでいますが、これがさらにややこしい計算になると大変です。
そもそもこの記述方法では、「time*200」の部分を調整したいとなった場合に要素の数だけ手間がかかってしまいます。

ここで活用するべきなのが「変数」というシステムです。

変数というと数学の方程式のxやyを思い出す人もいるかもしれませんが、つまりは任意の値を格納しておく箱のような存在です。
例えば「scaleUp」という変数に「time*200」を格納するとしましょう。
変数の箱を用意することを「宣言」などと呼びますが、宣言は下記のような形式で行います。

let scaleUp = time*200;

文頭にある「let」は変数を宣言する合図のようなものです。
付けなくても一応は動作してくれるのですが、エラーに繋がりかねないので付けるようにしましょう。
「let」の他にも「var」や「const」が存在しますが、軽くエクスプレッションを組む分にはひとまず「let」を使用しておくのが無難かと思います。

「let」で宣言した変数名は、もう一度宣言することができません。
つまり、既に値の入っている箱に全く別の値を上書きしてしまうというミスがなくなるわけです。
「Identifier 〇〇(変数名) has already been declared」みたいなエラーが発生した場合は、誤って上のミスをしている可能性が高いので要チェックです。

スクリプトを組む場合はこの仕様が仇になってしまうという話はまた別の機会にでも・・・・・・

さて、無事に変数の宣言ができましたのでエクスプレッション全体は以下のように修正できます。

let scaleUp = time*200;
[transform.scale[0] + scaleUp, transform.scale[1] + scaleUp];

このように記述しておけば、変数scaleUpの内容を調整するだけでエクスプレッション全体に変更が反映されます。

しかしながら、やはり配列の各要素ごとに加算の式を書かなければならないのは少々面倒に感じます。
そこで以下のルールを応用してエクスプレッションを書き直してみましょう。

1. パラメータの元の値は「value」と表記できる。
2. 配列同士の足し算は同じ番号の要素で加算できる。
3. 配列に1次元の値をかけることですべての要素に対して乗算できる。

確かな満足(*´ω`*)

せっかく紹介した変数宣言ですが、今回のように簡単な処理の場合は省略するのもいいでしょう。私は省略します。
この形式であれば、[1, 1]の部分を調整することで各次元の上昇率を異なる倍率にすることもできます。
複雑すぎる処理には対応できないケースもでてくるので、そういった場合は諦めていただくしかありません。

ともあれ、これで少しエクスプレッション君と和解することができました。
さらに仲良くなるためには、プロパティとメソッド、関数について理解を深める必要があるでしょう。

メソッドや関数はさておき、プロパティの概要はみなさんも既に利用されているはずです。
例えばスケールのパラメータを表現する際に用いた「transform.scale」という表現。「scale」が「transform」のプロパティに該当します。
すなわち、トランスフォームという枠組みの中にスケールという属性が含まれているという意味です。

実際にAfterEffects内でレイヤーのプロパティを覗いてみるとわかりやすいですが・・・・・・

確かにトランスフォームの下にスケールが存在していることがわかります。
実は「transform.scale」も省略された表現なので、ある程度遡って以下のように書くこともできます。

comp(“ブログのイメージ画像を作るためだけに生み出されたコンポ”) .layer(“顔文字の獣”).transform.scale;

【「ブログのイメージ画像を(以下略」というコンポにある「顔文字の獣」という名前のレイヤーのトランスフォーム:スケール】という意味です。
これを理解しておけば、他レイヤーや他コンポに存在するパラメータを容易く引用できるかと思います。

ちなみに「transform.scale」の後ろには「value」というプロパティが省略されています。
基本はそのままの値を参照するだろうということで記載せずとも動作するようになっていますが、内部的な意味合いとしてはそのように解釈されています。
つまり、この部分に「value」以外のプロパティを記載すれば、「scale」からまた別のパラメータを受け取ることができます。

例えばテキストレイヤーでプロパティーの名前を参照したいとなった場合は、「transform.scale.name」なんて記述すればいいわけです。
まあ、そうしたところで出力されるのは「スケール」という4文字の文字列だけなのですが・・・・・・

実用的なのはやはり「valueAtTime()」でしょうか。
「valueAtTime()」は丸括弧()内に任意の時間(秒)を代入することで、コンポ内の指定の時間の値を取り出すことができます。

transform.scale.valueAtTime(1);

上記のように記述すれば、1秒時点のスケールの値を取得することができるというわけです。「time」と組み合わせれば時間差でパラメータを取得することも可能になるでしょう。

このように任意の入力に対して決まった処理を行うものを関数と呼びます。
「wiggle()」や「random()」も関数です。後ろに丸括弧()が付くものはとりあえず関数と考えて相違ないでしょう。

中でも「valueAtTime()」のように特定のプロパティの下に設定された関数をメソッドと呼びます。

さて、つらつらと呼び方を述べてはいますが重要なのは名称ではありません。
最も留意すべき点は、関数やメソッドには引数が必要ということです。
引数というのは関数に入力する値のこと、丸括弧()内に記載するパラメータのことです。

引数を必要数記述してあげないと関数は動いてくれません。
そして何より、引数の順番を守らなければいけません。

ラーメン屋さんのコールも順番があると聞きます。
ヤサイニンニクアブラカラメやら何やら。
少なくとも店側でオーダーを共有する際は特定の順番になっているはずです。
あの順番を滅茶苦茶にしてしまうと、聞き返す回数も増えてスムーズに注文が回らなくなることでしょう。

・・・・・・そういうことです。

ラーメン屋さんは温情で聞き返してくれますが、エクスプレッション君は淡々とエラーを吐くだけです。
温情は期待せず、指定の引数を指定の順番で記述するようにしましょう。

とはいえ、「そもそもどのような引数が必要なのか」「どんな順番で引数を書けばいいのか」という疑問が絶えないと思います。
使ったことがない関数であれば尚のこと。
wiggle関数の周期と振幅の順番を間違えてしまうのは誰もが通る道でしょう。

ラーメン屋さんみたいにトッピングのメニュー表でもあれば、まだわかりやすいのですが・・・・・・

ありますね( ゚Д゚)

エクスプレッションを開いた際のピックウィップ(@みたいなぐるぐるマーク)の右隣にエクスプレッション言語メニューという項目が!
なんということでしょう。すべてのプロパティが載っているのはもちろんのこと、関数やメソッドにはご丁寧に引数まで記載されているではありませんか。

・・・・・・関数の処理の解説まであればさらに良かったんですがね(=_=)

いやしかし、これで引数と引数の順番については問題ないかと思います。
※一部「t」という引数だけ意味がわかりにくいと思いますが、これは時間を指しています。

ところで、上のスクリーンショットを見て「あれれ~? おかしいぞ~?」と思わず心の中で名探偵になってしまった方もいるはずです。
普段周期や振幅しか入力していないwiggle関数ですが、その他に引数を3つほど持っているではありませんか。

ですがよくよく見てみてください。「引数=値」の形式で記載されているかと思います。
これらはデフォルト引数といいます。
デフォルト引数には初期値というものが存在し、特別言及がない場合はその値で処理を行います。

ラーメン屋さんのコールもすべてのトッピングに対して言及しなければならないというわけではないでしょう。
スキップしたトッピングはデフォルトのオーダーとして扱われるはずです。

・・・・・・そういうことです。
そろそろラーメン屋さんで例えるのはやめましょうか。お腹が空きます。

デフォルト引数を変更すれば、今まで以上に応用的な処理が可能になります。
wiggle関数に関して言えば、振動をループさせるなんてこともできます。
上級者向けのエクスプレッションに挑戦したい! という方は是非目を通していただければと思います。

ともあれ、プロパティとメソッド、関数についてある程度扱えるようになってきたのではないでしょうか。
これでまた少しエクスプレッション君と和解することができましたね。

正直このまま彼を懐柔できるところまで解説したい気持ちが山々ですが、あまり長々と書き連ねると本当に切りがなくなってしまうので今回はこの辺りで。

エクスプレッション君との付き合い方はトライ&エラーです。
発生したエラーに対して原因を模索し、処理の理解を深めていくのが和解に向けての着実な道となります。
今日日、情報はインターネット上に溢れかえっています。エラー文を検索エンジンに入力するだけでも、問題の解決には至れるでしょう。

それでも私のこの記事が、少しでもその助力になればと切に願っております。

では、またの機会に。

 

 

 

 

──────にしても、またの機会って果たしてあるんですかね?

思えばトリサンブログで続き物ってないような・・・・・・いえ、会社周辺グルメがありましたね。

いやいや、きっと書きますよ!
ほら、タイトルに(1)って付けちゃいましたし(;・∀・)
気付いたら(完)に修正されてるとか、この部分の記述全部に打ち消し線が付いちゃってるとか、そんなことないですよ? たぶん。

兎にも角にも予定が未定ではございますが、次の機会があれば是非またお会いしましょう。
少なくとも今冬は越えることになると思うので、寒さにはお気をつけて。
体が震えたらwiggle関数だなんてくだらないことを言ってないで大人しく温かい格好をしてください。

ではではみなさん、ごきげんよう!

トリサンをもっと知る