テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】チュートリアルやデモ作成に使えるかな? ゲームの動きをTimelineで再現する方法

f:id:tsubaki_t1:20180726230124g:plain

前回はRigidbodyの動きをTimelineに格納することで、物理演算の負荷軽減やタイミングの調整などを行いました。
今回はゲームの動きをAnimationClipとして格納しておき、Timelineで再生してみます。

 

 

ゲームの動きを再現したい

ゲームのチュートリアルやオープニングで、キャラクターの「本来の動き」を実際に表現したいといったケースがあるかもしれません。
例えばスーパーマリオワールドのオープニングを見ることで、ソレがどんなゲームなのかひと目で分かります
また、してもらいたい動きを見せる事でゲームの楽しみ方を理解してもらいやすくなる効果もありそうです。

www.youtube.com他にも攻略法が分からないステージでのゴーストランナーや操作チュートリアルなど、色々と使えそうです。

また、単純にTimelineで茶番劇を作る際、動きを作るのが面倒ならキャラクターを操作し、動きをAnimationClipとして保存するといった手もあるかもしれません。

 

やり方

やり方は単純、昨日の内容と同じような感じです。

tsubakit1.hateblo.jp

  1. 動かすキャラクター、及び動くオブジェクト郡を全てRecorderで指定します。
    動くかもしれないコンポーネントを全て指定します。
  2. Start RecordでプレイをAnimationClipに格納します。

f:id:tsubaki_t1:20180726233239j:plain

あとは前回同様、AnimationClipをTimelineに登録して、Recorderで指定したキャラクターをTimelineで動かします。

f:id:tsubaki_t1:20180726233409j:plain

 

再現できるのはInspectorに出ている項目のみ

さて、この機能で再現できる項目ですが「Inspectorに表示されている項目のみ」という制限があります。要するに、内部で持っているパラメーターなどは再現できないという事です。

このため、「ボタンを押したら弾が出る」的なアクションの場合、「ボタンを押した」という状態をTimeline側で再現できないと、弾を出すのが難しいです
(弾をオブジェクトプールしている場合、プーリングしてるオブジェクトをキャプチャすればOKという話もあります)

 

またUIの動きをキャプチャして再現する場合、「UIの動き」や「動きの結果の変化」といった項目はTimelineで再生出来ますが、フォーカスが当たった事による色のTweenといったプロパティ制御されていて表面に出てこない項目は反映されていません。

https://user-images.githubusercontent.com/1644563/43270903-2627e516-9131-11e8-8c35-7b194dc9fb6b.gif

 

3Dの場合はOptimized Game Objectをしてると使えないかもしれない

3Dの場合ですが、Optimized Game Objectを設定していた場合、キャプチャすべきボーン情報が取れず再現出来ないかもしれません。
Optimized Game Objectを解除すればキャプチャ出来ると思います

なおキーの数が結構凄いことになるかもしれないので、余りに長いモノは避けるか、キャプチャするフレームレートを下げるのが良いかもしれません。

 

ビルド後のゲームでキャプチャは出来ない

このアプローチはあくまでも「チュートリアルシャドウラン等の動きを保存する」ものですので、例えばレーシングゲーム最速シャドウランを再現するといった用途には使えません

そちらは「リプレイ」等のキーワードで探すのが良さそうです。

【Unity】Timelineで物理演算のような動きを使いたい

https://user-images.githubusercontent.com/1644563/43196798-1c92cc20-9044-11e8-8762-806e2d9415c5.gif

今回はTimelineで物理演算のような動きを再現するアプローチについてです。

 

 

物理表現的な動きをTimelineで使いたい

Timelineで簡単な動画を作成していると、物理表現的な表現を使用したくなるケースが多々存在します。
例えば玉が跳ねるであったり、扉が壊れるであったり、揺れモノであったり。

そういった表現を作る場合はアニメーションでカーブを作る必要があるのですが、コレが結構面倒くさいです。
本当にごく単純なアニメーションなら楽で良いのですが、少しでも複雑になると手間が大幅に増える他、簡単に不自然な動きになります。

f:id:tsubaki_t1:20180723204959j:plain

 

ではTimelineでの制御を止めてコンポーネント単位で動かそうとなる訳ですが、3つ問題があります。

1つ目は物理演算は毎回確実に同じ動きをする訳ではないという点です。端末のCPUやFPS遅延の有無によって多少結果が変動します。

またTimelineでのプレビューが出来ない点も問題です。もし物理演算的に動くナニカが演出の重要な項目を担っている場合、その動きと演出のタイミングを合わせるのは至難の業です。

パフォーマンス的な点もあります。位置情報を読み取るだけのアニメーションと比較して、物理演算は多くの計算を必要とします。その物理演算で動かす対象の量がとても多かった場合、その演出には非常に高い負荷が発生してしまいますし、事前に用意するコストも地味に大きいです。

 

物理演算の動きをAnimationClipに変換してしまおう

そこで思いつくのが、物理演算的な動きをAnimationClipに変換してしまおうというアイディアです。
AnimationClipに変換することで幾つか出来ることがあります。

  • 物理演算の「動き」のみを再現出来る
  • RigidbodyやColliderは不要
  • Timelineでプレビュー出来る
  • 量によるが普通に物理演算するより軽い

勿論、物理演算のようなインタラクティブな反応を返す事は出来ませんし、物理演算の結果「期待したような動きにする」事は難しいかもしれませんが、やって見る価値はありそうです。

f:id:tsubaki_t1:20180725123056j:plain

 

 GameObjectの動きをレコードする

AnimationClipに変換するため、GameObjectの動きをレコードします。
これはGameObjectRecorderというAPIがあるのですが、AssetStoreにあるRecorderでも対応する機能があるので、今回はそちらを使用します。

assetstore.unity.com

まず最初にTimelineで動かしたいオブジェクトを用意します。
このオブジェクトは親オブジェクトを用意しておくと、あとで色々と楽です。

なお、子オブジェクトは全てユニークな名前を指定する必要があります。オブジェクトのバインドは名前単位で行うので、同じ名前は使えません。
逆を言えば、オブジェクトを差し替えるときに名前さえ一致してれば何とかなるという話でもあります。

f:id:tsubaki_t1:20180725123520j:plain

 

次にTools > Recorder > AnimationClipsでウィンドウを開き、
GameObjectに先程用意した親オブジェクトを登録します。

複数のオブジェクトを登録したい場合はAdd Object To Recordでレコードしたいオブジェクトを増やします。

f:id:tsubaki_t1:20180725123614j:plain

f:id:tsubaki_t1:20180725123720j:plain

また、Transform以外もレコードしたい場合はRecordedTargetsで複数選択します。
なお、ココで指定できるのは「子オブジェクトも含めた全てのコンポーネント」です。

f:id:tsubaki_t1:20180725123945j:plain

あとはStart Recordingボタンを押せばレコードが開始され、Stop RecordingでAnimationClipがプロジェクトに生成されます。

f:id:tsubaki_t1:20180725124526j:plain

動きに問題が無さそうなら次のステップです。

 

Timelineに使用する

次にTimelineにバインドします。

手順は単純で、Recorderで保存したオブジェクトをTimelineに登録するだけです。

f:id:tsubaki_t1:20180725124816j:plain

 

Rigidbodyとか、その辺りを全て外す

Timelineで動くのが確認出来たら、最後にRigidbodyやColliderも外してしまってOKになります。
完全にTimelineで動くオブジェクトに物理演算の動作は不要なので外してしまいます。
もしくはIsKinematic。
これは動かすオブジェクトの量が多い場合、パフォーマンスを劇的に改善します。

 

注意

Humanoidに使用する場合

このアプローチ、少し考えればラグドールに使ってしまおうと考えるかもしれません。
物理演算を使用せず単純なアニメーションでキャラクターの転倒を再現するのは非常に低負荷であり、地形に沿ってキャラクターが倒れる必要がない場合は、それはたしかに有効そうな手に見えます。

下はラグドールをアニメーションに変換して再生したもの

f:id:tsubaki_t1:20180725130606g:plain

例えば120体のラグドールを全てAnimationClipでキャプチャして直した場合、ラグドール(右)が5~10msかかったのに対し、アニメーション(左)の場合は概ね0.5ms以下に収まっています。

f:id:tsubaki_t1:20180725130035j:plain

ただ注意すべき点として、このアプローチで取得できるキャラクターのアニメーションはGenericタイプであるという点があります。そのためキャラクターのリグがHumanoidの場合は互換性がありません。

また常に同じ動きをしてしまう関係上、死屍累々感はありません。
まぁ、ここまで規則正しく並べなければそうでもないとは思いますが…

f:id:tsubaki_t1:20180725130425j:plain

 

キーフレームの数が結構凄いことになる

もう一つの問題は、キーフレームの数が結構エグい事になる点です。
Unityのリダクション機能も使えないですし、カーブで補完してくれる感じではないので、ちょっと注意が必要かもしれません。
初期設定では60FPSでレコードするので、30FPS辺りにすると結構良い感じに減りそうです。

 

感想

作るのが面倒だった(上手くリアルな感じで作れなかった)物理演算的な動きを、手抜きして作る方法についてでした。

 

関連

 Timelineのプレビューのみで物理演算を再生するアプローチです。
求める結果を得るために試行錯誤する場合に使えます。

tsubakit1.hateblo.jp

画面を録画出来るRecorderです。かなり便利

tsubakit1.hateblo.jp

【Unity】カメラを常に揺らしたり、だんだんと揺れを強化したりする演出

以前紹介したカメラを振動させるアプローチの少し異なるバージョンです。

tsubakit1.hateblo.jp

 

瞬間的ではない振動を表したい

以前紹介したImpulseですが、その名の通り瞬間的な力による振動を表現しています。
大抵のゲームでは振動は「何らかのトリガーによって引き起こされる」物ですので殆ど問題無いと思いますが、演出的な要因で振動が必要という事もあります。

 

例えばガチャの演出で、なにかが起こる前触れとしての振動や、単純にストーリー的に地震等の演出をしたい場合です。
前者は「振動がだんだん強くなる」後者は「振動が常に一定発生する」など、どちらもImpulseでは若干面倒な表現になります。

f:id:tsubaki_t1:20180722155243g:plain

また長時間続く振動の場合は、こちらの方が何かと都合が良いケースもあります。例えば下の動画ではImpulseではなく今回の手法を採用しています。Impulse連続するの面倒だったので

 

連続した揺れはCinemachine Noiseを使う

揺れが連続している場合、CinemachineのNoiseを使用します。これで、Cinemachineが有効な間は連続して一定の強度で揺れます

f:id:tsubaki_t1:20180722161753g:plain

  1. Cinemachine > Create Virtual Cameraで、Virtual Cameraを作成
  2. Basic Multi Channel Perlimを選択
  3. Noise Profileを6D Shakeに指定
  4. 揺れ幅や切り返し回数を強化

f:id:tsubaki_t1:20180722162130g:plainこれでカメラが振動するようになります。

 

振動の状態を切り替える(Timeline)

まずTimelineで振動状態と非振動状態を切り替えます。切り替え方は単純で、TimelineでVirtual Camera同士をブレンドするだけです。
その時、座標だけでなく振動のパラメータもブレンドしていくので、少しづつ振動が強くなっていくといった表現が実現出来ます。

f:id:tsubaki_t1:20180722163720g:plain

この時、次の切り替え先のカメラが座標は同じでズームしているような場合、上のような「ズームしつつカメラの振動が強化される」といった、良く言えばなんかワクワクする演出が実現できます。

f:id:tsubaki_t1:20180722164037j:plain

 

振動の状態を切り替える(Timeline以外)

Timelineを使用した場合、トラックでタイミングを調整できるので非常に簡単に振動のタイミングが制御出来るのですが、Timelineを使用しない場合…例えば普通のゲームの場合はどうでしょう。

この場合、Cinemachine MixingCameraを使用するのが良さそうです。

f:id:tsubaki_t1:20180722164532g:plain

Mixing Cameraは子となる複数のVirtual Cameraを重みでブレンドする機能で、Cinemachineでよくある「カメラ同士の切り替え」よりもタイミング制御がやりやすくなっています

要するに

  • 複数のカメラでプレイヤーを追跡する
  • 追跡するカメラ毎に振動あり・無しが異なる
  • 重みで振動あり・振動なしをブレンドする

という感じです。

ただしTimelineを代表とする「演出」ではなく任意の操作が割り込む「ゲームプレイ」の場合、常に振動するカメラは非常に邪魔になるかもしれません。普通にImpluse使ったほうが良いように思います。

【Unity】衝撃があった時にカメラを揺らす / 振動させる

f:id:tsubaki_t1:20180718012440g:plain

今回は、何らかの衝撃があったときにカメラを振動させる方法についてです。

 

 

カメラの振動

何か衝撃があったとき、カメラを揺らすのはよくある手法です。
ダメージを受けた事を強調したり、クリティカルなダメージを与えたり、巨大な何かが動いた時の迫力を足したりと、様々なケースで使用されます。

f:id:tsubaki_t1:20180718015750g:plain

今回はその「カメラの振動」をやってみます。

 

CinemachineのImpulseを使う

今回はCinemachineのImpulse Listenerを使用します。
流れとしては、任意のImpulse Sourceが振動を発信し、Impulse Listenerが受信すればカメラが揺れるという感じです。
当然Cinemachineの利用が前提となります。

f:id:tsubaki_t1:20180718015950j:plain

まず受信側の設定です。

Virtual CameraのAdd ExtensionsからCinemachineImpulse Listenerを選択します。
これで上のようなコンポーネントが追加されます。
項目がない場合はCinemachineのバージョンが古いかもしれません。この機能は2.2からです。

f:id:tsubaki_t1:20180718020446j:plain

後は「衝撃」を発行するだけですが、幾つかアプローチがあります。

衝撃を発行する(コライダー編)

まずはColliderから衝撃を発行するCinemachine Collision Impulse Source を見てみます。
この設定では、コライダーが「カメラの近く」で「勢いよくぶつかったら」カメラが振動します。距離による減衰や、質量・加速度の有無等でカメラの衝撃が強弱します。

f:id:tsubaki_t1:20180718021417g:plain

まずRigidbodyで動くようなオブジェクトに、Cinemachine Collision Impulse Sourceコンポーネントをセットします。
次にSingle Shapeを6D Shakeにセットします。

最後にHow To Generate The Impulseの項目で、全てにチェックを入れます。(振動が向きの影響を受けるか・質量の影響を受けるか・速度の影響を受けるか)

f:id:tsubaki_t1:20180718021721j:plain

f:id:tsubaki_t1:20180718022005g:plain

f:id:tsubaki_t1:20180718105525j:plain

これでCinemachine Collision Impulse Sourceを持つRigidbodyが衝撃を受ければ、衝撃を通知してカメラが振動するようになります。

 

衝撃を発行する(コード)

コードで衝撃を発行する場合は単純です。

f:id:tsubaki_t1:20180718022429j:plain

まず適当なオブジェクト(多分マネージャー的な)にCinemachine Impulse Sourceを追加します。Cignal Shapeは6DShakeです。
あとはCinemachineImpulseSourceコンポーネントGenerateImpulseAtを呼べば良いです。これで画面が振動します。

f:id:tsubaki_t1:20180718022456p:plain

なおGenerateImpulseでも生成が可能ですがvelocityの値はVector3.down(0, -1, 0)と非常に小さいので、Gainを上げておく等をしないと揺れてないと勘違いします。

 

Timelineから振動を呼ぶ

Timelineからカメラを振動させてみます。
TimelineにはUnity 2018.2現在「イベント」が無いので、UnityTimelineEventを使用します。

tsubakit1.hateblo.jp

まず、振動を発したいオブジェクトにCinemachine Impulse Sourceを追加します。例えば巨大ロボの足とか、Timelineで動かすならTimelineの子オブジェクトを用意して動かすのが何かと楽で良いです。

あとはTimelineEventからCinemachine Inpulse Sourece.GenerateImpulseを呼び出します

f:id:tsubaki_t1:20180718023239j:plain

f:id:tsubaki_t1:20180718023322j:plain

なお、この時Invoke In Editor Modeにチェックを入れておけばゲームを再生せずとも振動の動きを確認することが出来ます。
Cinemachineの振動はカメラを動かしますが、座標の元となるVirtual Cameraは動いていないので特に問題はないです。

 

感想

カメラ揺らし、ココゾって所で揺らせば迫力満点です。
もちろん常に揺らすような事をすると飽きるので、そのあたりは使い所を考えると良さそうです。

あとVRでカメラ揺らしは絶対にしない。やったやつ体育館裏な*1

 

関連

tsubakit1.hateblo.jp

*1:ほんのチョビっとならOKという意見も