Unityメモ

Android の戻るボタン対応

Input Systemを使っている場合。さらに設定でキーボード対応にする必要がある。
→物理ボタンではない場合に、うまく戻れない
using UniRx;
using UniRx.Triggers;

public static void SubscribeBack(this MonoBehaviour monoBehaviour, Action action)
{
#if UNITY_ANDROID
            monoBehaviour.UpdateAsObservable()
                .Where(_ => UnityEngine.InputSystem.Keyboard.current.escapeKey.wasPressedThisFrame)
               .ThrottleFirst(TimeSpan.FromMilliseconds(3000))
                .Subscribe(_ => action());
#endif
}

void Start()
{
this.SubscribeBack(async () => await OnClickBack());
}

UIToolkit

https://forpro.unity3d.jp/unity_pro_tips/2022/04/21/3629/
XamlとかHtmlのようにUIを構築
ここコインでは今更なので採用しないが、将来はこれのみで良さそう

カメラの FOV について

家庭用ゲーム機だと、目とモニターが離れているので、70程度にすることが多い
PCや携帯だと、目とモニターが近くなるので、より大きい数字として100程度にする

大きな数字になるほどより広い範囲が見える一方で、中心は遠く見えるようになる

ここコインでは最大100にした

PlayFab のマッチメイキングについて

想定していた動きと違っていたのでメモ

想定
条件が合致するプレイヤーが全て返る
実際
条件が合致するプレイヤーから選ばれた対戦相手だけが返る

→選ばれた状態で結果が返るので、選ぶ操作は出来ない。
→他の人とマッチングした人は取得できない

CreateMatchmakingTicket に与える CreateMatchmakingTicketRequest には MembersToMatchWith があるが、
これはチーム戦で同じチームになる人を、代表者が入れたうえでチケットを作り、代表者同士でマッチングする。

シェーダー


レンダーキュー
https://waken.hatenablog.com/entry/2016/08/23/141057
通常は「シェーダーから」を選ぶ。
そうするとシェーダー自身が定義している数値が使用される。
表示されている値はそのシェーダーの数値
通常は2000

カスタムシェーダーの場合は、値が適切かを確認する。
不透明なものはジオメトリ(2000)を選ぶ。
透過するものが2500
画面全体の雰囲気に影響するもの(ポストエフェクト)とかはより大きい数字になる。

Canvas 内に Canvas がある場合で、SetActiveで表示を切り替えた場合に、その内部にあるボタンが押せなくなることがあった。

内側のCanvas を削除したら押せるようになった。
Canvas の入れ子は、以前スケールの自動調整のためにつけていたが、やらないようにする

Android 12 から、Androidの起動時およびアプリ切り替え復帰時のエラー


GetAudioStreamVolume では見つからず、Unity JNI  java.lang.SecurityException listen で出てきた以下で解決した
https://forum.unity.com/threads/android-12-telephony-crash.1287986/
編集 → プロジェクト設定 → プレイヤー → Android → その他の設定 → 他のオーディオソースをミュートにする

https://docs.unity3d.com/ScriptReference/PlayerSettings-muteOtherAudioSources.html
Unity アプリケーションの実行中に、他のアプリケーションからのオーディオをバックグラウンドで再生することを停止または許可します。

→ ゲーム中に電話が鳴った時に、電話コール音をミュートしてしまう。
上記を true にせずに READ_PHONE_STATE パーミッションを得る事でも回避出来るようだが、そんな権限付けたくないのでこれで行く

https://issuetracker.unity3d.com/issues/android-player-crashing-in-fmod-when-targetting-sdk-level-31
この不具合が修正されると直るかも

[unity]Addressable Asset System(AAS)に登録したファイル情報が丸見えな話

https://www.create-forever.games/unity-aas-catalog-file/
特に秘密ではないので、速度優先で設定はoffのままとした

CDN

  - CDNはそもそもキャッシュ機構であり、ユーザーは変更できない
    - 人気のルールなど、ある程度意味づけしたものだけにする
    - ルールを集めて一定間隔で更新していくとしても、結局どこかに置かないといけない
      - ユーザーごとの領域の上限範囲で格納するとか
  - PlayFab内での格納
    - タイトル全体で50TB。上限なしと考えてよさそう
    - ダウンロードに課金。おそらくAzureCDNと同じ
  - UnityのCDN https://unity.com/products/cloud-content-delivery
    - 転送量が50GBまで無料
    - クレジットカード等の登録は必須のようなので、超えたら即座に課金されそう。
  - CloudFlare https://www.cloudflare.com/ja-jp/plans/
    - 無料は512MBまで。ファイルサイズであり転送量ではない
    - 拡張子指定がある。使えそうなのはcsv
    - Unity-android https://developers.cloudflare.com/mobile-sdk/unity/unity-android
      - SDKがあるようだ
      - アプリの高速化を目的としたものらしい
      - →2021/2/22 廃止されたようだ https://support.cloudflare.com/hc/ja/articles/360054452251-%E9%9D%9E%E6%8E%A8%E5%A5%A8%E9%80%9A%E7%9F%A5-Cloudflare-Mobile-SDK
        - 理由は選択と集中らしい。後継もない。
  - Google Cloud CDN  https://cloud.google.com/cdn/pricing/?hl=ja
    - 無料は無し。お試し$300はある
  - https://www.wpexplorer.com/free-cdn-services-for-wordpress/
    - wordpress向けではあるが網羅されている
    - CloudFlareがトップであり、好意的な書き方
    - 将来の移行を考えるとAzure等に初めからしておくべきだが、それは捕らぬ狸の皮算用。必要となったらすればいい

開発参考

https://mixi-developers.mixi.co.jp/22-technical-training-5fc362a9dc41

Unityでの回転軸の合成順番
Y→X→Z (ワールド座標からみたらZ→X→Y)

var rotX = Quaternion.AngleAxis(input.x, Vector3.right);
var rotY = Quaternion.AngleAxis(input.y, Vector3.up);
var rotZ = Quaternion.AngleAxis(input.z, Vector3.forward);
translate.rotation *= rotZ * rotX * rotY;

HorizontalLayout で、内部に Text を持ち、LayoutElement で Flexible Width を設定したが幅がずれる

https://kyoto-games.hatenablog.jp/entry/2017/06/21/025302
Min Width にチェックを入れて 0 を入れる
Preffed Width にチェックを入れて 0 を入れる

Collider は、アタッチしたGameObjectが移動しても同じ位置に留まる。エディタ上は枠が移動しているが、判定位置は異なる。

以下のいずれかを行うと一致する。

ここコインでは詳細表示の時でだけColliderを使っているため、
詳細表示を開始する時に更新するようにした。

ライトの種類の一つ「エリア(ベイクのみ) 」の使い方

  1. エリアライトを置く
  2. 反映させるオブジェクトを静的にする。
  3. ウィンドウ → レンダリング → ライティング でライティング設定を作る
  4. ライティングインスペクタの一番下にある自動生成にチェックを入れる
  5. 処理に時間が掛かるが、しばらくするとエリアライトが反映される

→ 使う場面は少なそう。
https://tsubakit1.hateblo.jp/entry/2017/02/06/233000
発光するマテリアル
放出にチェックを入れる
→同じく自動生成(ベイク)が必要なので、代替にはならない。そのまま素直に発光するオブジェクトに使う

→ライティング設定ごとにベイクデータが付くという事なら、シーンごとにライティング設定を持った方がよさそう

影が柔らかくなる、という特徴もある。実際、DirectionLightより現実に近い見た目になった

全体を暗くするには、Directional Lightの向きを反転

強さ(Intensity)を0にする、という説明もあった
→エディタ上で初めから向きを変えるのと、実行中に向きを変える場合で見た目が違う。ベイクされている
→エディタ上でDirectionalLightのチェックをoffにしても暗くならず、完全に暗くするには向きを変えるしかない

スポットライト実装

Light Shaft という名称が一般的

https://medium.com/@NegativeMind/unity%E3%81%A7light-shaft%E3%82%92%E8%A1%A8%E7%8F%BE%E3%81%99%E3%82%8B-b66e92a81ad5
文中のAsset Storeは提供終了している
コード取り込み。一部修正

Editor上でのカメラでは何も表示されないが、実行すると表示された。

デフォルトから明度のみ1にすると、目的に近い見た目
ただし前述のとおり、初めからDirectionalLightを変えて暗くしないと地面などが明るいまま

→LightShaftsはWindowsおよびOSXで動作、とあったので使用しない

GooglePlayGamesPlugin-0.11.01 に更新しようとしたがうまくいかなかった話


Assets以下ではなくパッケージに変わったようだ。
ExternalDependencyManager と GooglePlayGames のフォルダを消してからパッケージ取り込みをすると
エディタ上はエラーが無くなるが、Androidビルド時にエラー
他にも消すべきものがありそうだが、ここまでとした。

→ その後やり直しで出来た。

ノッチ部分は無視するようにした

https://baba-s.hatenablog.com/entry/2019/03/08/122500
UIをずらす場合はScreen.safeAreaで計算
https://docs.unity3d.com/ja/2021.1/ScriptReference/Screen-safeArea.html

対応するなら、ルートCanvasの子を一つ挟んで、それを変更するとか
https://eiki.hatenablog.jp/entry/2020/06/24/192013

→やってみたがCanvasScalerを使っている前提のロジック。KoKoCoinではいろいろあって無効化しているので調査が必要
→以下のようにしたらある程度出来たが、何度かやると必要以上に空くので止めた。なお、回転後イベントの実装
public void SetBannerSpace(RectTransform canvasInner)
{
    // ノッチ分の計算。一度に180度回転した時に正しくない事があるので、ノッチが無いほうも同じだけ空ける。
    var safeArea = Screen.safeArea;
    var marginX = Math.Max(safeArea.xMin, Screen.width - safeArea.xMax);
    var marginY = Math.Max(safeArea.yMin, Screen.height - safeArea.yMax);

    var offsetMin = new Vector2(marginX, marginY);
    var offsetMax = new Vector2(-marginX, -marginY);

    if (UserSettings.Instance.UseAdBannerTop)
    {
        offsetMax.y -= GetBannerHeight();
    }
    else if (UserSettings.Instance.UseAdBannerBottom)
    {
        offsetMin.y += GetBannerHeight();
    }

    canvasInner.offsetMin = offsetMin;
    canvasInner.offsetMax = offsetMax;
}

Android ビルド時に表示されるメッセージボックスについて

Warning!!  Google Play Games was not configured, Game Services will not work correctly.
https://anndoroido.blogspot.com/2016/07/unity-google-play-games-not-configured.html

ウィンドウ → Google Play Games → Setup → Android Setup
Google 開発者コンソールで取得した内容を張り付ける。
https://github.com/playgameservices/play-games-plugin-for-unity

クエスト(実績)またはリーダーボードの追加が必要
→APIアクセスに必要、とあるので作らなければいい

ゲーム実行時に出る「ようこそ●●さん」について
https://developers.google.com/games/services/android/signin
https://firebase.google.com/docs/auth/unity/play-games?hl=ja#integrate_play_games_sign-in_into_your_game
→自動ログインがデフォルトになって、操作できない?
隠す設定はありそうに見えるがUnityから触れるかどうか
https://stackoverflow.com/questions/21524560/google-play-game-services-welcome-back-popup-not-shown
https://answers.unity.com/questions/1112572/stop-google-play-games-popup-if-user-denies.html
→ PlayGamesLocalUser.Authenticate はコード上にあった

Text のサイズ自動調整をONにした場合で、途中に空白があるなどすると勝手に折り返される。

これを無効にして常に一行でサイズ計算したい場合、行間隔を適当に大きな数字にすると一行になる。
https://forum.unity.com/threads/ui-text-single-line.272284/

パーティクルのスケーリングはデフォルトがローカルになっているが、GameObjectのスケールとは動作が異なる。

合わせるにはヒエラルキーを選ぶ。
ただしパーティクルエディタ上の挙動と実際の挙動が合わなくなるので、調整は難しくなる。
ゲーム中にスケールが変わるオブジェクトの子として配置するかどうかで決める。

LayoutGroupの子にContentSizeFitterが設定できないが、これはLayoutGroup自体がコンテンツに合わせてサイズ変更する機能があるため。

「子のサイズを制御」のチェックを入れる。
この事が理由で、例えばボタンがあり、その中にあるテキストに従ってボタンを大きくしようとしても
テキストの親はボタンでありLayoutGroupではないので出来ない。

UI の均等割り

https://unity-yuji.xyz/ui-equal-division-in-screen-size/

上下分割。区切り10
VerticalLayoutGroup 間隔10。子のサイズを制御 幅ON 高さON
LayoutElement FlexibleWidth 1。FlexibleHeight 1
LayoutElement FlexibleWidth 1。FlexibleHeight 1

VRMをUnityに取り込む

https://vroid.com/studio

https://github.com/vrm-c/UniVRM
説明
https://vrm.dev/docs/univrm/
まずは新規プロジェクトに作ったほうが無難そうだ
取り込みだけしてPrefabにしたら、後は別の場所に持っていけるかどうか
モーションはある程度作ってからがよさそう

Unity で iOS/Android アプリの設定値をセキュアに扱う方法

https://zenn.dev/nikaera/articles/unity-ios-android-secret-manager

設定値格納用。バイト配列の関数がない。

広告

広告のプレースメント
https://developers.google.cn/admob/unity/ad-placements?hl=ja
Unity AdMobの広告プレースメントでモバイルアプリ内広告を実装する
https://qiita.com/minaduki_mina88/items/b29ea345519fc17ad849

実行時の警告
You are trying to create a MonoBehaviour using the 'new' keyword.
GitHub Issue https://github.com/googleads/googleads-mobile-unity/issues/1585
- とりあえず気にしなくてよいようだ。ソースを取り込んだ場合は手動で変えられるが、DLLで使っているので出来ない。

Google Unity向けのビルド

https://developer.android.com/guide/app-bundle/asset-delivery/build-unity?hl=ja
アプリのサイズは150MBを超える事が出来ないが、PlayAssetDelivery だと、一部を実行時配信などにすることで、サイズを超えられる
CDNが不要とのこと
→そこまで大きくなったら考える

縦向き対応

フォルダ名の先頭に . か、フォルダ名の末尾に ~ を入れることで、フォルダ自体が無視される。

https://docs.unity3d.com/Manual/SpecialFolders.html
PlayFab.Playを使えないプラットフォームで、コード自体をビルドさせないようにすることや、
音ファイルを含めないようにするなど

あたらしいUnityバージョンを入れるときにメッセージが出た時

Failed to delete old Unity installation files. Maybe Unity or some of its tools are still running?
UnityHub自体を管理者権限で実行する

Android で、ステータスバー(上部の時間とかバッテリーとか表示されている部分)を表示

https://forum.unity.com/threads/status-bar-always-hidden-on-android.362779/
https://github.com/Over17/UnityShowAndroidStatusBar
半透明や透明無しも出来るようだ
JavaでUnityPlayerActivityを継承しているので、コードだけ持ってくる
やってみたが、廃止予定関数を使っており、代替が不明なので見送り。

Google Play Console でアップロードした際に androidx.fragment:fragment が古い、という警告

mainTemplate.gradle に

dependencies {
implementation 'androidx.fragment:fragment:1.1.0'
// ...
**DEPS**}

と書けばバージョンを変えられるが、本来はUnity側の対応になるのでは。