今回から、Xで投稿している「すぐに使えるエクスプレッションTIPS」の解説をしていきたいと思います。
(いきなり#13から始まっていますが初回です)
Xで反響が大きかったものを中心に、順不同だったり、過去に遡ったり、間が空いたり色々すると思いますので、その辺は気にせずご覧ください。
・CS6/CC両対応のため、ECMAScript3相当のJavascript(ExtendScript)で記載しています。
・コンポジションサイズは、1920 * 1080 です。
では、解説を始めていきます!
1. 反射エクスプレッション
まずは、このポストの動画を再生してみてください。赤い球体が黄色い点線を境に、反射するような動作になっていますね?
今回は、この「反射」アニメーションが、どのような仕組みで動作しているのかについて、1つずつ説明していきたいと思います。
・変数pは、位置=positionの頭文字、変数rは、反射境界線=reflective borderの頭文字という想定で名前を付けてあります
エクスプレッション解説
これから説明するエクスプレッションは以下です。
var p = wiggle(0.5, 500);
var r = 960;
[(p[0] < r) ? p[0] : r - (p[0] - r), p[1]];
これを、位置プロパティにコピペするだけで、反射するような動作になります。
登場人物
まず最初は、登場人物から見ていきたいと思います。
右から、
- 反射前位置(p)・・・wiggleが適用された反射前の位置
- 反射境界線(r)・・・反射する境界線。この境界線より右に移動すると反射します
- 反射後位置・・・反射境界線で反射した後の位置
となります。この3人の登場人物がよくわからなくなってしまったら、この画像をもう一度見に戻ってきてください。
それでは、その仕組みを一行ずつ分解して見ていきましょう!
ますは1行目から。
1行目
var p = wiggle(0.5, 500);
最初に、変数pにwiggleの結果を代入しています。位置プロパティのwiggleの結果は、要素数2の配列(X位置とY位置)なので、pも要素数2の配列となります。
また、wiggleの具体的な値は、初期値のままであれば、[960, 540]を中心に、上下左右500pxの範囲の値で、2秒に1回変動します。
これが、1人目の登場人物「反射前位置(p)」になります。
次は2行目。
2行目
var r = 960;
変数r には、960 を入れました。
これが、2人目の登場人物「反射境界線(r)」になります。960 は1920の半分なので、画面の中央が反射境界線になりました。
最後は3行目。
3行目
[(p[0] < r) ? p[0] : r - (p[0] - r), p[1]];
まず、大前提として、エクスプレッションは、最後に書いた値がプロパティに反映されます。
今回は位置プロパティなので、要素数2の配列の形式で書き込むので、以下の形式になっています。
[/* X位置の値 */, /* Y位置の値 */];
それでは、更に分解して、X位置の値の部分からみていきましょう!
・「変数」は、数値や、文字や、配列など様々なデータを入れる入れ物のことです
・「配列」は、複数のデータが入る入れ物のことです。入っている値の数を「要素数」といいます。
・「配列」が入っている「変数p」から最初の値を取り出す場合は p[0]、2つ目の値を取り出す場合は p[1] と記載します。
位置プロパティのX値に設定する値
3行目
[(p[0] < r) ? p[0] : r - (p[0] - r), p[1]];
から、「X位置の値」だけを抜き出すと、以下のようになります。
(p[0] < r) ? p[0] : r - (p[0] - r)
これは、Javascriptの「条件式」を短縮した、「条件 (三項) 演算子」という構文です。
書き方は、「もしも、~だったら、~を実行。違ければ、~を実行」というように、条件と、実行内容をセットにして記述します。
(/*条件*/) ? /*条件が成立したら実行する内容*/ : /*条件が成立しなかったら実行する内容*/
ちなみに、「条件式」について詳しく知りたい方は、以下の記事にまとめてあるのでご覧ください。
「条件 (三項) 演算子」の部分を説明するために、元の「条件式」に書き換えると以下になります。
if(p[0] < r) {
p[0];
} else {
r - (p[0] - r);
}
元の「条件 (三項) 演算子」と見比べてみてください。よく見ると、書き方が変わっただけで、条件など、書いてあることが同じなのがわかりますか?
実際にどんなことをしているのか、まずはこの「条件式」に、コメントで説明を追加してみます。
if(p[0] < r) {
// もしも、p[0](反射前X位置)が、r(反射境界線)未満だったら = 反射境界線より左だったら
p[0]; // 反射前X位置をそのまま使用
} else {
// それ以外だったら = 反射境界線より右だったら
r - (p[0] - r); // 反射後位置を計算
}
上記コメントにも書いてありますが、改めて図にまとめてみました。
上記画像のように、反射前X位置(p[0])が、反射境界線(r)よりも左にあった場合は、反射前X位置をそのまま利用します。
また、反射境界線よりも右にあったら、反射後X位置を計算するという条件式になっています。
反射X位置の計算
では、ここからが本題です。「って、まだ本題じゃなかったの?!」と思われた方、すみません。
この先が、このエクスプレッションの本当の重要な部分なんです。あと少しです!
ここでも説明用の画像を用意したので、この画像を見ながら説明していきます。
それでは、最初に紹介した登場人物「反射前位置(p)」「反射境界線(r)」を使って、「反射後位置」を計算していきましょう!
まず、反射境界線をどれくらい超えているのかが知りたいので、青い部分を計算します。
この青い部分は、反射前X位置(p[0])から、反射境界線(r)を引くことで、計算できるので、以下のように書くことができます。
p[0] - r
次に反射境界線(r)からの跳ね返り量を知りたいので、オレンジの部分を計算します。
反射境界線(r)から、青い部分の距離だけ左に反射させたいので、反射境界線(r)から青い部分を引きます。
r - (p[0] - r)
これが、3人目の登場人物「反射後位置」のX値になります。
『r – (p[0] – r)』は、展開して 『r – p[0] + r』や、『r * 2 – p[0]』と書いても同じ結果になります
位置プロパティのY値に設定する値
最後に、3行目の「Y位置の値」の部分について説明します。
3行目
[(p[0] < r) ? p[0] : r - (p[0] - r), p[1]];
から、Y位置の値だけを抜き出すと
p[1]
となります。
Y位置は反射させる必要がないので、反射前Y位置(p[1])を、位置プロパティのY値にそのまま設定しています。
これが、3人目の登場人物「反射後位置」のY値になります。
これで三行目の説明はおしまいです。
[(p[0] < r) ? p[0] : r - (p[0] - r), p[1]];
上記三行目を最後にまとめると、
「基本は、XもYも反射前位置(p)を利用するけど、反射前X位置(p[0])が、反射境界線(r)の右にあった場合のみ、Xの反射位置を計算するよ」
という意味なのでした。
まとめ
ここまで書き終わって、ふと思いましたが、ここまで何人くらいの人が理解してくれたのかなーと、とても心配になっています。。
なんとなく理解できましたか?
ちなみに、変数pに代入する計算をwiggleの代わりに「time * 500」などに変更すると、単純に水平方向に反射するアニメーションになります。いろいろなアニメーションに変えてみると新たな発見があるかもしれないので、慣れてきたら色々お試しください!
感想や、わかりにくかった箇所などあれば、Xの返信や、DMなどいただけると嬉しいです。
きっと誰かの役にたっている(といいな)と信じて、次の解説記事も書いていきたいと思います!
Xのいいねやフォローもお待ちしてます!