Kakoのいろいろやったこと記

主にUnity関連でやったことをかいていきます

Gitでこれだけあれば大丈夫なやーつの記事

この記事は何か

Gitを初めて使う際の、コマンド(今回はGUIなので言葉自体の事)について、使い方がわからないと聞いたので「怖くないよプルプル▽」というために書いた記事。

言葉の説明のみ。

目次

実際の言葉

怖くない言葉
  • チェックアウト

  もうすでにコピーを持っているときに、他の人(過去の自分含む)がした作業をコピーしてきて使えるようにしたりする

  • クローン

  初めて使うときなどに、完コピを持ってくるときに使う

  • 新規ブランチを作る

  ブランチ、というものが「作業の分岐ルート」で、新しく分岐させたいときにする行動。機能ごとだったり、作業の塊ごとにする

  • コミット

  こんな変更をしたよ、と説明文と一緒に記録することができる。1ヶ月分の月報だと読みづらいけど、日毎の日報だと少し追いやすいよね、1時間ごとのログは過度だよね、って感じで、そこそこ細かく、でもある程度まとめてやると、後で便利。後々、他の人も見られることがあるので、ポエムを書いたり下ネタを書くととても楽しいことが起こるので注意

  • スタッシュ

  チェックアウトしたかったりするとき、でも一旦今の内容を保存しておきたい……なんてときに使う。チェックアウトするっていっても、今の作業どうするの……?ってかわいいPCくんは聞いてくれる。今の作業内容を一旦避難させることができる

  • スクワッシュ

  コミットが細かくなりすぎたり、ちょっとした変更が生じてコミットが増えちゃったとき、押しつぶして一つにまとめることができる

気をつけたい言葉
  • プッシュ

  これで全てが決まると言っても過言。プッシュをすると、Localじゃなくて他の人が見られる状態になる。変なコミットを消すなら今のうち(これの前)

  • リベース

  今作業している内容と、他の人の作業の内容を揃える行為。Pushしなければ他の人に影響はないといえば、ない。全体の作業の本流が、今の作業の根っこより先にいるときに、揃える行為。たまにコンフリクトというのが起きる。このとき、Fixするのにコミットが細かすぎると怠かったりする

  • マージ

何かしらのコミット(ブランチ)を、他の何かの上塗りに使う行為。完成した、チェックが終わった更新をマージしていくことで、本流が最新になっていく。ある程度組織になってる時は、内容を把握してる人がやる行為

 

その他

語弊を恐れず簡単のための書き方をしています。ggる必要があるかなないかな、くらいの判断にどうぞ。不明点はおきがっるに!

香川ゆるもく会にいってきましたFrom岡山

香川ゆるもくって?

sanuki-gamen.jimdofree.com
こちらです

本編感想

きつすぎずゆるすぎず最高でした。
なお、公式Twitterめちゃくちゃ熱がこもったやり取りをしているときの自分たちが映っています( ゚д゚ )


まずゆるめなもくもく会をするのですが、ある程度、もちろん空気を読みながら相談をしたり、技術的な共有も行われていて、良い場だなぁと思いました。
初学者向けの場をセッティングする場合、コーディングメインか、Component理解メインか、の相談を受けたりしました。教えていた経験をめっさ活かして答えられた、と思いたいです。

とあるチームが、ゲームの案を出したりしていて、とても楽しそうだなぁと見ていました。

最後に、成果発表をしたりするのですが、自分は実は今、

こちらの制作をお手伝いしており、これの成果を発表したりしました。作ってて楽しい最高プロダクト!
リリースの際は、是非!

他の方々は、いろんなアイディアが固まった方々だったり、Go言語だったり、様々でした。

カレー

なんと、主催の方がカレーを振る舞いつつの懇親会、みたいなものがありました!!!
めちゃくちゃうまかったですが、本来より数時間遅れての開催となりました。

新プロジェクトの相談

有り体にかくと「ビジネス」に近い話でしたが、ビビり散らかす程度には本格的なお話をしました。在職中もこんなに熱込めた話、少なかったです。
6時間くらい話していたと思います。やばい。
途中で、流石に腹が減った的に、カレーを食べました。めちゃくちゃ美味しかった。

逃げていった終電

そう、お察しの方はいるかもしれないですが、イベント終わってから6時間も話をしていたら、体力枯れるし、なんなら終電?そんなのもうないよってなりました。
ご厚意で、開催会場たるゲストハウスに泊めていただきました……!!!!これまたビビり散らかすほどおしゃれで最高空間でした。はやく喧伝しまくりたい(度をわきまえて)。

アフタートーク

参加者の方と、アフタートークをして、気づけば2時とかでした。楽しすぎる。
Assetの話だったり、技術的な話もしつつ、交流しまくった感じでした。もはやマブ

総括

地方イベントとか関係なく、やる気は存在するし、最高は存在する。再確認できる最高のイベントでした。
積極的にイベントも開催されたりしているので、近いし、香川、日程合う限りマストで行こうと思いました。




ん?家から?2時間くらいですね。

Unityのプロジェクト内で、Componentや自作クラスの参照を見つけるScriptを書きました。

何がしたいか

コンポーネントの参照をプロジェクト全体から見つけて、問題になっている箇所を見つけたかったので、参照を検索、というのがしたかった。具体的にはHorizontalLayoutGroupが見つけたかった。

結論 : ある

wiki.unity3d.com

でも作った

最近こういうの好きなので参考にしながら作りました。
github.com

f:id:Kakovail:20200309170535p:plainf:id:Kakovail:20200309170540p:plainf:id:Kakovail:20200309170545p:plain

Script

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

public class ReferenceFinder : EditorWindow
{
    private string _targetComponentName;
    private List<GameObject> _foundAssets = new List<GameObject>();
    private Vector2 _currentScrollPosition;
    private static IEnumerable<Type> _cashedComponents;
    private static Dictionary<string, List<Type>> _typeDict;

    static MonoScript[] _monoScripts;

    private static bool _isFirstTime = true;

    //開かれ方と、開かれたときの挙動
    [MenuItem("ReferenceFinder/Search")]
    private static void Open()
    {
        //開かれる際には一応取得
        _cashedComponents = GetAllTypes();
        GetWindow<ReferenceFinder>("Components Reference Finder.");
    }

    private void OnGUI()
    {
        //Editorに枠を出して、入力を_targetComponentNameに格納する
        EditorGUILayout.BeginHorizontal();
        _targetComponentName =
            EditorGUILayout.TextField("Target Component Name: ", _targetComponentName);
        EditorGUILayout.EndHorizontal();

        if (_foundAssets.Count > 0)
        {
            _currentScrollPosition = EditorGUILayout.BeginScrollView(_currentScrollPosition);
            foreach (var asset in _foundAssets)
            {
                EditorGUILayout.ObjectField(asset.name, asset, typeof(GameObject), false);
            }

            EditorGUILayout.EndScrollView();
        }

        if (GUILayout.Button("Search"))
        {
            _foundAssets.Clear();

            var guids = AssetDatabase.FindAssets("t:GameObject", null);


            foreach (var guid in guids)
            {
                string path = AssetDatabase.GUIDToAssetPath(guid);
                var loadAsset = AssetDatabase.LoadAssetAtPath<GameObject>(path);
                var typeCash = GetType(_targetComponentName) ?? null;

                if (typeCash == null)
                {
                    Debug.Log("No Type Found.");
                    return;
                }

                var tmp = loadAsset.GetComponentsInChildren(GetType(_targetComponentName) ?? null);

                foreach (var kari in tmp)
                {
                    _foundAssets.Add(kari.gameObject);
                }
            }
        }
    }


    /// <summary>
    /// プロジェクト内に存在する全スクリプトファイル
    /// </summary>
    static MonoScript[] MonoScripts
    {
        get { return _monoScripts ?? (_monoScripts = Resources.FindObjectsOfTypeAll<MonoScript>().ToArray()); }
    }

    /// <summary>
    /// クラス名からタイプを取得する
    /// </summary>
    private static Type GetType(string className)
    {
        if (_typeDict == null)
        {
            // Dictionary作成
            _typeDict = new Dictionary<string, List<Type>>();
            foreach (var type in _cashedComponents)
            {
                if (!_typeDict.ContainsKey(type.Name))
                {
                    _typeDict.Add(type.Name, new List<Type>());
                }

                _typeDict[type.Name].Add(type);
            }
        }

        //クラスが存在する場合、リストに表示
        if (_typeDict.ContainsKey(className))
        {
            return _typeDict[className][0];
        }
        else
        {
            //クラスが存在しない場合、念の為取得、再走
            if (_isFirstTime)
            {
                Debug.Log("Not found. ReScanning...");
                _cashedComponents = GetAllTypes();
                _isFirstTime = false;
                GetType(className);
            }

            _isFirstTime = true;

            return null;
        }
    }

    /// <summary>
    /// 全てのクラスタイプを取得
    /// </summary>
    private static IEnumerable<Type> GetAllTypes()
    {
        //Unity標準のクラスタイプを取得する
        var types = AppDomain.CurrentDomain.GetAssemblies()
            .SelectMany(asm => asm.GetTypes())
            .Where(type => type != null && !string.IsNullOrEmpty(type.Namespace))
            .Where(type => type.Namespace.Contains("UnityEngine"));

        //自作クラスも取得できるように
        var localTypes = MonoScripts
            .Where(script => script != null)
            .Select(script => script.GetClass())
            .Where(classType => classType != null)
            .Where(classType => classType.Module.Name == "Assembly-CSharp.dll");

        return types.Concat(localTypes).Distinct();
    }
}

エディタ拡張(?)楽しい

気軽にできてハック感あるのですごく達成感あります。よだれ鶏くらいの簡単さと充実感。

Unityのアンチパターンの記:Script編:第一部

対象

ゲームをなんとか自力で作れそうな段階。

なぜ書こうと思ったか

今まで本やチュートリアルをなぞってこなかったので、考えや知識の間違いを確認したいことと、初学者の身としてはアンチパターンを知っていきたい、という気持ちがあるので、どっかのなんかの誰かのためになるかな、と思ったことによる。

内容

見たことのあるちょっと良くなさそうなもので初期に改善できそうなものを突っ込んで、実際に改造してみる。
自作自演まさかり。

前提

  • 動作に関わるもの
  • 書きやすさ、読みやすさを主とした好みに関わるもの

を書きます。命名規則「自体」はスルーします。人によるので!

また、間違いがあったらすぐに直しますので、ご指摘いただけると幸いです。

PlayerAntiScript

数字が、良くない番号です。

using UnityEngine;

public class PlayerAntiScript : MonoBehaviour
{
    //1
    private const int Tsuyosa = 5;

    //2
    public Rigidbody Rigidbody => GetComponent<Rigidbody>();

    //3
    private int _hp = default;


    //4
    private GameObject _enemy;

    //5
    private void Start()
    {
    }


    private void Update()
    {
        //4,6
        _enemy = FindObjectOfType<EnemyScript>().gameObject;

        //7
        if (Input.GetMouseButton(0))
        {
            //2,8,9
            Rigidbody.AddForce(transform.forward * 30);
        }
    }

    private void OnCollisionEnter(Collision other)
    {
        //10
        if (other.gameObject.TryGetComponent<EnemyScript>(out var result))
        {
            //11
            result.GetComponent<EnemyScript>().Hp--;
            if (result.GetComponent<EnemyScript>().Hp < 1)
            {
                Destroy(result);
            }
        }
    }

    //1,3,4,12
    private int MaxEnemyNum = 30;
}

直してみたPlayer

using UnityEngine;

public class Player : MonoBehaviour
{
    //使ってないけど修正参考で上に出しておいた感じです
    static readonly int MaxEnemyNum = 30;

    private const int PlayerPower = 1;
    static readonly float Acceleration = 30f;

    private Rigidbody _rigidbody;

    private void Start()
    {
        _rigidbody = GetComponent<Rigidbody>();
    }

    private void FixedUpdate()
    {
        if (!Input.GetMouseButton(0)) return;

        _rigidbody.AddForce(transform.forward * Acceleration);
    }

    private void OnCollisionEnter(Collision other)
    {
        if (!other.gameObject.TryGetComponent<EnemyScript>(out var result)) return;

        //ここでは意味が無いけれどboolを返したら便利そう。名前が長いのは実はやばいけど全容が無いので第一部ではご容赦
        var isAlive = result.AddDamageAndCheckIsAlive(PlayerPower);
    }
}

説明

動作に関わるもの

1 : 後々変わりそうな数字でconstは警戒

constについて、詳しくは調べて頂いたらいいかな、と思いますが、簡単に書くと「進め方によっては数字を変更した際にバグる」です。
constは、事前に組み込まれるのでとても軽い部類なのですが、事前に組み込まれるがゆえに、以前組み込んだ数字のまま動くことがある、という現象があります。
なので「将来的に、まだ調整しそうな定数にしたい数値」はstatic readonly などを使ってあげると、気にしなくて良くなります。
最終的に、完全に確定した際には心置きなくconstを使う、のがいいと思います。

2 : 実質毎フレーム取得と不要なpublic

この宣言の仕方はとても便利なのですが、呼ばれ得る度に取得しているので、Updateで使うと実質毎回参照を取ります。大変です。

また、publicは割と怖くて、他のクラス、オブジェクトからも操作できてしまう、という問題があります。
「それの何が悪いの?気にしときゃいいじゃん」って思うかもしれませんが、例えば3つのオブジェクトが参照、変更をかけている時、同時に変更がかかったりしたらどうなるでしょう?やばいです。
実際、既存の有名Asset等でも、これで競合しちゃってUnityエディタがフリーズする、というのが発生することがあります(特にRefresh系)。
少なくとも手元では、その状況をそもそも発生させないためにも、不要なpublicを消すのが好ましいかな、と。
なので、不要な場合には、無しか、privateにしてあげましょう。

4 : 取得する形と違う必要性をなくせそうだし、これ使ってない……?

6で取得していますが、取得→gameObjectに変換、としていますが、だったらEnemyScriptの型で宣言しちゃってもいいのかな、と。
そもそも使ってないし(説明のために書いたんですけどね)。
仮にgameObject経由で取ってきたい情報があるなら、EnemyScriptの中で取得、こっちに公開して流したり。
もうちょっと進むとInterface切り分けとかも出てきそうな感じありますね。

6 : 毎フレームFindは重い!

この言葉のみです。重い!キャッシュする、とか言いますが、一度取得、どこかにしまっておく、いわゆるキャッシュをすることで、不要な参照を避けられ、軽くなります。これは変更後のRigidbodyの部分でやっています。

8 : AddForceってなんだろう?Updateで使わないように

AddForceといえば「FixedUpdateで使おう」とかよく言われます。なんでなんでしょうか?
これは、UnityのPhisics系が、基本FixedUpdateの時間の流れ方(フレーム間の幅)を単位として動いてくれるので、なにも気にしなくても時間という単位に関して解決してくれるためです。
docs.unity3d.com

Updateで使うなら明示的に時間を管理する必要があったりなかったりするので、そもそもFixedUpdateを使う、とすると幸せになれます。
詳しくやると運動方程式とかをちょっとだけやることになります。

10 : これだと消せないかも?

resultに対して取得したものが入っているんですが、今回はEnemyScriptが入っています。これだと、GameObject自体は消せないので、下のほうにあるDestroyがうまくきかないんじゃないかな?ってなりますね。
もちろん、将棋みたいに、やられたら敵という属性がなくなる、とかなら使いみちはあると思います。

11 : 他人が他人の体力をいじれるの、ちょっと怖い

2とも関連します。公開されている数値は、公開の仕方によっては、他人が直接いじることができます。
あくまでも相手にダメージを通知して、相手自身がダメージを処理結果だけ返したりする、というのが平和ではないでしょうか。
また、ここではPlayerだけがいじっていますが、他の要因、ダメージ床もある、フレンドリーファイアもある、などとなった場合にどんどん変な事になっていきます。
最初のうちは、なるべくなら動作する本人が処理する、のが平和に思えます。

個人的な好み

3 : 名前が変?

命名規則の種類の話ではなく、Script内での名前の規則性がなくて混乱する、というやつです。結構見ます。
Camelがどうとかいうのではなく、最低限内部では揃っていたほうがやりやすいのかな?と思います。

5 : 使わないなら消したい

これだけです。テンプレートを変えない場合、基本出てくるので、残っているのをよく見かけますが、使わないなら消したほうがいいのかなぁ、と思います。
ただ、今回は改造後で使っています。

7 : 早期リターンなんてものもあったり

これは好みですが、条件が1つしかなかったりする場合は、早期リターン、ガード節というのがあります。これもうまくいかない要因を排除できたり、ほんの僅かに軽くなったりがあるっぽいので好きでおすすめです。もちろん場合によります。
そして、今回は段階的に無視しましたが、FixedUpdateでキー入力をみるの、なんか危なかったり、なかったり。

9 : この30はまほうのすうじ

この数字、一体なんの数字で何に使っているんだろう?というのがわかりません。
こういった、なにかよくわからないけど動く魔法のような数字マジックナンバーと呼びます。どこかで宣言、名前を持ってくることで混乱が防げますね。

12 : 貴様……なぜここに……?

これは、シンプルに書く場所に意図がなさそうなのもよく見かけるもので……!
あとはですね、Playerがなぜ敵の数を管理する必要があるのか、というのもちょっと突っ込めるかもです。やること多すぎて大変なので、敵のボス的なScriptで管理するのも良いんじゃないでしょうか?


終わりに

セルフまさかり、心が痛いですね。ちょっと疲れたときに息抜きとして続けたいと思います。

PhotonでPrivateChatの小さいことに躓いて時間が溶けたから、それらを他の人はできるようになる備忘

この記事について

お仕事でいじっていて、プライベートチャットで躓いたこと2点と対処法を書きました。わからないことがあれば聞いていただけると追記します。

躓いたことと解決法

TargetId

doc.photonengine.com
これや、Referenceを参考にしたのですが、TargetUserIdってのが意味わかんなかったです。
自分の環境では、
{UserID}:{UserName}
がくっついたものが、相手のPrivateChatのIdでした……。そういう記述見つけられなかった……。
適当にPriavteChat送ったら、自分も受信するので、OnPrivateMessageでSenderをDebug.Logしてあげて形式を整えましょう

ChatClientの勘違い

ChatClientを自前実装しようとしてたんですが、
ChatClient.{呼びたいもの}でいけるんですね……

疑問点あったら何でも投げてください

めちゃくちゃつまづきまくったので、一通り心当たりがある気がします。気軽に投げてみてください(わからないこともたくさんあるので)。

Iwate.Unityに参加しました。Okayamaから。

何があったの?

iwateunity.connpass.com

Iwate.Unityというイベントがありました。もちろん岩手で!
参加しよう!と思いすぐに申し込みました。
なんならLTもしてやんよ……!と思い、しました。しましたとも。えぇ。

この記事の概要

技術的なものではなく、シンプルブログです!ご了承ください。

LTの内容

PDF化する際にだいぶ書き換えていますが、大体こんな内容でLTをしました。

www.slideshare.net
イラストでご協力頂いた皆様、圧倒的感謝……!

岡山to岩手

私は、岡山に住んでいるのです。会場は岩手です。
地図でいうとこんな感じです(会場は盛岡でした)。
f:id:Kakovail:20200304204640p:plain

なぜ参加したか?

楽しそうだったから

私は、人生を「たのしい」「おもしろい」を中心にしています。
「地方を盛り上げる、という取り組みが好きだし面白い!」
「岡山から行ったらなんか面白いんじゃね?」
「ちょうどLTしたかったし最高に楽しそう」
というのが理由でした。

気概が好きだったから

地方を盛り上げる、という考え方や、運営さんのブログを拝見して、とても良かったんです。
amidamangrove.hatenablog.com

これは、行くしか無い、と思いました。

岩手?ゆーて群馬くらいやろと思っていたから

東京に住んでると、岡山と香川の距離とか、あんまわからない人いません?
兵庫なんて岡山から行けるの?みたいな。
えぇ、私はそれでした。岩手?ゆーて群馬ぐらいやろ!!と。

感想

最高でした。
初めて学習する方もいらっしゃったり、意欲あふれる場でしたし、
主催の方と知り合えたのも個人的にとても大きかったです。
影響を受けて、ポテンシャルがガンガン上げられて、とても良い行動だった、と評価できます。
岩手の場所もわかりましたし……。
なお、次回も日程を無理矢理にでも合わせて参加したいと思っています。岡山から。

最後に

簡単にですが、以前参加した話を記事にしました。なんならWIPです。
勉強会、みんな、軽率に行こうぜ。俺はOkinawaもいけそうならいくんだ……!

Prefab編集画面でUIを追加した際にRaycastTargetをデフォルトでオフにするScriptを書きました


 f:id:Kakovail:20200304182118g:plain



注意
2020-03-04時点、
Prefab にUIを追加、次の操作で自分自身を再度開く、とするとOnになることを確認しました
やらないとは思いますが念の為。また、改善次第反映します。

追記
数点、拡張性のあるPresetの存在を教えていただきました……!
こちらに参考としてリンクいたします!ScriptでEvemnt以外はオフにしているのを、手動でコンポーネントごとに設定できる感じです!!
私のScriptは、少し書き換えれば、移行してきたプロジェクトの当たり判定を消したりできる、というのはメリットかな、と……!

speakerdeck.com


baba-s.hatenablog.com

Script

using System.Collections.Generic;
using UnityEditor;
using UnityEditor.Experimental.SceneManagement;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using static UnityEditor.Experimental.SceneManagement.PrefabStageUtility;

public static class RaycastDefaultRemoverInPrefabView
{
    private static List<Graphic> _tempPrefabGraphics = new List<Graphic>();

    private static PrefabStage _recentPrefab;
    private static GameObject _instance;

    [InitializeOnLoadMethod]
    private static void Initialize()
    {
        EditorApplication.hierarchyChanged += OnHierarchyChanged;
    }

    private static void OnHierarchyChanged()
    {
        if (Application.isPlaying) return;
        var tmpCurrentStageId = GetCurrentPrefabStage();
        if (tmpCurrentStageId == null) return;


        if (_recentPrefab == null || _recentPrefab != tmpCurrentStageId || _instance == null)
        {
            _recentPrefab = tmpCurrentStageId;
            _instance = tmpCurrentStageId.prefabContentsRoot;
            Debug.Log("this may new or different from current opened prefab. load next.");
            AddGraphicComponent();
            return;
        }

        var currentGraphic = _instance.GetComponentsInChildren<Graphic>();

        foreach (var tmp in currentGraphic)
        {
            if (_tempPrefabGraphics.Contains(tmp)) continue;
            Debug.Log($"{tmp.name} is new Object");
            tmp.raycastTarget = tmp.GetComponent<IEventSystemHandler>() != null;
        }

        AddGraphicComponent();
    }

    private static void AddGraphicComponent()
    {
        var tmpList = _instance.GetComponentsInChildren<Graphic>();
        _tempPrefabGraphics = new List<Graphic>();
        foreach (var content in tmpList)
        {
            _tempPrefabGraphics.Add(content);
        }
    }
}


github.com

使い方

RayCastDefaultRemoverInPrefabView.csをプロジェクトに配置!
大体どこでも大丈夫です。

これはなに?

UIを配置するときに、デザイナーさんと分業したりすることもあると思うんですが、RaycastTargetがOnになっているせいでめちゃくちゃに時間溶かしたり、オフにしなきゃって意識することでストレスが溜まったりするので、オフにしたいな、と思って書きました。すでにありそうでしたが、ぐぐラビティたりなかったので見つけられなく、書きました。
ボタンやスライダー等の、イベントがあるものはついたままになります。

参考

baba-s.hatenablog.com
dev.twsiyuan.com

流れ

上記サイト様、Scriptを参考したのですが、Prefab Viewに対応してない(と思います。Onのままだったので)みたいだったので、Prefab編集画面のみで動くものを参考にしながら書きました。

仕組み

 [InitializeOnLoadMethod] 

こいつで毎回初期化するんだと思います。

EditorApplication.hierarchyChanged += OnHierarchyChanged;

これでイベントを登録する、的な感じです。hierarchyChangedっていう出来事に対して、やってほしい処理を入れてる、くらいの感覚です。

GetCurrentPrefabStage();

また、これでPrefabのID的なものが取れるので、これで同一かをチェックします。

foreach (var tmp in currentGraphic)
{
    if (_tempPrefabGraphics.Contains(tmp)) continue;
    Debug.Log($"{tmp.name} is new Object");
    tmp.raycastTarget = tmp.GetComponent<IEventSystemHandler>() != null;
}

さっきまで観測していたものを格納していって、更新があった場合、Event系が入っているかどうかでDisableにします。すでに設置してあるものは無視されます。

結果

ストレスめっちゃ減りました。
ただ、明示的にオンにするのを意識しないともちろんあかんです。
また、処理的にも少し軽くなるっぽいです!

更新

2020-03-04 20時
Prefabが相違な際によろしくなさそうなのでLoadしたPrefabが違う可能性がある場合にSKIPするようにしました。