テラシュールブログ

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

【Unity】UnityとAndroidアプリの64bit対応

Android 64bit対応が本格化してきたので、少しまとめてみます。

Android 64bit対応

Androidの64bit対応バイナリを使用していないネイティブアプリはGoogle Playでリリース出来なくなるみたいです。 それについてのロードマップがAndroid Developers Blogにて公開されました。

Android Developers Blog: Get your apps ready for the 64-bit requirement

このアナウンス自体は結構昔(2017年末くらい)のタイミングで既に行われており、改めてアナウンスが行われたという感じです。

f:id:tsubaki_t1:20190118000529j:plain
Get your apps ready for the 64-bit requirement より引用

2019年8月から64bit対応してない新規アプリの公開が出来なくなる。更新は可

2019年の8月より、新規アプリの公開及び更新が不可になります。

ただしUnityを使用しているアプリは特例として、更新のみ可能です。正確に言えば、5.6以前のUnityです。

Extension: Google Play will continue to accept 32-bit only updates to existing games that use Unity 5.6 or older until August 2021.

Android Developers Blog: Get your apps ready for the 64-bit requirementにて

ここで「Unity 5.6以前」としているのは、Unity 2017から64bit対応しているからと認識しているからと思われます。

また条件は「Unity5.6以前(Unity 5.6 or older)」なので、Unity 5.4とかでも更新は可能と思われます。

2021年8月から64bit対応してないアプリを排除。Unityも含む

2021年の8月から、いよいよGoogle Playは64bit対応していないアプリを排除します。これはUnityでも同様です。

そのタイミングまでにはAndroid 64bit対応は完了しておく必要があります

Android 64bit対応済のUnityバージョン

Android 64bit対応は、以下のバージョンから行われます。なので、基本的にバージョンが古い場合は上げる必要があります。

  • Unity 2018.1 Experimentalとしてサポート
  • Unity 2018.2 正式サポート
  • Unity 2017.4.16f1

またIL2CPPを使用する必要があったり、ネイティブプラグインを使用しているなら64bit向けにビルドする必要があります。 そのあたりの情報は下の記事が分かりやすいです。

qiita.com

なお、LTSによるサポート対応はLTSリリースから2年です。Unity 2017.4f1リリース日が2018年4月辺りなので、そこから2年…つまり2020年4月までという点は一応覚えておく必要がありそうです。

Unity の新しいリリースプラン:TECH ストリームと長期サポート(LTS)ストリームの導入 – Unity Blog

関連

今回のアナウンスについて

forest.watch.impress.co.jp

android-developers.googleblog.com

意外と知られてない印象がある、アップグレードガイド

docs.unity3d.com

【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】新しいInput Systemの使い方

あけましておめでとうございます。 今年もよろしくおねがいします。

f:id:tsubaki_t1:20190107211238g:plain

さて、今回は新しいInput SystemがPackage Managerで使用できるようになったので、実際に使い方を確認してみました。
なおPreview版なので、動作が変化するかもしれません(本記事は0.1.2のバージョンで作成されています)

新しいInput Systemの導入

まずは新しいInput Systemを導入してみます。新しいInput Systemは古いInput Systemとの共存も可能ですが、今回は共存しない方向でいきます。

必要な項目のリストは以下の通り

  • Script Runtime Version.NET 4.xに変更
  • Active Input HandringInput System (preview) に変更
  • Package ManagerInput Systemを導入

まずScript Runtime VersionActive Input Handring.NET 4.xInput System (Preview)に変更します。この2つの作業はそれぞれエディターの再起動を要求します。

f:id:tsubaki_t1:20190107212823j:plain
.NETのバージョンとInput Systemの切り替え

あとはPackage ManagerInput Systemをインポートします。もし一覧にない場合はPacakgeManager内のAdvanceボタンからShow Preview Packageを有効にします。

f:id:tsubaki_t1:20190107212420j:plain
Package ManagerでInput Systemを導入

これで準備完了、早速試してみます。

新しいInput Systemの利用(InputControl)

新しいInput Systemを使ってみます。

最初は比較的以前のInput Managerと似たようなアプローチでInputControlベースの機能です。下のコードはマウスの位置とスペースキーが押されているかどうかをログに表示します。
今回紹介するのは基本的なフレーム毎に情報を取得するスタンスで、動作はフレームレートに依存します。

gist.github.com

f:id:tsubaki_t1:20190107220219j:plain
実行結果

Mouse.currentで現在のマウスを取得、position.ReadValue()で現在のマウスの座標しています。またKeyboard.currentでキーボードを取得し、spaceKey.isPressedで押されているかどうかを取得します。isPressedの他にもwasPressedThisFrame(今のフレームで押したか)やwasReleasedThisFrame(今のフレームで離したか)といった情報も取得が可能です。

この例ではマウスとキーボードですが、同様の手順でJoystickAccelerometerGamepadGyroscopeJoystickPenTouchscreen等にアクセスするためのAPIが用意されています。
逆をいえば、GamePadとKeyBoardの両方で入力を受け付ける場合には両方から情報を取得する的な工夫が必要そうです。

また入力を取得するデバイスProjectSettings > Input(New)Supported Devicesから指定出来るみたいです。指定がなければ取れるモノは全て取得します。
ただし、自分がこれを変更するとエラーになるので、バグっている、もしくは何か条件がありそうです。

f:id:tsubaki_t1:20190109114541j:plain
使用するデバイス一覧の設定

新しいInput Systemの利用(InputAction)

次に新しいInput SystemのInputActionベースの入力取得についてです。こちらのアプローチは今までのInput Managerベースと異なり、イベントで動作します。これは入力を行う度にイベントが呼ばれるというスタンスで、事前にデリゲートに処理を登録しておく必要があります。

この処理で面白いのは1フレームに複数回の入力を受け取れるという点です。フレームに依存せず入力を受け取れる為、究極的に言えば処理落ちした場合でも入力がスキップしないという期待が持てます。

例えば下のGifアニメでは、低フレームレートの環境でマウスの位置を、Input Manager(現行)Input Systemの両方で取得して線を引いています。Input Managerはフレーム開始時のマウスのみを取得しているために非常に単純な図形しか描けないのに対して、Input Systemはフレームの中間の入力も取得出来るのでマウスの動かした通りの線が引けています

なお、非同期で入力を取得出来るかは、現状プラットフォームに依存します。これは未完成なのかもしれませんし、デバイス的な成約かもしれません。また、フレームに依存せず非同期にコールバックを受けている用に見えますが、実際にはバッファに入力を溜めておき、フレームの頭に一気に入力を処理するという流れみたいです(フレーム間の処理を利用するならば、バッファの中の時間を元に動作を再現するような実装が必要)

f:id:tsubaki_t1:20190108222131g:plain
Input ManagerとInput Systemの比較。Input Systemの入力はフレームが落ちても劣化していない

実際にInput Systemを使ってみます。

まずはInputActionフィールドを用意し、inputAction.performedに入力を受けた時の動作を記述します。下の例の場合、mouseInput(マウスを動かした時に動作する想定)にはマウスの座標を、fireInput(ボタンを押す想定)には押したら反応するように設定します。

なお入力は定義しただけでは動作しないので、inputAction.Enable()で有効化します。

gist.github.com

次にエディター側の操作で、ユーザーの操作と入力を関連付けます。これはInspector側で行います。+InputActionとバインドする操作を追加し、Bindingで登録する項目を追加、ダブルクリックでメニューを開き、実際にバインドする入力を選択します。

もしGetInputAxisのように'Aキー'と'Dキー'の2つをバインドしたい等の場合は、BindingではなくCompsoite>Axis等を選択します。

f:id:tsubaki_t1:20190108224221g:plain
InputActionと入力のバインド操作

これで実行すればマウスの位置とクリックの情報をログに出してくれますが、このままだとMouse DownとMouse Upの両方のイベントを受け取る事になります。なので、InputActionInteractionsPressを設定し、押した時にしか(もしくは離した時にしか)イベントを呼ばれないようにして、この問題を回避します。

f:id:tsubaki_t1:20190108225010g:plain
2回クリックしているが、押したときと離した時の2回呼ばれる為4回「Fire」とログが出る

f:id:tsubaki_t1:20190108225201j:plain
Press時にしかイベントを呼ばれないようにする

新しいInput Systemの利用(InputActions)

最後にInputActionを複数まとめたinputActionsを作り、多くのコントローラーで使い回す事をしてみます。
Input Actionには複数の入力やバインド情報がまとめられる他、入力時の動作実装を楽にするコードを生成する機能があります。

f:id:tsubaki_t1:20190108230017j:plain
InputActionを複数まとめたInput Actions

実際の手順を見てみます。今回もマウスの位置とクリックの入力を取得するコードを生成します。

  1. Assets > Create > Input ActionsでInput Actionアセットを作成します。名前はMyInputSampleとします。
  2. MyInputSampleをダブルクリックで開いて、Action Maps+をクリック、Playerを作成します。
  3. Actions+をクリック、バインドする入力を登録していきます。
  4. Save Assetボタンを押して、バインド画面を閉じます。
  5. MyInputSampleを選択後にGenerate C# Classにチェックを入れ、Generate Interfaceをクリックします。
  6. Applyボタンを押します。

これでApplyボタンを押した後にInputActionsと同じ名前のコードが自動的に生成されます。

f:id:tsubaki_t1:20190108231122g:plain
InputActions設定の流れ

f:id:tsubaki_t1:20190108231441j:plain
Generate C# Classでコードが自動生成される

次はC#側の実装を行います。

まずMyInputSample…先程生成されたクラスをフィールドに登録します。またMyInputSampleも有効にしないと動作しないので、input.Enable()input.Disable()で有効・無効を切り替えておきます。

動作の登録はインターフェースを使います。Action Mapを作ると自動的にI+ActionMap名+Actionsなるインターフェースが作られるので、継承します。今回の場合はSampleなのでISampleActionsが自動生成されます。後はメソッドの中身を埋めてinput.Sample.SetCallbacks(this);で自身(の持つコールバック)を登録します。

gist.github.com

最後にMyInputSample inputMyInputSample(アセット)を登録してやれば準備完了です。マウスを動かすとログが表示されます。

f:id:tsubaki_t1:20190108233231j:plain
作成したInputActionsを登録する

Control Schemaの追加

プラットフォーム毎に違う入力がある場合は、Control Schemaで作れそうです。例えば上はキーボードとマウスの動作ですが、ゲームパッドの動作を対応させようと思います。

  • No Control Schemaを選択し、Add Control Schemaを選択します。
  • +ボタンを押し、GamePadを選択
  • Addを押す

これでゲームパッドを利用中の場合のキー操作が作れました。

f:id:tsubaki_t1:20190108234322j:plain
Control Schemaの登録

この調子でVR機器やタッチパネル等、複数の端末に対応させるのが良さそうです。

動的なキーバインドの変更

アクションマップはテキストで制御されているので、差し替える事が出来ます。

例えば上でPC Schemaを追加した状態でFireの動作をマウスクリックからSpaceキーに変更する場合は、下のようなコードを記述します。

input.Sample.Fire.ApplyBindingOverride("<Keyboard>/space", input.PCScheme.bindingGroup);

この<Keyboard>/spaceの部分を確認する一番手っ取り早い方法は...ボタンを押すことですが、WIndow > Input Debugerのレイアウトから確認するのも良さそうです。コチラの場合は、実際にボタンを押せるのかといったレベルで確認出来ます。

f:id:tsubaki_t1:20190108235824g:plain
ボタンのバインド文字列を確認する

f:id:tsubaki_t1:20190109000059j:plain
Input Debuggerでボタンが反応しているのか、どのボタンがどのパラメータを持つのかを確認

毎フレーム入力の取得したい場合

InputActionは「操作が変化した瞬間」のみイベントを呼び出します。つまり押しっぱなしで移動するようなケースの場合にうまく動作しません。なので、トップのGifアニメのようなキャラクターを動かすような、毎フレーム入力を取得するようなアプローチに使用すると面倒な所があります。

その対策を色々と確認していますが、現状一番手っ取り早いのは下のようなアプローチです。

bool push;

public void OnFire(InputAction.CallbackContext context)
{
    push = context.ReadValue<bool>();
}

もしくは下のようなコードでも取得出来ました。下の例ではUpdateのタイミングでマウスの位置を取得し続けます。

void Update()
{
    var control = input.Sample.MousePosiiton.lastTriggerControl as Vector2Control;
    if (control != null)
    {
        Debug.Log(control.ReadValue());
    }
}

controlsでも入力は取得できますが、全てのスキーマの入力を取得してしまったのでlastTriggerControlの方が楽かなという印象です。

感想

概ね問題なく使えそうです。現状まだ完全にプレビューで未完成の部分がかなり多いですが、そのうち完成するんじゃないかなと。

今回は上辺だけ書きましたが、もう少しバージョンが進んだらもう少し込み入った部分も書いていきたい所です(バッファに入力を流し込んでる所とかの話)

関連

使い方の動画です

www.youtube.com

アップデート最新情報系

https://forum.unity.com/threads/input-system-update.508660/

Unity公式サンプルのリポジトリ(Stalableリポジトリだが動作するとは限らない)

github.com

【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