アニメーションカーブでつけたキャラの動きに追従して左右の向きを自動で制御するエクスプレッションを考察とともにポストしておく。
残像はおまけ
なおキャラの左右反転はスケール値の変更ではなく前回のポストで使ったエッセンシャルグラフィックスの仕組みを使っている。
アニメーション設定

普通にパスでアニメーションが設定してある。左右に歩いてジャンプする。キャラの左右の向きは制御していない。前後の動きからエクスプレッションで自動設定する。
エクスプレッションの仕組み
下記コードは1を返すとキャラが左向き、0を返すと右向きになるもの(エッセンシャルグラフィックスをそう作ったので)スケールX調整で左右反転を行う場合最後のあたいを100か-100を返すようにすれば動く。
MAX_ITE = 30; // 前の値の取得を試みる最大回数
FRAME_STEP = 5.0; // 少し前とするフレーム数
//
DT = thisComp.frameDuration * FRAME_STEP;
p = transform.position;
CURRENT_VALUE = p.valueAtTime(time)[0];
diff = 0;
i = MAX_ITE;
dt = DT;
while(i--){
diff = p.valueAtTime(time-dt)[0] - CURRENT_VALUE;
if (diff != 0){
break
}
dt += DT;
}
diff < 0 ? 0: 1;
// エクスプレッションで決めているからか、自身の前の値は取れない模様
// thisProperty.valueAtTime(time-dt)
基本的に少し前のフレーム時点でのX座標値を見て現在と比べて大きいか小さいかで向きを決めている。値が同じ値の場合、前の向きを維持したいのだがエクスプレッションで設定した前の向きの値がどうもうまく取れないので、X座標に差が出るまで時間をさかのぼっている。あまりたくさん値を取得し続けるとパフォーマンス的な問題がでるかもしれないのでMAX_ITE値で試行回数の制限をつけている。少し前のフレームも純粋に前のフレームではなくFRAME_STEP値である程度幅を設けている。このほうが演出的にも自然になる事があり、先の探索パフォーマンス面でも有利になる。何か問題が出たら2つの値を調整すればいい。あとは強制で向きを上書きできる機構をつけてもいいかもしれない。
応用
今回は左右の向きの例だが同じ方法で360度の方向を取る事もできる。上から見下ろす支店などキャラの見た目制御をもっと詳細に行う場合に使える。
今回の例ではアニメーション的にあまり問題にならないが、慣性を無視して自由にキャラが動き回る場合、キャラの向きの切り替えが頻繁に起こりすぎる場合が出ることが想定され見た目的に良くない。この場合位置の取得に数フレーム分の平均を取るとか切り替えのフックになる範囲を狭めるとかいろいろ方法はあるがエクスプレッションだけだと大変になるのでとりあえず必要になるまでやらない。
グローバル変数
前のフレームの向きをグローバル変数($)やレイヤーのプロパティ値に無理やり入れる実装を試みていたが短い時間では動いてもどうも再生ごとに結果が異なったり動作が不安定になるのでやめた。再生ヘッドの位置で初期値が変わるかもしれないのと、そもそもtimeToFrames()値が正しい値を返さないような不可思議な現象に見舞われた。グローバル変数の可否や是非はまた別途調査したい。



