テラシュールブログ

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

【Unity】アニメーション中、指定の位置に到達するように位置を補正する

f:id:tsubaki_t1:20170130223038g:plain

ジャンプやダッシュジャンプを用いて障害物を登るというケースはよく有ります。この高さにアニメーションが一致すれば問題は無いのですが、任意の段差や距離をジャンプしたいといったケースは多々あります。

 

そういったケースの場合、幾つか解決の手法はありますが、今回はAnimator.MatchTargetを使用した解決法をメモします。

Animator.MatchTarget

Animator.MatchTargetは、アニメーションの指定タイミングでゲームオブジェクトの位置及び回転が到達するように調整するAPIです。

例えば下のように、ジャンプ開始モーションから補正を開始して着地時に指定位置に到達するような、微妙な位置を調整したり出来ます。

f:id:tsubaki_t1:20170130224713g:plain

到達して欲しい位置は、単純なRoot位置だけではなくBodyやLeftHand、RightHand、LeftFoot、RightFootといった調整が出来ます。

例えば上のGifアニメでは、左足が着地する位置に合わせて位置を調整しています。

実際に使ってみる

StateMachineBehaviourの用意

実際に使ってみます。

まず、普通にジャンプするアニメーションを用意します。そのままだとジャンプ力が足りず、変な所に着地してしまいます。

f:id:tsubaki_t1:20170131002757g:plain

このアニメーションに補正をかける訳ですが、実行時にステートマシンを調べるのも面倒なので、StateMachineBehaviourを使います。Mecanimでステートを選択中にAdd Behaviourで挙動を追加。

f:id:tsubaki_t1:20170130230223j:plain

追加するコードはこんな感じです。

gist.github.com

座標とウェイトの調整

コンポーネントは下のようになります。

まずTarget Body Partは「MatchPositionが到達して欲しいパーツ」です。先程も書いた通り「ルート、体、右手、右足、左手、左足」が指定出来ます。

逆にMatchPositionは、指定パーツが到達する位置(絶対値)で、Match Rotationが回転です。

この動きを、Weightsで制御します。Position Wieghtは、X/Y/Z方向にそれぞれ対応したウェイトです。例えばYを0に設定しておくと、MatchPositionでY軸にズレていてもY方向に動きません。

f:id:tsubaki_t1:20170130232653j:plain

 

今回は単なる移動なので、とりあえずMatch PositionとPosition Weightを調整します。
Target Body PartをLeft footに変更し、Match Positionを想定の位置に調整。

f:id:tsubaki_t1:20170130233027j:plain

アニメーションのタイミング調整

このStateMachineBehaviourのStartとEndが重要なポイントです。
MatchTargetは、Startから開始してEndのタイミングで対象の位置に到達します。そのため、キャラクターが動き始めたタイミングをStart、停止するタイミングをEndに指定します。

見るべきは、時間ではなくパーセントの方です。例えば下のアニメーションの場合、だいたい50.6%~76%くらいの位置で移動していますので、startは0.506、endは0.76と設定しておきます。この辺りは要微調整です

f:id:tsubaki_t1:20170130233452g:plain

f:id:tsubaki_t1:20170130234034j:plain

これで、タイミングや位置の調整が上手くいっているならば、着地のタイミングで対象位置に到達するような感じでアニメーションしてくれます。

f:id:tsubaki_t1:20170130234545g:plain

注意点

ApplyRootMotoinで動いている

MatchTargetですが、ApplyRootMotoinで動作しています。つまり、ApplyRootMotoinにチェックが入っていないと動作しません

が、逆を言えばApply Root Motoinにチェックが入っていればRootMotionの無いアニメーションでも動作します。

例えばユニティちゃんのアニメーションにはRootMotoinが入っていませんが、着地のタイミングに合わせて目標地点に到達するように調整出来ます。

f:id:tsubaki_t1:20170130235601g:plain

もしApplyRootMotoinを付けたくない場合は、下の記事が参考になりそうです。

gametukurikata.com

移動速度は距離を時間で割った速度で、等速

MatchTargetですが、基本的に移動速度は一定速度(距離を時間で割った速度)です。そのため、距離があまりにも想定アニメーションと比較して離れすぎている場合、非常に気持ちの悪い感じの動きになります。

また、基本的に目標地点へ一直線で動くので、カーブを描いて到達して欲しいようなケースでは有効ではないです。

なので、補正程度に使用するのが良さそうです。

MatchTarget補正中にステートの補完が走ると変な位置に到達する

MatchTargetで移動中、アニメーションのステートがブレンドを開始すると、妙な位置に到達する事があります。

f:id:tsubaki_t1:20170131000649j:plain

機能するMatchTargetは一つのみ

機能するMatchTargetは一つのみです。重複する場合、上に配置したStateMachieneBehaviourが優先されます。また、同様にサブステートがある場合は親に設定したStateMachieneBehaviourが優先されます。

なお、下のStartが上より早い場合、無視されるっぽいです。

f:id:tsubaki_t1:20170131002217j:plain

画面外に跳ねて、地面に着地する的な。

f:id:tsubaki_t1:20170131002326g:plain

関連

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

Galaxy S7と接続中のBluetoothヘッドホンがブチブチ切れる問題

先日BoseBluetooth ノイズキャンセリングヘッドホン QC 30を購入して楽しんでいたのですが、最近Bluetoothの音がブチブチ切れ音が遅延する問題に悩まされてました。

てっきりQC30の問題かと思いましたが、プロジェクターやiPadでは問題なく再生出来るのでGalasy s7 edgeの問題と仮定、ググったところ見事に同様の問題がヒット。

smartphone-watch.net

が、しかし

特定のBluetooth機器とだけでなく、複数のBluetooth機器で同じ症状が出るということで、こちらは対処法も見つかっていません。

おおぅ…マジか

解決

他のサイトでBluetoothのON/OFFや端末の再起動を試すも効果がなし。一瞬、専用のiPod Touchでも買おうかとよぎりましたが、もう少し調べてみることに。

すると、どうやらBluetoothのサービスを強制終了すれば治る可能性があるとの記述が…

How To Fix Galaxy S7 Bluetooth Problems | RecomHub

 

実際に試した所、コレが当たりでした。

やり方

  1. 設定を開く
  2. アプリーケーション管理を開く
  3. 右上のその他よりシステムアプリを表示を選択
  4. 一覧よりBluetooth共有を選択
  5. 強制終了を選択して、ついでにキャッシュを削除
  6. これでBluetoothが切断されるので、
    BluetoothをON/OFFしてBluetoothを再起動

再接続時以降はヘッドホンがブチブチ切れる事は無くなりました。

 

上手く行くかはわかりませんが、もし同様の問題があるなら試してみるのも良いかもしれません。

【Unity】知らないと面倒くさい事になるかもしれないAnimatorの「Write Defaults」の動作について

 今回はWrite Defaultsについて。

この挙動は少し分かりにくいので、少し補足します。

Write Defaultsという項目

f:id:tsubaki_t1:20170116000110j:plain

AnimatorのWrite Defaultsの項目のマニュアルを見ると、下のような物のようです。

Write Defaults : AnimatorStates を書くかどうかにかかわらず、その Motion によってアニメーション化されてないプロパティーによってデフォルト値に戻します。

 さて、「Motionによってアニメーション化されていないプロパティのデフォルト値」とは何でしょう。

キーが未定義なアニメーションは起動時のパラメータをデフォルト値として使う

プロパティのデフォルト値は、要するにAnimatorの起動時の位置やパラメータです。

AnimationClipが変更するオブジェクトや座標のパラメータを事前に保持しておき、特にキーが設定されていない項目は、その値を基準にブレンドを行うみたいです。

例えば下のGifアニメでは、最終的な座標(左下)のみを持つアニメーションを用意し、キーを何も持たないアニメーションからブレンドさせています。
Animatorを起動すると、デフォルト値はAnimator起動時の位置になるので、UIを配置した位置から最終的な座標(左下)へブレンドする形でアニメーションしています。*1

http://cdn-ak.f.st-hatena.com/images/fotolife/t/tsubaki_t1/20150205/20150205101008.gif

f:id:tsubaki_t1:20170116002224j:plain

Write Defaultsという項目

ネタバラシをすると、Write Defaultsの項目は要するに「アニメーションキーが設定されていない項目はデフォルト値を使用する」という項目です。

例えば下のようなUIを用意し、それぞれ「Sample 1のUIみ動かすアニメーション」「Sample 2のUIのみ動かすアニメーション」「Sample 3のUIのみ動かすアニメーション」を用意します。

f:id:tsubaki_t1:20170116003958j:plain

f:id:tsubaki_t1:20170116004112j:plain

このUIを動かすアニメーションを順番に再生すると、特にキーを設定しなくてもUIが仕舞われる感じのアニメーションが再生されます。

これはキーを設定していない項目はデフォルト値を元にブレンドしている為です。

f:id:tsubaki_t1:20170116004548j:plain

f:id:tsubaki_t1:20170116004403g:plain

逆にWrite Defaultのチェックを外していた場合、該当ステートではデフォルト値による上書きが無くなります。上のアニメーションの場合、UIを仕舞う挙動が無くなり、最後にアニメーションした位置がそのまま使用されます。

f:id:tsubaki_t1:20170116004809j:plain

f:id:tsubaki_t1:20170116004814g:plain

注意点

デフォルト値が保持されるケースの問題

なお保持するのはAnimationClipが変更する項目で、それ以外の項目は保持しないみたいです。保持するのは現在再生中のAnimationClipが変更するパラメータではなく、AnimationControllerが保持する全AnimationClipのいずれかが変更するパラメータです。つまり、AnimationControllerに含まれてるだけで効果を持ちます。

Write Defaultの有無に関わらず、AnimationClipで動かすパラメータはスクリプト上で動かす場合は注意が必要です。

tsubakit1.hateblo

デフォルト値がリセットされるケース

Write Defaultsを使用する上で一番の問題は、ここで使用するデフォルト値はAnimatorを含むGameObjectを非アクティブにするとリセットされ、アクティブ化した際のパラメータが利用されるという意味不明な仕様です。

例えばWrite Defaultsを使用中にGameObjectを一度非アクティブにすると、デフォルト値が変わってしまう為UIの切替が中途半端になります。

f:id:tsubaki_t1:20170116010217g:plain

tsubakit1.hateblo.jpので、Animatorを含むGameObjectの非アクティブ化は避け(親オブジェクトの非アクティブ化でも同様)、Animatorのみをdisableにしないと、ややこしい事が起こります。*2

f:id:tsubaki_t1:20170116012707j:plain

ちなみに、表情にBlendShapeを使いつつデフォルト値を前提に使用している場合、状態が混ざって面白い顔になる事があります。上のような感じ。
(他の表情が50とかの状態がデフォルト値となり、色々な表情が混ざる)

関連

tsubakit1.hateblo.jp

*1:この手法でUIを動かす場合、ブレンド率はリニア強制なので硬い動きしか表現出来ません。やるならブレンドツリーでやる事をお薦め。というかTweenお薦め

*2:正直、この仕様のせいでWrite Defaultsは死に機能になってる感がある

【Unity】AnimationControllerのAnyStateを使用してる際、現在のStateへ何度も移動しないようにする

今回は小さなTipsです。

f:id:tsubaki_t1:20170114000055g:plain

例えば上のように「どれか一つのUI状態を持つ」UIをAnimationControllerで管理し、かつAnyStateから呼び出すように作成した際、Triggerを叩くと何度もUI表示アニメーションが再生されてしまうといった事があります。

AnyStateの先へは何処からでも行ける

下Gifでは、UIの切替にAnyStateを使用してみましたが、ShowItem1が呼ばれる度にアイテムを表示するアニメーションが再生されてしまいます。

これはAnyStateの先に登録しているため、既にアニメーションが再生していた場合でもAnyStateへ戻り再度アニメーションを再生してしまう為です。

f:id:tsubaki_t1:20170113235304g:plain

Can Transition To Self

そんな時は、Transition(矢印)の設定にあるCan Transition To Selfのチェックを外します。これで、自身に遷移するアニメーションは無視されるようになります。

f:id:tsubaki_t1:20170114000259j:plain

f:id:tsubaki_t1:20170114000612g:plain

Triggerは使われないと消えない

この手法には一つ穴があります。それはTriggerはConditionの判定に使用された時に初めてチェックが外れるという仕様です。

例えばTriggerで次のステップへ移動する処理を作成しますが、Step2のみ時間移動とします。そうすると、Step2でTriggerが呼ばれてしまうと、Step3に移動した瞬間ステートを切り替えてしまいます。

f:id:tsubaki_t1:20170114001651g:plain

その為、Trigger実行中に他のステートに切り替えようとすると、一瞬別のステートに行きますがTriggerが再度判定されステートが戻ってくるといった事になります。

f:id:tsubaki_t1:20170114002124g:plain

ステート切替時にTriggerを消す

場当たり的な対処となりますが、ステート切替時にTriggerを消すと、この問題を回避出来ます。要するにStatemacihneBehaviourのOnStateExitのタイミングでTriggerを初期化すれば良いのです。

f:id:tsubaki_t1:20170114002505j:plain

gist.github.com

まぁ、ここまでしてAnyStateを使いたいかと言われると微妙な気もしなくもないですが…

関連

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp