御幸備忘録

主にUnityに関してのブログです。

Unity Hubで「Adding modules」が表示されなくなった時の解決法

はじめに

 Unity Hubで新たにモデュールを追加しようとしても、「Adding modules」が表示されず困ったときの解決法です。恐らく以下が原因です。

  • Unity Hub以外からUnity Editorをインストールした。
  • ローカルにあったUnity EditorをUnity Hubに登録した。
  • 以前使っていたUnity EditorをUnity Hubに登録した。

※書き方が違うだけで、肝なのはUnity Hubを経由せずインストールしたことです。

一度Unity Editorを削除して再びUnity Hub経由でインストールしてもいいですが、時間がかかるためそれ以外の解決をします。

解決方法

Unity EditorをフォルダーごとUnity Hubで選択したフォルダーに移動する

Windowsを例に説明すると

1. 「Remove from Hub」を選択して、Unity EditorをUnity Hubから削除します。

2. 以下の場所に

C:\Program Files\Unity\Editor\Unity.exe

 にインストールされているUnity EditorをUnityフォルダーごと

C:\Program Files\Unity\Hub\Editor

 このHubフォルダー以下に移動させます。

3. この後、再度Unity EditorをUnity Hubに登録します


これで「Adding modules」が表示されるようになったはずです。

Unity Hub 3.0.0を試す

Unity Hub 3.0.0について

 少し前(7月8日)からUnity HubのBeta版がリリースされているようです。現在は3.0.0-beta.4が最新版です。

Unity Hub 3.0.0のインストール

 Unity Hub 3.0.0をインストールするには、Unity HubのSettingを開きAdvancedからRelease ChannelをBetaに切り替える必要があります。(Unityのダウンロードページから直接ダウンロードすることはできません)

 既にUnity Hubを利用している前提で進めますが、まだインストールされてない方はこちらからどうぞ。

f:id:MiyukiFueda:20210926223422p:plain

Release ChannelをAdvancedに切り替えます

 Betaに切り替えると、上部にHub 3.0.0-beta.4 Availableと表示されるので、クリックします。「Restart Now and Install」をクリックし、再度Unityが開くまで待ちます。(Windowsの警告やファイアウォールの許可が表示された場合は、適宜対応してください)

f:id:MiyukiFueda:20210926224845p:plain

Restart Now and Installを選択します

 Unity Hubが3.0.0に更新されると、以下の画面に変わっています。この画像ではプロジェクトがありませんが、既にプロジェクトがある場合はここに表示されます。もしもアカウントのサインインやUnity本体のインストールがまだの場合、先に案内が表示されます。

f:id:MiyukiFueda:20210926230420p:plain

Unity Hub 3.0.0-beta.4

Unity Hub 3.0.0の設定を変更する

Unity起動時にUnity Hubを自動で隠す

 新規プロジェクトの作成やプロジェクトを選択した後に、自動でUnity Hubを閉じてトレイに常駐することが出来るようになりました。(どうせUnity Editorで隠れるからいいよっていうのはありますが、)基本的にはこの設定はオンがお勧めです。

f:id:MiyukiFueda:20210926232913p:plain

Unity起動時、Unity Hubをトレイに隠す

チャンネルを戻す

 3.0.0を試したいだけだったので、ChannelをProductionに戻しました。3.0.1以降でうっかりベータ版を更新しないためです。もし2.4.5に戻したい場合は、この後再インストールすることができます。

f:id:MiyukiFueda:20210926234023p:plain

Release ChannelをProductionに切り替える

ウィンドウの色を変えたい

 リリースノートによると、現在はダークモードのみ提供されています。今後のアップデートでライトモードも追加されるようです。

リンク

forum.unity.com

unity3d.com

Unityのシーン遷移は遅くない

はじめに

Unityを使ってるとシーン遷移が遅いってよく聞くので調べてみました。
Time.realtimeSinceStartupでシーン遷移前と後の時間を計ってるだけです。

検証

何もないシーンをSceneManager.LoadSceneで読み込んだ場合

カメラ以外のオブジェクトがないシーンを2つ用意します。(Scene0、Scene1と名付けました)
スクリプトはカメラにアタッチします。

f:id:miyukifueda5:20190329054207p:plain
Scene0
// Scene0.cs
// 最初に呼び出されるシーンです
// ここから他のシーンを呼び出します
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;

public class Scene0 : MonoBehaviour
{
    IEnumerator Start()
    {
        // Unityが安定するまで10秒待つ
        yield return new WaitForSeconds(10);

        SceneManager.LoadScene("Scene1");
        
        Timer.startLoadScene = Time.realtimeSinceStartup;
    }
}
f:id:miyukifueda5:20190329054514p:plain
Scene1
// Scene1.cs
// 何も無いシーンです
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;

public class Scene1 : MonoBehaviour
{
    IEnumerator Start()
    {
        Timer.endLoadScene = Time.realtimeSinceStartup;

        float time = Timer.endLoadScene - Timer.startLoadScene;
        Debug.Log($"Scene1の読み込み時間は{time}秒です。 ");
    }
}

[出力結果]
Scene1の読み込み時間は0.07846355秒です。

Cubeが10000個あるシーンをSceneManager.LoadSceneで読み込んだ場合

新たにScene2を作りCubeを複製して10000個作ります。

f:id:miyukifueda5:20190329055815p:plain
Scene2

ソースコードは先程のをちょっと書き換えるだけなので省略します。

[出力結果]
Scene2の読み込み時間は2.428547秒です。

感想

2秒以上かかりかなり遅いです。 何もないシーンとCube10000個あるとシーンだとかかる時間が全然違う。 シーン遷移が重いというより、オブジェクト読み込みに時間がかかっている(広義的にはそれもシーン遷移だけど(笑))
実際のゲームでは3Dモデルとか画像とかのアセットが大量に読み込まれるので、それが原因だと思う。

追加検証

Cubeが10000個あるシーンをSceneManager.LoadSceneAsyncで読み込んだ場合

気になったので、追加で調べてみた。
SceneManager.LoadSceneAsyncで非同期にシーンを読み込んだ後、シーン遷移単体にはどのくらい時間がかかってるのかを測定。 先程のScene0とScene2を流用します。 Scene0.csは非同期処理に合わせて時間の取り方を修正。 Scene2.csは変更なし。

// Scene0.cs
// 最初に呼び出されるシーンです
// ここから他のシーンを呼び出します
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;

public class Scene0 : MonoBehaviour
{
    IEnumerator Start()
    {
        // Unityが安定するまで10秒待つ
        yield return new WaitForSeconds(10);

        //SceneManager.LoadScene("Scene2");
        AsyncOperation asyncOperation = SceneManager.LoadSceneAsync("Scene2");
        
        // シーンのロードが終わるまで待機
        while(!asyncOperation.isDone)
        {
            // ループ毎に時間を取ります
            Timer.startLoadScene = Time.realtimeSinceStartup;
            yield return null;
        }
    }
}

[出力結果]
Scene2の読み込み時間は0.5203323秒です。

感想

最初の検証と同じ時間になると思ったけど、結構差が開いた。 オブジェクトが多いとシーンの読み込みが終わってても遷移でごたつく? それでも2番めの検証の5分の1くらいの時間になってるから効果は大きい。
実際に使う時にはLoadSceneMode.Additiveで追加読み込みにしたりやAwakeでゲームオブジェクト全体を非アクティブにするような工夫が必要だと思う。

終わりに

以前から気になってたけど、ようやく調べられた。
シーン遷移を嫌って1シーンでゲームを完結させるプロジェクトに携わったことがあるけど、シーン分けて作る方法を模索した方がいいと思うんですよね。(途中のシーンから再生できないとか動作の確認大変なので)
次は1シーンだけで作る場合と普通にシーン分ける場合の比較記事各予定です。予定なので守らないかもしれないけど。

【Unity】マルチシーンにしたときに警告が出たので調べてみた

はじめに

SceneManager.LoadSceneAsync()でマルチシーン(複数シーンを同時に開いた状態)にしたとき、以下の警告が出たので調べてみた。

Your multi-scene setup may be improved by tending to the following issues:
Multiple scenes baked with Auto enabled can appear differently in Play mode when reloading them. Consider disabling Auto and rebaking.
f:id:miyukifueda5:20190310200519p:plain

環境

Unity 2018.3.7f1

解決

マルチスクリーン周りが原因なのは分かるけど、そんなこと言われてもどこを直せばいいか分からない。
いろいろ調べてたら

原因 調べてみるとLightingのエラーでした。 Lightingの設定をAuto Generateにしていると新しくシーンがロードされるたびにライトがベイクされるようで、「複数のシーンをロードすると、シーンごとに自動設定した光の当たり方と異なるかもしれないけど大丈夫か?」という警告のようです。

【Unity2018】マルチシーンを使うと"Your multi-scene setup may be improved by tending to the following issues"というエラーが出た - ぱふの自由帳

という記事をを見つけたので解決!と思ったけどLighting設定がどこか分からずもう少し探すことに…
Window > Rendering > Lighting Settingsの後、開いたWindowの一番下のAuto Generateのチェックボックスをオフにする。

f:id:miyukifueda5:20190312014146p:plain
Window > Rendering > Lighting Settingsを選択
f:id:miyukifueda5:20190312020620p:plain
一番下のAuto Generateのチェックボックスを外す

終わりに

最初、原因が全然分からないから時間かかった。
もう少し警告文が分かりやすければ早かったかな。
同じとこで詰まった人がすぐ見つけられるように、キーワード多めに入れたつもりだから参考になればと願う。

参考

ぱふの自由帳
http://pafu-of-duck.hatenablog.com/http://pafu-of-duck.hatenablog.com/entry/2018/11/18/000022

Unity公式 Lighting ウインドウ
https://docs.unity3d.com/ja/2018.2/Manual/GlobalIllumination.html

【Unity】エディタ拡張で全プレハブからRigidbodyを削除する機能を作ってみた【C#】

はじめに

Unity4からUnity2018にアップデートする過程で100個以上あるPrefabからRigidbodyを外さなければなかったので作った。
ToolsからRemove Conponents From Prefabを選べば使えます。
Rigidbodyを書き換えれば他のコンポーネントにも対応できます。

ソース

using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

class RemoveConponentsFromAllPrefab : MonoBehaviour
{
    private static IEnumerator m_iEnumerator = null;

    [MenuItem("Tools/Remove Conponents From All Prefab")]
    static private void StartRemove()
    {
        var prefabs = GetPrefabs();

        foreach (var p in prefabs)
        {
            // StartCoroutineがnon staticで使えないため、MoveNext()を使用
            m_iEnumerator = RemoveConponentsFromPrefab(p);
            m_iEnumerator.MoveNext();
        }
    }

    static private List<GameObject> GetPrefabs()
    {
        Debug.Log("Prefabの取得");
        string directoryPath = "Assets";
        List<GameObject> assets = new List<GameObject>();

        // Asset以下の全ファイルを取得
        string[] filePathes = Directory.GetFiles(directoryPath, "*", SearchOption.AllDirectories);

        foreach (var filePath in filePathes)
        {
            // Prefabファイルのみ処理を行う
            if (filePath.Contains(".prefab") && !filePath.Contains(".meta"))
            {
                GameObject asset = AssetDatabase.LoadAssetAtPath<GameObject>(filePath);
                Debug.Log("Loaded " + filePath);
                if (asset != null)
                {
                    assets.Add(asset);
                }
            }
        }

        return assets;
    }

    static private IEnumerator RemoveConponentsFromPrefab(GameObject prefab)
    {
        // 非アクティブなオブジェクトのコンポーネントを取得するため引数にtrue
        var components = prefab.GetComponentsInChildren<Rigidbody>(true);

        if (components.Length > 0)
        {
            Debug.Log("Destroy " +components[0].name+ " in " +prefab.name);
            foreach (var c in components)
            {
                // Destroyでは即時反映されないためDestroyImmediateを使用
                DestroyImmediate(c, true);
            }

            var go = Instantiate(prefab);

            //待機処理
            while (go == null)
            {
                yield return null;
            }

            go = PrefabUtility.ConnectGameObjectToPrefab(go, prefab);

            Debug.Log("Replace " + prefab.name + " with " + go.name);
            PrefabUtility.ReplacePrefab(go, prefab, ReplacePrefabOptions.ConnectToPrefab);

            Debug.Log("Destroy " +go.name);
            DestroyImmediate(go, true);
        }
    }
}

あとがき

StartCorutine()ではなくMoveNext()を使った方法やPrefabUtility等、学ぶ事が多かった。
もう少し使いやすさを上げてRigitbody以外にも対応させたい。
Unity2018.2では問題ないが、Unity2018.3ではPrefabUtilityが旧形式と警告されているので後々対応したい。

参考

StartCoroutine(MonoBehaviour)を使わずにコルーチンを実行する【Unity】【エディタ拡張】
http://kan-kikuchi.hatenablog.com/entry/Coroutine_Editor

【Unity】【エディタ拡張】スクリプトからPrefabを操作する(Unity2018.2まで版)
http://light11.hatenadiary.com/entry/2018/12/19/220554

InputFieldから絵文字を除く方法

はじめに

InputField内に絵文字があると自動で取り除くスクリプトを作成しました。

絵文字とありますが、厳密にはサロゲート文字か判定してるだけなので全ての絵文字に対応してるわけではありません。

副次的に漢字の異字体等、他のサロゲートペアを使ったものにも対応してたりします。

スクリプト

using UnityEngine;
using UnityEngine.UI;

public class InputFieldController : MonoBehaviour
{
    [SerializeField] private InputField inputField = null;

    void Start()
    {
        inputField.onValueChanged.AddListener(delegate { OnValueChange(inputField); }); 
    }

    private void Reset()
    {
        inputField = GetComponent<InputField>();
    }

    private void OnValueChange(InputField inputField)
    {
        string str = string.Empty;

        foreach (var c in inputField.text)
        {
            if (!char.IsSurrogate(c))
            {
                str += c;
            }
        }

        inputField.text = str;
    }
}

使い方

上記をコピペcsファイルを作ってオブジェクトにアタッチするだけです。後はReset()が勝手にやってくれます。
後からInputFieldをアタッチした場合は歯車(設定)からResetを押すか手動でアタッチします。

終わりに

このスクリプトは、サーバ側に合わせてクライアント側から絵文字を入力・送信できなくする対応の過程で作りました。
絵文字そのものの対応は難しかったですが、サロゲート文字を除外することで取り敢えず解決したかなってとこです。