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

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

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

// Copyright (c) 2021 Hiroyuki Kako
// This software is released under the MIT License, see LICENSE.

#if UNITY_EDITOR
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 class RaycastDefaultRemoverInPrefabView : EditorWindow
{
    private static List<Graphic> _tempPrefabGraphics = new List<Graphic>();

    private static PrefabStage _recentPrefab;
    private static GameObject _instance;
    private static bool _isActive;

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


    [MenuItem("KEditorExtensions/RaycastDefaultRemoverInPrefabView")]
    private static void Open()
    {
        GetWindow<RaycastDefaultRemoverInPrefabView>("Toggle");
    }

    private void OnGUI()
    {
        using (new GUILayout.HorizontalScope())
        {
            _isActive = EditorGUILayout.Toggle("Use RaycastDefaultRemoverInPrefabView", _isActive);
        }
    }

    private static void OnHierarchyChanged()
    {
        if (!_isActive) return;
        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);
        }
    }
}
#endif


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するようにしました。