テラシュールブログ

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

【Unity】知らないとハマるかもしれない、2Dでスプライトアニメーションが即座に切り替わらない問題の対処方法

f:id:tsubaki_t1:20190109213049g:plain

今回はMecanim(Animator Controller)を使用している場合に即座にアニメーションが切り替わらない問題、その対策についてです。

例えば上の画像では、右はジャンプ開始時や着地直後に速やかにアニメーションが切り替わっているのに対して、左側はモーションの切替えが一瞬遅れているのが確認出来ます。この2D特有の現象の解決方法についてです。

2Dでアニメーションが即座に切り替わらない問題の解決法

アニメーションが即座に切り替わらない理由で真っ先に頭に上がるのはHas Exit Timeですが、今回は残念ながら違います。

先に結論を言ってしまえば、これはTransitoin Duration(s)(日本表記:遷移間隔)0以外を設定しているために発生します。 なので、Transitoin Duration(s)の値を0に設定する事で問題を回避することが出来ます。

f:id:tsubaki_t1:20190109214748j:plain
Transition Durationを0にする

原因

今回のケースの問題は、アニメーションが切り替わっているが、表示が切り替わっていない事が原因です。

通常アニメーションを切り替える場合、2つのアニメーションをブレンドする形で切り替えを行います。これを行わないと即座にポーズが差し替わってしまい、特に等身が高い場合は大きな違和感になります。このアニメーションのブレンド期間がTransition Duration(s)です。

f:id:tsubaki_t1:20190109220712g:plain
ブレンド期間を持つ(左)とブレンド期間を持たない(右)

3Dの場合は結構有り難い機能ではありますが、2Dのスプライトアニメーションの場合はアニメーションのブレンドという物は存在しません。*1しかしてブレンド期間は用意されている訳で、結果としてブレンド期間がある場合、ブレンドが半分を超えるまで移行前のアニメーションが再生される事になります。

f:id:tsubaki_t1:20190109221340j:plain
スプライトアニメーションの場合、紫の分だけアニメーション再生開始が遅延される

このブレンド期間を0にしてやることで、アニメーション切り替え後に即座に次のアニメーションを再生させます。これで2D アニメーションが遅延することは無くなります。

f:id:tsubaki_t1:20190109221542j:plain
SettingsのTransition Durationを0にする

全てのTransition Durationを0にしたい

問題がわかった所で作業を行いたい所ですが、非常に面倒なことにTransition Durationは複数選択で一気に変更することが出来ません。また、初期設定では(たとえ2D設定であっても)Transition Durationは0.25が初期値として設定されており、割と気づいたら紛れ込んでいるという事が多いです。さらにPresetを利用した初期値の設定も使用できないという、非常に面倒な項目でもあります。

なのでスクリプトで一気にTransition Durationを0にする方法を考えてみます。

以下のコードをEditorフォルダ以下に配置し、更新したいAnimatorController達を選択しつつAssets>UpdateTransitionTimeを実行します。これで全てのTransition Durationは0になると思います。上手くいかない場合は頑張って改造して下さい。

gist.github.com

関連

正直言ってしまえば、2Dの場合はAnimatorよりSimpleAnimatorのほうが管理が楽だし良いんじゃないかなと個人的には…

tsubakit1.hateblo.jp

スケルタルアニメーションの場合、遷移時間は表現の上で非常に大事です。ただ遷移時間が長いとモッサリするのも事実

tsubakit1.hateblo.jp

Transition Durationが0なのに即座に切り替わらない場合は、HasExitTimeが怪しいです。それでも上手くいかない場合は、AnimatorControllerの動作を勘違いしているかもしれません。

tsubakit1.hateblo.jp

コンポーネントやアセットの初期値をオーバーライドするPreset。今回の場合は「Transition先もオーバーライド」してしまうため使えませんが、他のアセット郡の初期値を考える場合には、非常に良い感じになります。

tsubakit1.hateblo.jp

今回作成したコードのような処理は、AssetGraphToolで自動化出来ていると色々と楽で良いです。

tsubakit1.hateblo.jp

*1:スケルタルアニメーションやテクスチャをブレンドする場合は除く

【Unity】2D AnimationのキャラクターにIKをつけてアニメーションで動かすまで

f:id:tsubaki_t1:20181228201422g:plain

今日は前回の続きで、スケルタルアニメーションをやっていきます。今回やるのは独自のキャラクターを動かす方法についてです。

タナカさん登場

前回のキャラクターを動かそうと思いましたが自分が動かしても良い感じにならない(ハイクォリティなテクスチャーにはハイクォリティなアニメーションが必要)ので、自分が3分くらいで適当につくったキャラクターを使います。タナカさん(仮)です。
Paperというアプリで作りました。こういう時にタブレットがあると便利ですね

f:id:tsubaki_t1:20181228201904j:plain
タナカ氏

これを、前回と同じようなアプローチで動かせるようにします。

ボーンをつけて、ジオメトリを生成、ウェイトを調整して完成です。一つ違う点があるとすれば、PSBのマルチスプライトワークフローではない場合は最初にスプライトを選択しないとボーンが作れません。

f:id:tsubaki_t1:20181228202136j:plain
設定後のタナカ氏

登録作業完了後はシーンに配置して、親オブジェクトにSprite Skinコンポーネントを追加、Create Boneボタンでボーンを自動生成します。これで一つのスプライトを変形させて色々なポーズを取らせる事が出来るようになります。

f:id:tsubaki_t1:20181228202827j:plain
配置してSprite Skinを追加した

タナカさんをIKで動かせるようにする

アニメーションはFK(ボーンを回転させる)でも作れますが、幾つかのケースではIK(特定座標に到達するようにボーンを調整する)の方が楽です。なのでキャラクターの「頭~腰」と「手」「足」でIKをセットアップします。

最初にIK Manager 2DをルートのGameObjectに設定します。

「+」ボタンで、使用するIKの数(頭、右足、左足、右手、左手)だけ要素を作成します。
作成する種類は、手足はLimb、頭はChain(CCD)で作成しました。

f:id:tsubaki_t1:20181228203528j:plain
IK Manager 2Dを設定

作成したSolverで、BoneのEffectorとTargetを関連付けます。Effectorはボーンの最終到達点、TargetはEffectorが目指す先です。

SolverはEffectorの位置がTargetに到達するように、ボーンの位置を調整します。ボーンの最終的な向き(例えば足や剣の向き)はEffectorのTransformの向きが影響します。

f:id:tsubaki_t1:20181228204703j:plain
EffectorとTarget

実際にIKをセットアップします。やってることは簡単で、Lamb Solver 2DCCDSolver2DのEffectorにボーン末端のGameObjectをセットしているだけです。手や足首といった物があればソレになります。下の例では腕までしかボーンが無いので、GameObjectを追加してソレを割り当てています。

CCDSolverの場合は、影響を受けるボーンの数(Chain Length)もココで指定します。

f:id:tsubaki_t1:20181228205610g:plain
IKのセットアップ

この作業を頭手足、全てに適応すればIKのセットアップは一通り完了です。

アニメーションにする

最後に作ったキャラクターをアニメーションにして使えるようにします。
この時、2つの選択肢があります。IK「で」アニメーションさせるか、編集に「のみ」IKを使うか…の話です。

IKでアニメーションする場合、基本的に腕や足といったパーツをIKで動かす事になります。これは多分2D Animationで想定された使い方で、作るのは楽だし、段差などの微調整が必要な部分を解決してくれます。ただし計算コストがかかります。また腕が変な方向にフリップしたりします。こちらで作る場合は、Targetの位置やEffectorの向きをアニメーションで調整すれば良いです。

もう一つはIKは編集に使うだけで、基本的にはAnimatorで操作するといった場合です。今回はIKは編集用と割り切った方法をやってみます。コチラの場合は、各ボーンに動きを登録し、最終的にはIK Manager2D系は全て外す事になります(もしくはウェイト0で運用)

最初にやることは、各SolverのTargetをルートオブジェクトの子から外す事です。AnimationClipを編集する際、動かすと自動的にクリップに登録されるのを避ける為、親子関係は外しておきます。もし最終的なキャラクタから完全にIKを省く場合(Animation Clipだけでボーンを動かす場合)は、Solverも外しても良いです。

f:id:tsubaki_t1:20181228211715j:plain
TargetをRootの外に持たせる

次にアニメーションクリップを編集していきます。編集する前にはAnimation Windowのロックボタンを押しておきます。でないとウィンドウのフォーカスがちょくちょく外れる事になります。

f:id:tsubaki_t1:20181228212224j:plain
Animation Windowはロックしておく

さて、基本的なポーズ作りはTargetを動かしてIKを調整するのが楽で良いです。ただしTargetでボーンを動かしてもAnimationClipに位置が保存されません。なので、下のようなフローでキャプチャーしていきます。

  1. Targetを動かして、IKベースでポーズを作る
  2. 動かしたボーンを選択して、InspectorのTransformで「Add Key」
  3. 1~2を繰り返してアニメーションを作成
  4. IK Manager 2DのWeightを0にして、実際のアニメーションの動きを確認

https://user-images.githubusercontent.com/1644563/50515683-7cdc9780-0ae9-11e9-9925-e47e84370128.gif

この形でスプライトのアニメーションを作れば、作成後はIK関連のコンポーネントIK Manager 2DSolver各種を破棄してもアニメーションしてくれます。

感想

ということで、タナカ氏を無事動かすことが出来ました。

良い感じに…となると練習とセンスを鍛える必要がありそうですが、ちょっと動かすというモチベーションなら、結構楽に出来るんじゃないかなという感じです。

関連

チュートリアル動画(2D Animation V1)

www.youtube.com

前回の記事

tsubakit1.hateblo.jp

【Unity】2D Animation(v2)でボーンベースで動くキャラクターを作る

f:id:tsubaki_t1:20181226215612j:plain

今回は Anima 2Dの後継、Unity 2D Animation(V2)でボーンベースで動くキャラクターを作成してみます。
なお今回は長くなりすぎたのでIk周りはやりません。セットアップまでです。

スケルタルベースのキャラクター表現

最近のゲームでよく見るスタイルの、スケルタル(骨格)ベースのキャラクター表現です。スプライトを差し替えるスプライトアニメーションと比較して、高解像度なスプライトで高フレームレートなアニメーションを実現出来るのが特徴です。

f:id:tsubaki_t1:20181226220521g:plain
ボーンベースを動かして対応するスプライトを動かす

この表現を行う為のツールとしてAnima2Dがありましたが、Unityに吸収されUnity 2D AnimationパッケージとUnity 2D IKパッケージという形で統合されました。

tsubakit1.hateblo.jp

で、今回 Unity 2D AnimationがVersion 2にアップデートされたので、使い方を見てみます。*1

パッケージの導入

パッケージはPackage Managerから導入出来ます。GUIで変更可能で、JSONを書き換える必要はありません。

今回の操作ではPSD Importerも使用します。これはスプライトのレイアウトを云々するのを楽にしてくれます。

f:id:tsubaki_t1:20181226221204j:plain
導入するパッケージ一覧

PSBをインポート

最初にPSDをPSBにしてインポートします。
PSDはパーツごとにレイヤーを統合しておきます。全て統合しても利用は可能ですが、可動部が非常に大きいパーツ(例えば腕や足、頭)は分割してあるのが良さそうです。

f:id:tsubaki_t1:20181226221523g:plain
PSDのレイヤー情報

レイヤーをまとめたら、PSDではなくビッグデータ(PSB)フォーマットで出力し、Unityプロジェクトへインポートします。PSD Importerが導入されていれば、これでスプライトは自動的にスライスされ、分割で配置されます。

f:id:tsubaki_t1:20181226222057j:plain
インポート時に自動的にレイヤー単位で分割配置される

なお今回のアプローチではCharacter Rigが必ず必要です。

f:id:tsubaki_t1:20181226221939j:plain
Character Rig

tsubakit1.hateblo.jp

場合によってはPivotの位置をキャラクターの足元になるように(目分量で)調整して、次はスプライトのセットアップです。

スキンのセットアップ

スプライトエディターからSkinning Editorを開きます。この項目がない場合は2D Animationパッケージが多分無いです。

f:id:tsubaki_t1:20181226222227j:plain
Skinning Editorを開く

ボーンのセットアップ

最初にボーンをセットアップします。

Create Boneでボーンを作っていきます。このボーンが、まさにキャラクターの骨になります。

ボーンはボーンの先端から少し離して配置することも出来ます。例えば肩や足、髪の毛など、腰の影響を受けるが接触はしていないというパーツは、一旦離して配置します。この場合、最後にクリックしたボーンの影響下になります。

f:id:tsubaki_t1:20181226223541g:plain
ボーンをセットアップ

なおボーンを設定すべきスプライトが影に隠れて見えにくい場合は、右上の項目からスプライトを個別に表示することも可能です。他にもダブルクリックでメッシュを表示したりもできます(上では自分はダブルクリックで腕を表示しています)

f:id:tsubaki_t1:20181226224844j:plain
スプライトを個別表示

ジオメトリのセットアップ

次にスプライトを変形させるために、メッシュを作成します。これは自動で作ることが出来ます。

Auto Geometoryを選択後、Generate For All Visibleでメッシュが自動的に生成されます。ついでにボーンに紐付いたウェイトも自動的に設定されます。 自動生成が気に入らなければ(変形するメッシュの密度が足りないようなら)手動で調整することも出来ますが、今回はしません。

f:id:tsubaki_t1:20181226224407j:plain
メッシュの自動生成

ウェイトのセットアップ

メッシュとウェイトを自動生成すると、予想外のボーンに対してウェイトがかかっていたりします。例えば腕のボーンが体にかかっていたり、その逆だったり。これを放置すると、ボーンを動かした時にメッシュが奇妙な変形を起こす事になります。

例えば下の図の場合、腰のボーンの影響を受けているため二の腕がたるんでしまっています。

f:id:tsubaki_t1:20181226225912g:plain
予想外のボーンの影響を受けて予想外のタルみを見せる二の腕

なのでメッシュが影響を受けるボーンを限定します。

ボーンの影響はBone Influenceでメッシュ毎に設定することが出来ます。これでメッシュが影響すべきボーンを限定してやれば、上のような問題は起こらなくなります。またブラシでボーンの影響の強度を調整したりもします。

f:id:tsubaki_t1:20181226225420j:plain
Bone Influenceでメッシュが影響するボーンを減らす

f:id:tsubaki_t1:20181226232425g:plain
ウェイトがちゃんとしてれば、変な影響を受けない

キャラクターを配置

セットアップが完了したら、シーンに配置します。

PSBでインポートしたファイルをそのままシーンに配置すれば、ボーンの設定されたキャラクターとして配置して、FKで各パーツを動かせます。

なおキャラクターが大きすぎたり、キャラクターの中心位置が微妙な場合、大きさはPixel Per Unit、中心位置はPivotで調整します。

f:id:tsubaki_t1:20181226231308g:plain
セットアップしたキャラクターをシーンに配置

感想

スプライトの配置や描画順がサクッと出来て、実際のレイアウトを確認しながらボーンを調整してジオメトリとウェイトが自動でできるのは楽で良いです。次はキャラクターを動かしたりアニメーションさせたりします。

なお「試したいけどPSBなんて持ってないよ!」という場合は、下のプロジェクトからサンプルを入手出来ます。

github.com

しかし何故PSBなんでしょう。PSDだったら多くのツールで編集が可能なのに

関連

tsubakit1.hateblo.jp

PSD Importerが使えない場合

blogs.unity3d.com

*1:まぁVersion 2でもPreviewな訳ですが

【Unity】3Dアクションの連続攻撃(コンボ)で学ぶAnimatorControllerのtips

今回はボタンをタイミング良く押すと連続攻撃になる動作を作成します。
格ゲーのようなコマンド入力ではなく、3Dアクションによくあるような非常に単純なもの です。

 

 

ボタン連打でコンボ攻撃

3Dゲームなどで「ボタンを連打したら連続攻撃」という機能をよく見ます。
今回はコンボ表現の単純な紹介をしようと思いましたが、コレが思ったより重要な要素の塊だったので、解説しながら内容を紹介していきます。

なお格ゲーが作りたいならPlayableAPIで再生するアニメーションを選択する部分を自分で拡張するがお勧めです。

f:id:tsubaki_t1:20181102003515g:plain

今回の動作を作るにあたり、使用したコードは「Animatorのトリガーを呼ぶ」くらいで、殆どスクリプトを記述せず実現出来ました。

 

1.  ボタンを押したら殴る

最初のステップでは、ボタンを押したら(Attackトリガーが有効になったら)殴るモーションに入らせます。

  1. [アイドル] と [パンチ] のモーションのトランジション(遷移)を設定
  2. [アイドル] → [パンチ]のコンディションにAttackトリガーを設定
  3. [パンチ] → [アイドル] のコンディションはHasExit(終了時間あり)を設定

これで実行時にAttackトリガーを押せば[パンチ]と[アイドル]の間を行ったり来たりします。

f:id:tsubaki_t1:20181101214104j:plain

ポイントは[アイドル]→[パンチ]のHasExit(終了時間あり)を外す事です。
アイドルや走行といった他のアニメーションに即時切り替わることが期待されているモーションは、HasExitを外さないとモッサリします

 

2.  ボタンを押したら次の攻撃への実現

単発ではなく、順番に攻撃アニメーションを行うように修正を行います。

上ではアニメーション終了時に即座に戻っていましたが、今回はトリガーが押されたら次のアニメーションへとなるようにAnimatorControllerを修正します。

f:id:tsubaki_t1:20181101212637g:plain

考え方は簡単で、攻撃モーションをトリガーで繋いでいくだけです。全ての遷移にはAttackのトリガーによる切り替えを設定しておきます。

f:id:tsubaki_t1:20181101213358j:plain

ここでのポイントはトリガーはトランジションを通ると即座にOFFになる事です。複数のステートの巡回を行いつつちゃんとアニメーション終了待ちさせるといった点では、トリガーは非常に有用です。
ただし「トランジションを通らなければOFFにならない(スクリプトでOFFにする必要がある)」為、使いすぎるとトリガーのリークが起こります。

 

3.  攻撃の入力待ち時間の調整

Attackトリガーの入力待ち受け時間とモーションの繋ぎを調整します。

f:id:tsubaki_t1:20181101220236j:plain

まず注目すべきはオレンジで囲った「終了時間」の部分です。この部分がAttackトリガーの入力を受け付ける時間です。初期値では0.5となっているので、これを出来る限り後ろの方(せめて大体の攻撃モーションが終了して収束する0.8割くらいの位置)に移動します。

f:id:tsubaki_t1:20181101221519g:plain

ここで重要な考えはトリガーの判定は終了待ちで指定したタイミングを「通過した瞬間」に行われるという点です。トリガーが通過すると次に判定するのは次の周の終了待ちのタイミングなので、終了待ちを早めに設定すると簡単にタイミングを逃します。

終了待ちを行わないという選択肢もありますが、その場合「攻撃モーションをキャンセルして次の攻撃モーションが始まる」可能性があります。

 

4.  モーションの繋ぎの調整

入力待ち時間の設定が終わったらモーションの切り替えにかかる時間を調整します。
ここでのポイントは遷移間隔を短くすることです。ここが長いとモーションのブレンド時間が伸びてモーションがボンヤリします。
遷移時間を短くすることで発生する急激な軸足の変化は、オフセットをズラして調整します。

f:id:tsubaki_t1:20181101222358g:plain

なお遷移間隔とオフセットでズレた位置が次のステートの開始点です。
つまり遷移時間が0.25(初期値)で次のステートの終了待ちが0.5(初期値)の場合、0.25~0.5までにトリガーを押さないとタイミングを逃します。

5.  ボタンが押されなかったらキャンセルする

タイミングよくボタンを押したら攻撃は出来ました。次はタイミングを逃してボタンを押さなかった場合にモーションをキャンセルしてアイドル状態に戻す挙動を作ります。

f:id:tsubaki_t1:20181101230043g:plain

やり方は[パンチ]や[フック]といったモーションからアイドルへ「終了時間あり」つきでトランジションを作ります。
この時、必ず終了時間を[パンチ]→[フック]への終了待ち時間より後に設定します。
これでモーション完了時にボタンが押されていなければ[アイドル]へ戻るようになります。

f:id:tsubaki_t1:20181101223854j:plain

なお、どうしても[パンチ]→[フック]の終了時間よりも[パンチ]→[アイドル]の終了時間が前に来る(必ず先に[パンチ]→[アイドル]の遷移が始まってしまう)という場合は、中断要因を使用して強引にフックモーションを実行するという力技もあります。
(これは理解できない挙動の要因になりえるので、余り使わない方が良いと思います)

f:id:tsubaki_t1:20181101225821j:plain

 

6.  ボタンで攻撃を分岐させる

コンボ中に押すボタンによって攻撃を切り替えます。

f:id:tsubaki_t1:20181101232745g:plain

ステートマシンの途中で分岐が発生しますが、この分岐はInt型のパラメーターをもたせる事で解決します。このInt型のパラメーター(AttackType)をボタンと一致させれば、ボタンで挙動が変わるコンボが的なのを実現出来ます。

f:id:tsubaki_t1:20181101232331j:plain

ボタンに応じたトリガーという手もありますが、トリガーのリーク(トリガーが開放されず押した状態が保持されてしまう状態的な)が発生するので、パラメーターで分岐させるほうが好みです。

今回はAttackTypeのパラメーターで分岐しましたが、実際には「移動中か?」や「HPの割合」等をコンディションに渡して再生するアニメーションを切り替えるのも良いかもしれません。

 

7.   ステートマシンを整理する

さて分岐を追加したことでステートマシンが割と大変な感じになってきました。最後にサブステートを使用してステートマシンを整理しておきます。

最初のポイントは、ステートマシンはサブステートに入るとEntryから始まり、Exitで出るとサブステートから遷移するという点です。

  1. サブステートマシン[アタック]を作成
  2. [アタック]と[アイドル]のトランジションを作成。[アイドル]→[アタック]のコンディションはAttack
  3. [アタック]へ攻撃系のモーションを全て移動
  4. 攻撃系モーションの遷移先をExitへ変更
    (終了時間は1に設定)

ダイジェストすると、下のような感じです。

https://user-images.githubusercontent.com/1644563/47859170-0c8b0000-de31-11e8-9fb6-ef052c2a174c.gif

f:id:tsubaki_t1:20181101234413j:plain

まだ攻撃処理が分岐する部分(ハイキックとアッパー)がゴチャゴチャしそうなので、少し過剰ですがもう少し整理しておきます。

分岐する攻撃をサブステート[アタック(分岐)]へ移動します。
[フック]→[アタック(分岐)]へのトランジションは「Attackトリガー」だけで良いです。判断はサブステートマシン側で行います。

f:id:tsubaki_t1:20181102000524j:plain

サブステート側では、Entryから[アッパー]と[キック]へのトランジションを設定します。その際、分岐はAttackTypeのみです。

あとはアニメーション終了時にExitに持っていけば、親サブステート[アタック]のExitへ到達し、最終的に[アイドル]へ戻ります。

f:id:tsubaki_t1:20181102000822j:plain

f:id:tsubaki_t1:20181102001207g:plain

関連

blogs.unity3d.com

www.slideshare.net

AnimatorControllerの整理系

tsubakit1.hateblo.jp終了待ちキャンセル

tsubakit1.hateblo.jp

攻撃モーションが「他の全ての攻撃モーションに遷移する」場合にステートがスパゲティ化するのを何とかするアプローチ

tsubakit1.hateblo.jp