Unity 遊戲框架搭建 2019 (四十二、四十三) MonoBehaviour 簡化 & 定時功能

MonoBehaviour 簡化

在前兩篇,我們完成了第九個示例。為了完善第九個示例,我們複習了類的繼承,又學習了泛型和 params 關鍵字。

我們已經接觸了類的繼承了。接觸繼承之前,把類僅僅當做是方法的集合,接觸了繼承之後,我們的類還可以使用繼承來解決一些問題。

第十個示例

在 Unity 中,我們的腳本都往往繼承自 MonoBehaviour,繼承了之後我們就可以在腳本內編寫很多功能。比如訪問 transform/gameObject,再比如控制動畫接收碰撞事件等等。另外我們繼承了 MonoBehaviour 才能被作為腳本掛到 GameObject 上。

僅僅是通過繼承,MonoBehaviour 的很多功能都能夠進行復用。所以繼承的一個作用就是代碼復用。而我們知道方法也可以代碼復用,泛型可以對結構進行復用。那麼繼承能是復用什麼?

繼承既能復用代碼也能復用結構。不過術業有專攻,有的情況下使用方法進行復用更合理,有的情況下適用於泛型,當然也有適用繼承的情況。

像 GameObjectSimplify 和 TransformSimplify,這兩種方法集,目前其實通過繼承來實現會更好一點。因為這兩個類中的方法全部都是要傳一個固定的對象進去的,比如 GameObjectSimiplify 的每個方法第一個參數都是 GameObject 參數,而 TransformSimplify 也是如此。他們使用起來也不是很方便。

使用代碼如下:

GameObjectSimplify.Show(gameObject);
TriansformSimplify.Identity(transform);

可以看出都需要把所有的類名字全部打出來,而使用繼承就會好很多。

我們先實現第十個示例代碼,如下

MonoBehaviourSimplify.cs

using UnityEngine;

namespace QFramework
{    
    public partial class MonoBehaviourSimplify : MonoBehaviour
    {
        public void Show()
        {
            GameObjectSimplify.Show(gameObject);
        }

        public void Hide()
        {
            GameObjectSimplify.Hide(gameObject);
        }

        public void Identity()
        {
            TransformSimplify.Identity(transform);
        }
    }
    
    public class Hide : MonoBehaviourSimplify
    {        
        private void Awake()
        {
            Hide();
        }
        
#if UNITY_EDITOR
        [UnityEditor.MenuItem("QFramework/10.MonoBehaviour 簡化", false, 11)]
        static void MenuClicked()
        {
            UnityEditor.EditorApplication.isPlaying = true;
            
            var gameObj = new GameObject("Hide");
            gameObj.AddComponent<Hide>();
        }
#endif
    }
}

MonoBehaviourSimplify 為了可以在之後的示例中進行擴展,所以加上了 partial 關鍵字。而其中的 Show、Hide 等方法這次沒有使用 static 關鍵字,那麼這種方法叫做成員方法。成員方法必須通過對象來調用。而有 static 關鍵字的叫做靜態方法,靜態方法必須通過類來調用。

示例就是代碼中的 Hide 腳本。

而 MenuItem 中有一行代碼:

UnityEditor.EditorApplication.isPlaying = true;

這行代碼執行之後,UnityEditor 就會自動運行。

其他的都很簡單,MenuItem 執行之後如下所示:
006tNc79gy1fzfsg3oncxj30ls0b475d.jpg

示例是正確的。

OK,這個示例就完成了。

菜單如下:
006tNc79gy1fzfsg7lffdj30hk0dqwle.jpg

目錄結構如下:
006tNc79gy1fzfsgddemfj30eo0b675s.jpg

今天的內容就這些,我們接觸了繼承之後,又強化了一次繼承的使用,這樣我們之後每次寫示例的時候會有很多設計工具選擇。

定時功能

在上一篇我們完成了 MonoBehaviour 的簡化示例,通過做這個示例,強化了一次繼承的使用。
而為了讓示例腳本自動運行,就接觸了 EditorApplication.isPlaying 這個 API,有了這個 API 我們之後所有需要運行 UnityEditor 的腳本都可以按照這種格式去做。

今天我們再接着往下學習。

第十一個示例

我們都知道,在項目中,我們會遇到非常多的定時需求。而定時功能在 Unity 中最容易實現的方式是通過 Coroutine(協程)實現。在這個示例中我們實現一個簡單的定時工具。

在實現在哪裡呢?

我們目前有兩個選擇:

  • 一是寫一個工具類,比如 TimerUtil 或者 DelayUtil,或者乾脆卸載 CommonUtil 里。
  • 二是實現到 MonoBehaviourSimplify 里。

考慮到,執行協程是需要通過 MonoBehaviour 啟動的,所以方法在 MonoBehaviourSimplify 中定義更好一點。而實現的部分需要定義一個協程方法。這個協程方法並不希望被子類或者外部類調用,所以這個協程方法應該使用 private 權限。

實現之後的示例代碼如下:

using System;
using System.Collections;
using UnityEngine;

namespace QFramework
{
    public partial class MonoBehaviourSimplify
    {
        public void Delay(float seconds, Action onFinished)
        {
            StartCoroutine(DelayCoroutine(seconds, onFinished));
        }
        
        private static IEnumerator DelayCoroutine(float seconds, Action onFinished)
        {
            yield return new WaitForSeconds(seconds);

            onFinished();
        }
    }

    public class DelayWithCoroutine : MonoBehaviourSimplify
    {
        private void Start()
        {
            Delay(5.0f, () =>
            {
                UnityEditor.EditorApplication.isPlaying = false;
            });
        }

#if UNITY_EDITOR
        [UnityEditor.MenuItem("QFramework/11.定時功能", false, 11)]
        private static void MenuClickd()
        {
            UnityEditor.EditorApplication.isPlaying = true;

            new GameObject("DelayWithCoroutine")
                .AddComponent<DelayWithCoroutine>();
        }
#endif
    }
}

以上代碼中,大家可能對 Action 比較陌生。Action 其實是 C# 自定義的委託。
定義如下:

namespace System
{
	public delegate void Action();
}

至於委託是什麼…,理解成動態方法就好了,在初期呢,我們用它來做回調函數。

還有這樣的一個寫法也可能比較陌生: () => { } ,這種寫法叫做 lambda 表達式,相當於實現了一個沒有名字的方法。詳細的使用方法可以自己用搜索引擎查一下,這裡筆者只要能看懂以上代碼就行。當然在以後的文章中會非常深入地講 委託、lambda 表達式在庫/框架中的使用的。

示例代碼執行之後,如下:
DraggedImage.aba351c681524dfab0a1f5b8f01ff01f.png
過了五秒後,UnityEditor 運行會自動停止。
如下:

DraggedImage.dcb427502b394946810177e994b3f3ae.png

結果是正確的。

這篇文章的示例就寫完了。

菜單欄如下:
006tNc79gy1fzfsh7n2yrj308r07ujtj.jpg

文件目錄如下:
006tNc79gy1fzfshacdguj30f60bytab.jpg

我們可以進行一次導出了。

我們一篇文章再見,拜拜~

轉載請註明地址:涼鞋的筆記:liangxiegame.com

更多內容