[Unity3D] 子類組件怎么無損替換父組件

今天筆者給大家?guī)硪粋€非常實(shí)用的無損(無感)替換父組件解決方案欢峰。可以避免繼承的子類組件替換原有組件時可能導(dǎo)致的數(shù)據(jù)丟失,或者繁瑣的恢復(fù)通用設(shè)置的操作。

寫在前面:

前段時間想要做本地化卜范,采用了繼承了 Text 組件,相較于新增一個專門用于標(biāo)識的腳本鹿榜,優(yōu)點(diǎn)是游戲?qū)ο笊峡梢陨賿煲粋€腳本海雪,但是問題來了,怎么無損的替換掉原有組件而不丟失數(shù)據(jù)呢舱殿?

解決方案:

在這里筆者收羅了2個解決方案:

  1. Unity UGUI 本地化方案 - Localiztion Tool - Zero - CSDN博客
    此工具的基本原理就是將Text控件的FileID和GUID換成LocaliztionText控件的FileID和GUID奥裸。 (基本就是一個文本級別的操作) ←作者原話
  2. ButtonEx
    額,別看命名是 Button 啥的怀薛,其實(shí)它就是我要重點(diǎn)講的第二個解決方案刺彩,內(nèi)容可引起極度舒適。枝恋。

實(shí)現(xiàn)原理:

ButtonEx 的作者對 Unity 編輯器的理解相當(dāng)?shù)纳羁檀淳蟆?shí)現(xiàn)原理雖然和第一個解決方案一模一樣。但他用到了Unity 自帶的序列化解決方案焚碌。因?yàn)椴灰蕾囉谖谋酒枞粒阅軌蛑С侄M(jìn)制格式的預(yù)制體,也就無需強(qiáng)制轉(zhuǎn)Scene十电、Prefab 為文本文件了(當(dāng)然知押,使用第三方版本管理就不說了)。
上面提到的Unity Native解決方案究竟是個什么鬼鹃骂,又為什么說跟第一個解決方案原理一樣呢台盯?
答案就是編輯器模式下,每個資源都有一個編輯器層面的對象與之對應(yīng)畏线。也就是說每一個腳本都有一個 MonoScript 對象與之對應(yīng)著静盅,記錄著這個腳本的 FileId 和 GUID .而這個對象信息也會序列化持久保存在組件的 “m_Script” 字段中,也就是第一個解決方案作者提到的規(guī)律:


只不過 ButtonEx 的作者從上游出發(fā)寝殴,使用 ButtonEx 腳本資源在編輯器下的代言人:MonoScript 對象替換了原來的 Button組件的 MonoScript 對象從而實(shí)現(xiàn)了無損+無感的組件替換體驗(yàn)蒿叠。
現(xiàn)在,該明白為什么說他們原理一樣了吧:> 都是對 m_Script 字段進(jìn)行了更新蚣常。<

核心代碼:

        /// <summary>
        /// Convert to the specified component.
        /// </summary>
        protected static void ConvertTo<T>(Object context) where T : MonoBehaviour
        {
            var target = context as MonoBehaviour;
            var so = new SerializedObject(target);
            so.Update();

            bool oldEnable = target.enabled;
            target.enabled = false;

            // Find MonoScript of the specified component.
            foreach (var script in Resources.FindObjectsOfTypeAll<MonoScript>())
            {
                if (script.GetClass() != typeof(T))
                    continue;

                // Set 'm_Script' to convert.
                so.FindProperty("m_Script").objectReferenceValue = script;
                so.ApplyModifiedProperties();
                break;
            }

            (so.targetObject as MonoBehaviour).enabled = oldEnable;
        }

是不是超級簡單呀市咽!
真的是一波操作猛如虎,回頭一看Native 抵蚊,真香施绎!

動畫演示:


Tips:

  • 開篇嘮的是 本地化啊 ,Text 啊贞绳,但是通篇 ButtonEx 谷醉!好吧,給個 TextEx 的無損/無感切換的動畫演示算是首位呼應(yīng)咯熔酷。
  • 動畫中孤紧,筆者演示了瘋狂修改各種屬性,然后來回切換組件的無感/無損體驗(yàn)拒秘。

演示代碼:

using UnityEngine;
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
[CustomEditor(typeof(TextEx))]
public class TextExEditor : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
    }
}
#endif
public class TextEx : Text
{
    public string m_key;
#if UNITY_EDITOR
    [MenuItem("CONTEXT/Text/Convert To TextEx", true)]
    static bool _ConvertToButtonEx(MenuCommand command)
    {
        return CanConvertTo<TextEx>(command.context);
    }
    [MenuItem("CONTEXT/Text/Convert To TextEx", false)]
    static void ConvertToButtonEx(MenuCommand command)
    {
        ConvertTo<TextEx>(command.context);
    }
    [MenuItem("CONTEXT/Text/Convert To Text", true)]
    static bool _ConvertToButton(MenuCommand command)
    {
        return CanConvertTo<Text>(command.context);
    }
    [MenuItem("CONTEXT/Text/Convert To Text", false)]
    static void ConvertToButton(MenuCommand command)
    {
        ConvertTo<Text>(command.context);
    }
    protected static bool CanConvertTo<T>(Object context)
        where T : MonoBehaviour
    {
        return context && context.GetType() != typeof(T);
    }
    protected static void ConvertTo<T>(Object context) where T : MonoBehaviour
    {
        var target = context as MonoBehaviour;
        var so = new SerializedObject(target);
        so.Update();
        bool oldEnable = target.enabled;
        target.enabled = false;
        foreach (var script in Resources.FindObjectsOfTypeAll<MonoScript>())
        {
            if (script.GetClass() != typeof(T))continue;
            so.FindProperty("m_Script").objectReferenceValue = script;
            so.ApplyModifiedProperties();
            break;
        }
        (so.targetObject as MonoBehaviour).enabled = oldEnable;
    }
#endif
}

友情提示:

  • 由于子組件是父組件的功能擴(kuò)展号显,必定會新增字段啥的,父組件替換子組件會導(dǎo)致子組件定制化的序列化數(shù)據(jù)丟失躺酒。故筆者并不推薦父組件反過來替換子組件(自嗨另算)押蚤。
  • 每一個運(yùn)行的Unity 組件基本上都有一個 Editor腳本與之對應(yīng)用于繪制Inspector,在UGUI組件中羹应,Text / Image 這些的Editor 腳本是繼承GraphicEditor類型的揽碘,而 Button/Toggle/DropDown這些組件因?yàn)槔^承了 Selection,所以他們的 Editor腳本是繼承的 SelectionEditor。
  • 隨著版本更新上述SelectionEditor已經(jīng)作古雳刺,同時上述 TextEx 演示代碼的重寫 OnInspectorGui方法劫灶,Inspector布局也變樣了,如果沒強(qiáng)迫癥的還可以玩玩掖桦。

寫的最后:

簡單的筆記本昏,也希望對讀者有所幫助吧!
當(dāng)然枪汪,還有大把擴(kuò)展的余地涌穆,譬如為之創(chuàng)建具有 EditorWindow 的自動化工作流。雀久。冰啃。

擴(kuò)展閱讀:

Unity的 MonoScripts - 嘿嘿 - CSDN博客
QFramework

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末剂桥,一起剝皮案震驚了整個濱河市妻柒,隨后出現(xiàn)的幾起案子封恰,更是在濱河造成了極大的恐慌,老刑警劉巖巡蘸,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奋隶,死亡現(xiàn)場離奇詭異,居然都是意外死亡悦荒,警方通過查閱死者的電腦和手機(jī)唯欣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來搬味,“玉大人境氢,你說我怎么就攤上這事∨鑫常” “怎么了萍聊?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長悦析。 經(jīng)常有香客問我寿桨,道長,這世上最難降的妖魔是什么强戴? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任亭螟,我火速辦了婚禮,結(jié)果婚禮上骑歹,老公的妹妹穿的比我還像新娘预烙。我一直安慰自己,他們只是感情好道媚,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布扁掸。 她就那樣靜靜地躺著翘县,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谴分。 梳的紋絲不亂的頭發(fā)上锈麸,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天,我揣著相機(jī)與錄音狸剃,去河邊找鬼掐隐。 笑死狗热,一個胖子當(dāng)著我的面吹牛钞馁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播匿刮,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼僧凰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了熟丸?” 一聲冷哼從身側(cè)響起训措,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎光羞,沒想到半個月后绩鸣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡纱兑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年呀闻,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片潜慎。...
    茶點(diǎn)故事閱讀 38,683評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡捡多,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出铐炫,到底是詐尸還是另有隱情垒手,我是刑警寧澤,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布倒信,位于F島的核電站科贬,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏鳖悠。R本人自食惡果不足惜榜掌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望竞穷。 院中可真熱鬧唐责,春花似錦、人聲如沸瘾带。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至朴恳,卻和暖如春抄罕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背于颖。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工呆贿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人森渐。 一個月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓做入,卻偏偏與公主長得像,于是被迫代替她去往敵國和親同衣。 傳聞我的和親對象是個殘疾皇子竟块,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評論 2 349

推薦閱讀更多精彩內(nèi)容