[unity2019]Android でアプリを実行する[初心者向け]

unity2019 では、

unityで面倒なパス設定をせず
Android Studio を入れる必要もなく

Android 実機でアプリを実行することが出来ます。

あまりに簡単でビックリ

ただ、問題ゼロとはいきません。その対処についても追記するので、お役に立てると嬉しいです。

インストール条件

unity2019 であること
unity2019 インストール時に Android SDK & NDK Tools、OpenJDK も入れておく(チェックする)こと

このチェックは必須

実機を繋いでビルド&実行

USB 端子に Android 実機を繋ぐ

unity の File - Build Setting

Android を選び、Switch Platform
しばらく時間がかかります

Build And Run

Android端末のUSBデバッグを許可する

機種によって画面は異なりますが、USB 設定画面でおそらく設定可能なのではないかと。

この画面は AQUOS SH-M12
許可したら Retry

たったこれだけで動作!

とかいって、本当は色々と問題あったんでしょ?

ハイ。仰る通りです。

最初はビルドエラー

英語はなんとなく UnityScript なんてしらないよ、と言ってそうです。
コードを見たところこのようになっていました。

英語がわからなくても、Google 翻訳や Deepl などを使えば大体わかる

いつこの using が入ったのか記憶にはないのですが…おそらく色々とこねくり回している最中にまぎれこみ、後で必要なくなって残骸として残ったようです。

不要なコードなので、今回はこの行を削除しました。

using で色が灰色になっているものは未使用。なので、消しても大丈夫です。
Visual Studio2019 では右クリック > using の削除と並び替え、で消すこともできます。
(VS Code も多分似たような機能はあるでしょう。タブン)

万が一必要なコードだった場合は、#if を使って

Windows では処理するけど、Android では処理しない

という切り分けを行う必要があります。今回のであればこんな感じ。

#if UNITY_STANDALONE_WIN
using UnityScript.Scripting.Pipeline;
#endif

Macなら、Editorなら、iOSなら…など様々な定義が用意されています。
詳しくは Unity のホームページ で確認しましょう。

起動はしたが、初期画面から進まない

Made by unity までは無事表示できましたが、最初はタイトル画面が出ませんでした。

こんな感じ

灰色っぽい背景色、また外枠は表示されているのが確認できたので、心臓部である main シーンは実行されたが、その次の menu シーンで問題が起きた。と仮定しました。

今回のプロジェクトでは、ということです。
基本的に、問題解決は仮定ー推論ー確認ー当たりなら修正、というプロセスを問題がなくなるまで続ける必要があります。

プログラムで1番辛いのは問題の原因を探すとこ…。
丁寧に一つずつ確認するのが大事。

Unity Editor で実行してみる

仮定や推論のためにもう少し情報が欲しいと、Unity Editor で実行したところ、灰色画面ではないものの思いきりエラーが出ていました。

このエラーはさすがに見過ごせんと検証した結果、以下の問題が見えてきました。

Animator のモーション名は、Windows だと取得できるが Android だと取得できない

具体的には以下のコードが上手く動きません。
Android の場合、ac.layers.Length は 0 を返してしまうようです。

UnityEditor.Animations.AnimatorController ac = animator.runtimeAnimatorController as UnityEditor.Animations.AnimatorController;

motionNames = new HashSet<string>();

// Animator に登録された名前を取得
for (int layer = 0; layer < ac.layers.Length; layer++)
{
    for (int s = 0; s < ac.layers[layer].stateMachine.states.Length; s++)
    {
        UnityEditor.Animations.ChildAnimatorState state = ac.layers[layer].stateMachine.states[s];

        motionNames.Add(state.state.name);
    }
}
warningNames = new HashSet<string>();

モーションを再生(Play) する分には Windows でも Android でも問題なく実行できているので、デバッグ用にモーション名を取得したり、その存在を確認している上記ロジックを外すことにしました。

この修正で、Unity Editor ではエラーなく動くようになりましたが、相変わらず実機では動きませんでした。

AssetBundle リビルドしてなかった問題

完全にウッカリ

ソースコードを更新していてふと気づきましたが、プラットフォームを変えてから AssetBundle を作り直してなかった気がします。

さすがにデータは機種依存でなければまずそうです。全てリビルドしました。

自作のツールを使ってます

その後実機に Build And Run したところ、無事に動きました!

細かい問題を解決する

動いたけど、まだまだ問題アリ

動くだけでも8割がた満足ですが、細かい点を挙げると気になる点はいくつかあります。
まず、画面の向き。
横長画面のゲームなので、画面は横固定にしたいです。

こちらになってほしい

アイコンも unity のままになっているので、ちゃんとしたアイコンにしたいですね。

アイコンを変える

Edit - Project Settings - Player

オレンジ色の部分を好みの画像にしてください。
(画像は Assets/ に含める必要があります)

なお、圧縮された画像の場合「見た目が悪くなるかもしれない。大丈夫?」という警告が出るようです。

CompressionをNoneに

画面を横固定にする

Default OrientationLandscape Left(またはRight)にします。

色々な画面サイズでもキチンと表示されるようにする

よく見るとキャラクターの左右、一部黒く出ているのがわかります。

オレンジ部分が問題箇所

あらゆる解像度のスマフォ画面に対応するためには、この問題を解消する必要があります。

ハミ出した理由:unity で設定した画面比率と、スマフォの画面比率が異なるため

unity では画面サイズ 1920x1080 pixel(16:9) を基準として開発していました。
これは 2K テレビや、Youtube の最大解像度ですね。

Game Viewは16:9

Canvas で1920x1080を設定

一方、今回テストに使用したアンドロイド AQUOS SH-M12 は 2160x1080 です。

価格の割に性能はイマイチだと後で知った…

つまり、1920x1080 が基準であれば 2160-1920 = 240、左右 120 ピクセル分広い画面となります。

そのため、こんな感じで左右の手が枠からはみ出しているわけです。

また、横ではなく縦の方が長い場合、横方向がはみ出すことはなくなりますが、縦方向に同じ問題が。

こちらの方がハミ出してる感が強い

このハミ出している部分を見えなくしたいので、ハミ出している部分に黒いイメージ(板)を置いて、見えないようにします。

アスペクト比を無視して画面最大まで絵を引き延ばすという手もありますが、キャラが痩せたり太ったりするので、お勧めしません。

2つの板はスマフォの解像度によって適切な位置・サイズになるようにプログラムで調整します。

const float TARGET_WIDTH  = 1920f;
const float TARGET_HEIGHT = 1080f;

float scale_w = Screen.width  / TARGET_WIDTH;
float scale_h = Screen.height / TARGET_HEIGHT;

if (scale_w > scale_h)
{
    // 横方向にマスク
    float width = ((Screen.width / scale_h) - TARGET_WIDTH) / 2;
    float x = TARGET_WIDTH / 2 + width / 2;
    // SetXY, SetSize は RectTransform の拡張メソッド
    RectMasks[0].SetXY( x, 0);
    RectMasks[0].SetSize(width, Screen.height);
    RectMasks[1].SetXY(-x, 0);
    RectMasks[1].SetSize(width, Screen.height);
}
else
{
    // 縦方向にマスク
    float height = ((Screen.height / scale_w) - TARGET_HEIGHT) / 2;
    float y = TARGET_HEIGHT / 2 + height / 2;
    RectMasks[0].SetXY(0,  y);
    RectMasks[0].SetSize(Screen.width, height);
    RectMasks[1].SetXY(0, -y);
    RectMasks[1].SetSize(Screen.width, height);
}

コードが面倒、多少描画ロスしても絵を置いただけでなんとかしたいという人は、見えない部分に大き目の四角いマスクの絵をただ表示しておく、というのもアリかもしれません。

現実的にどんな比率のスマフォがあるかはわからないため、この程度の大きさだとハミ出すかもしれませんが…。
前述のコードで制御する場合はどんな画面サイズでも計算するので、マスクが足りない、という事が発生しません。

無事、完成しました!

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA