そういうのがいいブログ

アプリ個人開発 まるブログ

アプリ開発覚え書き

【Unity】Androidビルド時の警告 PlayerSettings->Active Input Handling is set to Both, this is unsupported on Android and might cause issues with input and application performance. Please choose only one active input handling. Ignore and continue? (This dialog won't

要件

Unity 6000.0.55f1

はじめに

Androidにてビルドしたところ、下記の警告が発生したので対応をメモ

PlayerSettings->Active Input Handling is set to Both, this is unsupported on Android and might cause issues with input and application performance. Please choose only one active input handling. Ignore and continue? (This dialog won't appear again in this Editor session if you'll choose Yes)

警告内容

プロジェクト設定の Active Input Handling をどれにすべきか聞かれています。
「Active Input Handling」は入力方式(旧 Input Manager、新 Input System)を選択する設定です。

現在は Both(旧 Input Manager + 新 Input System の両方) に設定されていますが、
Android では Both は公式にサポートされていません。
そのため、入力の競合やパフォーマンス低下を防ぐ目的で Unity が警告を出しています。

どちらにすべき?

Input Manager (Old) が良いとき

  • タッチ操作だけの Android アプリを開発する場合
  • 生成AIを活用してコードを書く場合(情報量が豊富でコード例が出やすい)
  • 過去の旧Input Manager用コードやアセットを流用したい場合
  • 初期設定を簡単に済ませたい場合

メリット:
UIボタンやタッチ入力が設定なしでそのまま動作し、
学習コストが低い。Androidビルドでも安定して動く。

Input System Package (New) が良いとき

  • PC対応やゲームパッド対応を予定している場合
  • キーボード、マウス、タッチ、コントローラーなど複数の入力デバイスを統一的に扱いたい場合
  • 入力マッピングやカスタマイズ性を重視する場合
  • 新しいAPIで将来的な拡張を見据えている場合

注意点:
UIボタンやタッチ入力を使う場合はInput System UI Input Moduleへの切り替えが必要。
旧Input Managerのコードはそのままでは動かないため書き換えが必要。


設定方法

  1. Unity メニューから 編集 > プロジェクト設定 > プレイヤー を開く

  2. アクティブな入力規則 のプルダウンを以下のいずれかに変更
     ・入力マネージャー(旧)
     ・入力システムパッケージ(新)

  3. Unity を再起動して反映


旧版に設定すると・・・

旧版に設定して再起動すると下記の警告が発生します。 旧版で使うなら「No」を押します。

This project is using the new input system package but the native platform backends for the new input system are not enabled in the player settings. This means that no input from native devices will come through.

Do you want to enable the backends? Doing so will RESTART the editor.

おわりに

Unityとしては、「 Input System Package (New)」を推奨していくはずですので、
新規プロジェクトであれば、 Input System Package (New)を採用した方が良さそうですね。

【Unity】URPプロジェクトで 反射(鏡面)床を作る方法 

要件

Unity 6000.0.26f1
URPプロジェクト

はじめに

URPプロジェクトにおける反射(鏡面)床のメモです。

以下の記事を参考にさせていただき、
自プロジェクトで都合の良いように変更しています。

qiita.com

対象読者は、Unityの簡単な操作ができる方です。

概要

反射床を作る方式は複数あるようですが、
今回は「Planar Reflection」という方式で進めます。

概要としては、以下を行い反射床を表現しています。
1.床に対して反転したカメラを用意
2.反転カメラの映像をレンダーテクスチャに映す
3.レンダーテクスチャに映した映像を専用シェーダーで左右反転させる
4.左右反転したレンダーテクスチャの映像を床に映す

作成手順

1.オブジェクトの準備

1.1 反射床用のオブジェクトを用意する

平面を追加します。

ヒエラルキーの「+」ボタン
→「3Dオブジェクト」
→「平面」


このような平面が追加されます。

1.2 反射確認用オブジェクトの配置

確認用に3Dオブジェクトのキューブやカプセルを反射床の上に配置しておきます。

1.3 反射用カメラの設置

反射用カメラを追加します。

ヒエラルキーの「+」ボタン
→「カメラ」


追加したカメラの名前を「ReflectionCamera」としておきます。(好きな名前でOK)

オブジェクトの準備は以上です。


2.コンポーネントの設定

メインカメラと反射用カメラへのコンポーネント設定を行います。

2.1 メインカメラにコンポーネント追加

メインカメラにスカイボックスコンポーネントを追加します。


スカイボックスコンポーネントを追加後、
好きなスカイボックスのマテリアルを設定してください。


今回はデフォルトのスカイボックスマテリアルを使用します。


2.2 反射用カメラの設定

反射用カメラは以下の設定を行います。
・Cameraコンポーネントをオフ
・ポストプロセスを有効化
・Audio Listenerの削除
・スカイボックスコンポーネントを追加


反射カメラのスカイボックスコンポーネントには、
メインカメラのマテリアルをスクリプトで設定します。
そのため、マテリアルの設定は不要です。

3.反転シェーダーを作成

カメラから受け取った映像を反転するシェーダーを作成します。

今回作成するシェーダーは色設定、反射強度設定、ぼかし設定の機能も持ちます。

プロジェクトタブの「+」ボタン
→「シェーダー」
→「Unlitシェーダー」


シェーダーの名前は「PlanarReflection」にしてください。


シェーダーのファイルをダブルクリックしてシェーダーファイルを開き、
中身を下記に置き換えてください。

Shader "Custom/PlanarReflection"
{
    Properties
    {
        _Color("Base Color", Color) = (1, 1, 1, 1)
        _MainTex("Main Texture", 2D) = "white" {}
        _ReflectionTex("Reflection Texture", 2D) = "white" {} // PlanarReflectionスクリプトで渡されるリフレクションテクスチャ
        _reflectionFactor("Reflection Factor", Range(0, 1)) = 1.0 // 反射強度 0:反射なし ベースカラーのみ 1:完全に反射のみ
        _Roughness("Roughness", Range(0, 1)) = 0.0 // ぼかし強さ 0:ぼかし無し 1:最大ぼかし
        _BlurRadius("Blur Radius", Range(0, 10)) = 5.0 // ぼかし量を制御
    }
    SubShader
    {
        // "Queue"="Geometry" → 描画順をGeometryキュー(通常の不透明オブジェクト:2000)に設定
        // "RenderType"="Opaque" → 不透明オブジェクトとして扱う(レンダリングパスやポストプロセスで使用)
        Tags { "Queue"="Geometry" "RenderType"="Opaque" }

        // 深度バッファでの位置を調整する。
        // 負の値でカメラに近づける → 同じ座標の他オブジェクトよりも優先的に描画される
        // 今回は Offset -1, -1 で、わずかに手前扱いにする
        Offset -1, -1

        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD1;
            };
            struct v2f
            {
                float2 uv : TEXCOORD1;
                float4 screenPos : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };
            // パラメータ宣言
            float4 _Color;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _ReflectionTex;
            float4 _ReflectionTex_ST;
            float _reflectionFactor;
            float _Roughness;
            float _BlurRadius;
            float4 _BaseColor;

            // ガウス重み関数
            float gaussianWeight(float x, float sigma)
            {
                // ガウス重み: exp(-x²/(2σ²))
                return exp(-(x * x) / (2.0 * sigma * sigma));
            }
            // ガウスぼかしサンプリング関数
            half4 gaussianBlur(sampler2D tex, float2 uv, float blurAmount)
            {
                // _Roughness が小さい場合は計算コストを避けるためオリジナルテクスチャをそのまま返す
                if (blurAmount <= 0.001)
                {
                    return tex2D(tex, uv);
                }
                half4 color = half4(0, 0, 0, 0);
                float totalWeight = 0.0;
                // ピクセルサイズ: 画面解像度から取得
                float2 texelSize = float2(1.0 / _ScreenParams.x, 1.0 / _ScreenParams.y);
                // 動的にサンプル範囲とステップを調整
                int sampleCount = (int)lerp(3, 9, _Roughness);
                float stepSize = blurAmount * _BlurRadius;
                float sigma = stepSize * 0.5;
                // 2次元畳み込み: 水平方向・垂直方向のぼかし
                for (int x = -sampleCount; x <= sampleCount; x++)
                {
                    for (int y = -sampleCount; y <= sampleCount; y++)
                    {
                        // オフセットの計算(ピクセル空間→UV空間)
                        float2 offset = float2(x, y) * texelSize * stepSize;
                        float2 sampleUV = uv + offset;
                        // 境界チェック: UVが 0~1 の範囲内か確認
                        if (sampleUV.x >= 0.0 && sampleUV.x <= 1.0 &&
                            sampleUV.y >= 0.0 && sampleUV.y <= 1.0)
                        {
                            // 中心からの距離を計算
                            float distance = length(float2(x, y));
                            // ガウス重みを取得
                            float weight = gaussianWeight(distance, sigma);
                            // 重み付きで色を加算
                            color += tex2D(tex, sampleUV) * weight;
                            totalWeight += weight;
                        }
                    }
                }
                // 正規化した色を返す(加重平均)
                return color / totalWeight;
            }

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.screenPos = ComputeScreenPos(o.vertex); // スクリーン座標に変換。これがないと反射描画が正しくならない
                o.uv = v.texcoord;
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                // カメラが描画した位置のUVを取得
                float2 screenUV = i.screenPos.xy / i.screenPos.w;
                half4 tex_col = tex2D(_MainTex, i.uv);

                // screenUV の X を反転して鏡面UVとする
                float2 reflectionUV = float2(1 - screenUV.x, screenUV.y);
                // ガウスぼかしを適用
                half4 reflectionColor = gaussianBlur(_ReflectionTex, reflectionUV, _Roughness);
                // 反射とメインテクスチャを混合
                fixed4 col = tex_col * _BaseColor * reflectionColor;
                col = lerp(tex_col * _BaseColor, col, _reflectionFactor);

                return col;
            }
            ENDCG
        }
    }
}



4.反転シェーダーのマテリアルの作成と割当て

4.1 マテリアル作成

反転シェーダーのマテリアルを作成します。

→作成したシェーダーファイルを右クリック
→「作成」
→「マテリアル」


作成したシェーダーを使用するマテリアルが作成されました。

4.2 マテリアル割当て

作成したマテリアルを反射床のオブジェクトにドラッグ&ドロップをして割り当てます。


反射床の見た目は真っ黒になりますが問題ありません。

5.反射用スクリプトの作成と割当て

5.1 スクリプト作成

新規スクリプト「PlanarReflectionView」を作成し下記の内容に変更します。

using UnityEngine;
//using Unity.Cinemachine;
using System.Collections;

public class PlanarReflectionView : MonoBehaviour
{   
    [Header("References")]
    //[SerializeField] private CinemachineBrain _cinemachineBrain;
    [SerializeField] private Camera _mainCamera;// メインカメラ
    [SerializeField] private Camera _reflectionCamera = null;// 反射用テクスチャを取得するためのリフレクションカメラ
    [SerializeField] private GameObject _reflectionTargetPlane = null; // 反射平面を行うオブジェクト
    [SerializeField] private Skybox _mainSkybox;
    [SerializeField] private Skybox _reflectionSkybox;

    
    [Header("Render Settings")]
    [SerializeField, Range(0.3f, 1.0f)] private float _resolutionScale = 1.0f;// テクスチャ解像度(数値を上げるほど高負荷) 0.3f: 低解像度, 1.0f: フル解像度    

    [Header("Material Properties")]
    [SerializeField] private Color _reflectionColor = Color.white; // 反射の色
    [SerializeField, Range(0.0f, 1.0f)] private float _reflectionFactor = 1.0f; // 反射強度 0:反射なし ベースカラーのみ 1:完全に反射のみ
    [SerializeField, Range(0.0f, 1.0f)] private float _roughness = 0.0f; // ぼかし強さ
    private const float _blurRadius = 5.0f; // ぼかし半径
    
    [Header("Internal Runtime States")]
    private RenderTexture _renderTarget; // リフレクションカメラの撮影結果を格納するRenderTexture
    private Material _floorMaterial; // 平面のマテリアル シェーダー(PlanarReflection)操作用
    
    private int _lastScreenWidth;
    private int _lastScreenHeight;
    private float _lastResolutionScale;

    //private ICinemachineCamera _lastActiveVirtualCamera;
    
    private void Start()
    {
        /*
        if (_mainCamera == null || _reflectionTargetPlane == null || _cinemachineBrain == null)
        {
            Debug.LogError("PlanarReflection: 必要なコンポーネントが設定されていません。メインカメラ、反射平面、CinemachineBrainを確認してください。");
            enabled = false;
            return;
        }
        */

        //反射平面のマテリアル取得
        Renderer renderer = _reflectionTargetPlane.GetComponent<Renderer>();
        _floorMaterial = renderer.sharedMaterial;
        
        
        // カメラコンポーネント無効化:リフレクションカメラはUnityのデフォルトレンダリングフローには参加させず、不要なレンダリングや順序の問題を避ける
        _reflectionCamera.enabled = false;

        // 初期スクリーンサイズとスケール
        _lastScreenWidth = Screen.width;
        _lastScreenHeight = Screen.height;
        _lastResolutionScale = _resolutionScale;
        
        CreateRenderTarget();
    }

    void Update()
    {
        if (_floorMaterial != null)
        {
            _floorMaterial.SetColor("_BaseColor", _reflectionColor);
            _floorMaterial.SetFloat("_reflectionFactor", _reflectionFactor);
            _floorMaterial.SetFloat("_Roughness", _roughness);            
        }
        
        // スクリーンサイズ or 解像度スケール変更検出
        if (Screen.width != _lastScreenWidth ||
            Screen.height != _lastScreenHeight ||
            !Mathf.Approximately(_resolutionScale, _lastResolutionScale))
            //|| _lastActiveVirtualCamera != _cinemachineBrain.ActiveVirtualCamera) シネマシーンを使用する場合はこの条件もif分に追加
        {
            _lastScreenWidth = Screen.width;
            _lastScreenHeight = Screen.height;
            _lastResolutionScale = _resolutionScale;
            RecreateRenderTarget();
           
            //_lastActiveVirtualCamera = _cinemachineBrain.ActiveVirtualCamera;
        }
    }

    private void LateUpdate()
    {
        // フレーム終了時に反射描画
        StartCoroutine(RenderReflectionAtEndOfFrame());
    }
    
    private IEnumerator RenderReflectionAtEndOfFrame()
    {
        /*
        WaitForEndOfFrame は Unity がフレーム描画を行う「直前」に実行されます。
        CinemachineBrain の LateUpdate → Transform 更新 → WaitForEndOfFrame() → 反射描画 という順番で、確実に正しい位置で反射を描画できます。
        */
        yield return new WaitForEndOfFrame();
        RenderReflection();
    }

    
    private void CreateRenderTarget()
    {
        int width = Mathf.Max(256, Mathf.RoundToInt(Screen.width * _resolutionScale));
        int height = Mathf.Max(256, Mathf.RoundToInt(Screen.height * _resolutionScale));
        
        // 既存のRenderTextureがあれば解放
        if (_renderTarget != null)
        {
            _reflectionCamera.targetTexture = null;
            _renderTarget.Release();
            DestroyImmediate(_renderTarget);
        }
        
        // 新しいRenderTextureを作成
        _renderTarget = new RenderTexture(width, height, 24)
        {
            name = "PlanarReflectionRT",
            useMipMap = true,
            autoGenerateMips = true
        };

        _floorMaterial.SetTexture("_ReflectionTex", _renderTarget);// マテリアルにリフレクションテクスチャを設定
        _floorMaterial.SetFloat("_BlurRadius", _blurRadius);
    }
    
    private void RecreateRenderTarget()
    {
        if (_renderTarget != null)
        {
            _reflectionCamera.targetTexture = null;
            _renderTarget.Release();
            DestroyImmediate(_renderTarget);
        }
        CreateRenderTarget();
        
        RenderReflection();//カメラ変更時に真っ黒な床が一瞬表示されるためすぐ描画する。
    }

    private void RenderReflection()
    {
        // メインカメラの設定をコピーし、位置・向きなどを反映
        _reflectionCamera.CopyFrom(_mainCamera);
        
        // Skybox同期
        if (_mainSkybox != null && _mainSkybox.material != null)
        {
            _reflectionSkybox.material = _mainSkybox.material;
        }

        // ワールド空間でのメインカメラの方向・上向き・位置
        Vector3 cameraDirectionWorldSpace = _mainCamera.transform.forward;
        Vector3 cameraUpWorldSpace        = _mainCamera.transform.up;
        Vector3 cameraPositionWorldSpace  = _mainCamera.transform.position;

        // 反射平面オブジェクトのローカル空間に変換
        Vector3 cameraDirectionPlaneSpace = _reflectionTargetPlane.transform.InverseTransformDirection(cameraDirectionWorldSpace);
        Vector3 cameraUpPlaneSpace        = _reflectionTargetPlane.transform.InverseTransformDirection(cameraUpWorldSpace);
        Vector3 cameraPositionPlaneSpace  = _reflectionTargetPlane.transform.InverseTransformPoint(cameraPositionWorldSpace);

        // ローカル空間では平面の法線が (0, 1, 0) と仮定し、Y軸方向を反転して鏡面対称を得る
        cameraDirectionPlaneSpace.y *= -1.0f;
        cameraUpPlaneSpace.y        *= -1.0f;
        cameraPositionPlaneSpace.y  *= -1.0f;

        // 再びワールド空間へ変換
        cameraDirectionWorldSpace = _reflectionTargetPlane.transform.TransformDirection(cameraDirectionPlaneSpace);
        cameraUpWorldSpace        = _reflectionTargetPlane.transform.TransformDirection(cameraUpPlaneSpace);
        cameraPositionWorldSpace  = _reflectionTargetPlane.transform.TransformPoint(cameraPositionPlaneSpace);


        // 反射カメラに位置と向きを設定
        _reflectionCamera.transform.position = cameraPositionWorldSpace;
        _reflectionCamera.transform.LookAt(cameraPositionWorldSpace + cameraDirectionWorldSpace, cameraUpWorldSpace);

        // レンダリングターゲットを設定して描画
        _reflectionCamera.targetTexture = _renderTarget;
        _reflectionCamera.Render();
    }
}

※一部コメントアウトしているのはCinemachineを使う時用です。


5.2 スクリプト割当て

空のオブジェクトを作成し、作成したスクリプト「PlanarReflectionView」を割り当てます。


6.スクリプト必要情報割当て

空のオブジェクトをクリックして
インスペクター上に表示されているReferencesの5項目に情報を割り当てます。

MainCamera → メインカメラのオブジェクトを割当て
ReflectionCamera → 反射カメラのオブジェクトを割当て
ReflectionTargetPlane → 反射床オブジェクトを割当て
MainSkybox → メインカメラのオブジェクトを割当て
ReflectionSkybox → 反射カメラのオブジェクトを割当て

以上で準備完了です。

確認

プレイボタンを押してメインカメラの位置や回転を変更してみると、
平面上に反射しているかのような映像が映されます。


※メインカメラの映像を基に平面へ映像を映しているという手法のため
 シーンビュー上では反射しているように見えません。

おわりに

アプリケーションとして出力した場合でもウインドウサイズの変更にも対応しています。
お役に立てましたら幸いです。

【Unity】画像をUnityに取込み後 スプライトとして使えない問題への対応策

要件

Unity6000.0.26f1

はじめに

画像をUnityに取り込んでUIなどで使用する際には、
取り込み後、テクスチャタイプを「スプライト(2DとUI)」に変更することで使用できていました。


しかし、Unity6000系になってからはスプライトが扱えないようになっています。

理想:スプライトを扱える

現実:スプライトを扱えない


原因

原因はスプライトモードがデフォルトで「複数」に設定されているためでした。

対応策

対応策はスプライトモードを「単数」に設定することです。
これでスプライトを扱えるようになります。

デフォルトで「単数」に設定する方法

デフォルトで「単数」に設定する方法はkanさんがまとめていただいています。

kan-kikuchi.hatenablog.com

おわりに

スプライトモードを「複数」にして使用したことがないので調べてみると、
画像1枚に複数のスプライトがまとまっている時は「複数」に設定して切り出すようです。

この記事がお役に立てましたら幸いです。

【Unity】URP カメラのポストプロセスをスクリプトからオンオフする方法

要件

Unity 6000.0.26f1

はじめに

カメラコンポーネントのポストプロセスのチェックボックス切替えを
スクリプトから操作するメモです。

今回切替えたいのはこちらの項目

サンプルスクリプト

using UnityEngine;
using UnityEngine.Rendering.Universal;

public class AAA : MonoBehaviour
{ 
    private void Start()
    {
        UniversalAdditionalCameraData additionalCameraData = Camera.main.GetComponent<UniversalAdditionalCameraData>();
        
        //オフにする場合
        additionalCameraData.renderPostProcessing = false;

        //オンにする場合
        additionalCameraData.renderPostProcessing = true;        
    }
    
}

カメラはUniversalAdditionalCameraDataというコンポーネントで拡張されているらしく、 Cameraコンポーネントではなく、UniversalAdditionalCameraDataコンポーネントを使用する必要があります。

参考

docs.unity3d.com

【Unity】Steam向け macOS 多言語化設定 ビルド時にInfo.plistへLocalizationsを設定する方法

要件

Unity 6000.0.26f1
Localization 1.5.3
Xcode 15.4

はじめに

Steam向けにUnityでmacOSアプリを制作しており、
ビルド後に実行しても主要言語が切り替わらないという問題が起きました。

原因と対策を書きます。

原因

Info.plistに多言語化の設定がないことが原因でした。

Xcodeでいうところのinfo>Localizationsの箇所です。

対策

ビルド時に自動で多言語化の設定を追加します。

Editorという名前のフォルダを作成し、下記のスクリプトをフォルダ内に入れてください。

Unityからビルドして.appもしくは.xcodeprojファイルを生成する際に、
どちらの形式でも設定できるようにしています。

using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode;
using System.IO;
using UnityEngine;

/// <summary>
/// mac向けビルド「.app」と「.xcodeproj」における
/// info.plist に言語設定を追加するスクリプト
/// </summary>
public class AddLocalizationPostBuild
{
    [PostProcessBuild(999)]//実行順序を最後にする
    public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
    {
        // macOS ビルドでない場合は処理をスキップ
        if (target != BuildTarget.StandaloneOSX) return;

        string plistPath = "";

        // macOS .app ビルドの場合
        // .appの場合のInfo.plistへのパスは、xxx.app/Contents/Info.plist になる
        plistPath = Path.Combine(pathToBuiltProject, "Contents", "Info.plist");
     
        
        // macOS .app で Info.plist が存在するか確認
        if (!File.Exists(plistPath))
        {
            // Xcode ビルドの場合は上記のパスは存在しないため、プロジェクト名を取得して Info.plist のパスを再設定
            
            //plistPathを初期化
            plistPath = "";
            
            //プロジェクト名
            string productName = PlayerSettings.productName;
            
            // .xcodeproj の場合の Info.plist へのパスは、xxx.xcodeproj/プロジェクト名/Info.plist になる
            plistPath = Path.Combine(pathToBuiltProject, productName, "Info.plist");
            
            if (!File.Exists(plistPath))
            {
                Debug.LogError($"❌ Info.plist が見つかりません: {plistPath}");
                return;
            }
        }

        // Info.plist を読み込んで編集
        PlistDocument plist = new PlistDocument();
        plist.ReadFromString(File.ReadAllText(plistPath));

        // CFBundleLocalizations のキーを追加
        PlistElementArray localizations;
        if (plist.root.values.ContainsKey("CFBundleLocalizations"))
        {
            localizations = plist.root["CFBundleLocalizations"].AsArray();
        }
        else
        {
            localizations = plist.root.CreateArray("CFBundleLocalizations");
        }

        // 言語を追加
        AddLocalizationIfNotExists(localizations, "en"); // 英語
        AddLocalizationIfNotExists(localizations, "ja"); // 日本語

        // 変更した内容を保存
        File.WriteAllText(plistPath, plist.WriteToString());
        Debug.Log($"✅ Info.plist に CFBundleLocalizations を追加しました: {plistPath}");
    }

    // 言語がすでに存在していなければ追加
    private static void AddLocalizationIfNotExists(PlistElementArray array, string lang)
    {
        foreach (PlistElement elem in array.values)
        {
            if (elem.AsString() == lang)
                return;
        }
        array.AddString(lang);
    }
}


上記サンプルの対応言語は英語と日本語のみです。
言語を追加する場合は、下記の要領で言語を追加してください。

        // 言語を追加
        AddLocalizationIfNotExists(localizations, "en"); // 英語
        AddLocalizationIfNotExists(localizations, "ja"); // 日本語

おわりに

ChatGPTに聞いてもmacOS向けでXcodeを使用する場合の内容は
見当違いな回答が多く、少し苦戦しました。
お役に立てれば幸いです。

【Unity】Steam ビルドデータのアップデート方法 macOS Windows

はじめに

過去記事で初めてビルドデータをアップロードする手順を書いています。

marumaro7.hatenablog.com

今回はデータをアップロードする手順になります。

1.デポの設定

最初にデポの設定を行っていきます。

1-1.デポの新規作成

→「Steamworks設定を編集」を押します。


→「SteamPipe」タブ
→「デポ」


→「新しいデポを追加」


作成するデポに対して名前の入力とデポIDの選択を求められます。
デポの名前:
 Windows用とわかるようにしたいので
 「自分のアプリ名 Win バージョン情報」としておきます。
デポID :
 デフォルトのままで問題ありません。


macOS用にもデポを作成したいため続けてもう一度「新しいデポを追加」を押して作成します。
デポの名前:
 macOS用とわかるようにしたいので
 「自分のアプリ名 Mac バージョン情報」としておきます。
デポID :
 デフォルトのままで問題ありません。


その後、オペレーティングシステム
WindowsMacへそれぞれ変えます。
「保存」をお忘れなく!

1-2.デポの追加

アプリ管理画面まで戻り、「関連する全てのパッケージ、DLC、体験版、ツール」を押します。


ストアパッケージのパッケージタイトルの欄が押せるのでクリック


「デポの追加/削除」を押します。


先程作成したデポが表示されているはずです。
両方を追加して保存します。


「含まれるデポ」に新規作成したデポが追加されました。


デポの追加が必要なのは今の画面だけではなくあと2箇所あります。
1つ前の画面に戻って、今実施したデポの追加を「プロモーションあるいは特殊パッケージ」の
2つのパッケージに対しても実施します。


1-3.デポの公開

デポに対してビルドデータのアップロードを行うのですが、
今までの設定を「公開」しないとアップロードができません。

ここからはそのための手順になります。

→アプリ管理画面
→「Steamworks設定を編集」


→「公開」タブ
→「公開の準備」


→「Steamに公開」ボタンが出現するので押す。


→確認コードを入力しろと言われるので説明文の通りに確認コードを入力
→「本当に公開する」
※未リリースの場合はリリースされるわけではないのでご安心を。

これでビルドデータをアップロードする準備ができました。

2.ビルドデータアップロード

ビルドデータのアップロードは2種類あります。
・Zipファイル(最大 2048MB)をSteamに直接アップロードする
・Steamworks SDK 経由でアップロードする

今回は過去記事と同様にZipファイルを直接アップロードする方法を実施します。

2-1. Zipファイルアップロード

アップロードするページへ移動します。
→「SteamPipe」タブ 
→「ビルド」
→「こちら」


アップロードするページにこれました。


Windows向けのビルドをアップロードします。
Unityでビルドして出来上がったフォルダをまるごと圧縮してください。
そのファイルを「ファイルを選択」より選んで「アップロード」を押します。
その後、「アップロード」ボタンだった箇所がゲージに変化し、アップロードの進捗がわかります。


アップロード完了後、下にメモ欄が出現します。
メモ欄にバージョン情報など 後から見た時に区別がつくような内容を記入して「Commit」を押します。


macOSの方も続けてアップロードします。

Xcodeで公証済みの.appファイルをZip化してアップロードします。 公証済みの.appファイルの作り方はこちらです。 marumaro7.hatenablog.com

操作画面を更新してから「ファイル選択」→「アップロード」します。
(操作画面を更新せずアップロードしたところうまくいきませんでした。)

アップロード完了後、下にメモ欄が出現します。
メモ欄にバージョン情報など 後から見た時に区別がつくような内容を記入して
「Commit」を押します。


2-2.ビルドの有効化

アップロードしたビルドデータを有効にしていきます。
→「SteamPipe」タブの「ビルド」
→Win用のビルドデータに対して
 「ブランチ用にビルドをライブに設定 ...」の項目を「default」に設定
→「変更をプレビュー」


→「今すぐビルドをライブに設定」


確認のウインドウが出現するため「OK」を押します。


これを行うことで「過去のWindows向け」と
「過去のmacOS向け」、「今回のWindows向け」の内容が一つに統合されます。
(色々試しましたが、新バージョンのみをdefaultにする方法がわかりませんでした。)


macOS用も同様の手順でdefaultに設定します。
新旧のビルドデータが合体したまとまりができていると思います。

3.起動ファイルの指定

起動するファイルがどのファイルなのかを指定します。

→「インストール」タブ
→インストール全般

前回設定時から変更があれば更新しておきます。

4.公開

「公開」タブから
「公開の準備」〜「本当に公開する」を押します。


5.含まれるデポの設定変更

新旧のデポが合体した状態なので不要なデポは対象外にします。

アプリ管理画面まで戻り、「関連する全てのパッケージ、DLC、体験版、ツール」を押します。


ストアパッケージのパッケージタイトルの欄が押せるのでクリック


「デポの追加/削除」を押します。


古いビルドデータが割り当てられているデポのチェックを外します。


これでダウンロードサイズが少なくなるはずなので
古いデータはインストールされないようになっていることがわかります。


デポの設定変更が必要なのは今の画面だけではなくあと2箇所あります。
1つ前の画面に戻って、今実施したデポの追加を「プロモーションあるいは特殊パッケージ」の
2つのパッケージに対しても実施します。

以上で完了です。

おわりに

古いビルドデータのデポと新しいビルドデータのデポが
合体してしまうところがおかしい気がしています。
もっと良いやり方があれば教えていただきたいです。

【Steam】ビルド審査での指摘事項 メモ

はじめに

Steam向けへアプリリリースに向けて
ビルドデータを審査に提出した結果、不合格となりました。

いくつか指摘事項をいただいたのでメモしておきます。

指摘1 知的財産権(IP)の使用許可の提示

提出したアプリはVRoid Studioの配布キャラクターやVRoid Studioで自作したVRMモデルを含んでいる内容です。
それらに対し、使用許可のライセンスの提示を求められました。

配布キャラクターについては、利用規約のURLをレビュー依頼分に添付。
自作キャラクターについては、自作の証明としてキャラクターを編集している様子をスクリーンショットしてGoogle Driveに証拠画像を保存、レビュー依頼分にGoogle DriveのURLを貼り付けました。

指摘2 アプリ内で言語選択オプションが見つからない

自動で言語が切り替わるようにしていましたが、
アプリ内で言語切り替えできるようにした方が良いようです。

指摘3 スクリーンショット・PVとのアプリ内容不一致

スクリーンショット・PVはVRoid Hubからアプリ実行中にインポートしたモデルを採用しており、アプリ自体には含まれていませんでした。

外部からダウンロードされたもの である場合、「このモデルはインポートしたモデルであり、アプリには含まれません」といった文言を追加する必要があるようです。