1. 程式人生 > >【Unity3D基礎教程】給初學者看的Unity教程(七):在Unity中構建健壯的單例模式(Singleton)

【Unity3D基礎教程】給初學者看的Unity教程(七):在Unity中構建健壯的單例模式(Singleton)

hh

該部落格中的程式碼均出自我的開源專案 : 迷你微信

為什麼需要單例模式

遊戲中需要單例有以下幾個原因:

  • 我們需要在遊戲開始前和結束前做一些操作,比如網路的連結和斷開,資源的載入和解除安裝,我們一般會把這部分邏輯放在單例裡。
  • 單例可以控制初始化和銷燬順序,而靜態變數和場景中的GameObject都無法控制自己的建立和銷燬順序,這樣就會造成很多潛在的問題。
  • Unity3D的GameObject需要動態建立。而不是固定在場景裡,我們需要使用單例來建立GameObject。
  • Unity3D的場景中的各個GameObject需要從單例中存取資料。

單例的設計原則

在設計單例的時候,我並不建議採取延遲初始化的方案,正如雲風所說:

對於單件的處理,採用靜態物件和惰性初始化的方案,簡直就是 C++ 程式設計師的陋習。Double Checked Locking is broken,相信很多人都讀過了。過於依賴語法糖,通常就會造成這種結果。其實讓程式有明顯的初始化和退出階段,是很容易被規劃出來的。把單件(singleton) 的處理放在正確的時機,以正確的次序來處理並非難事。

我們應該在程式某處明確定義單例是否被初始化,在初始化執行完畢後再執行正常的遊戲邏輯

  • 儘量避免多執行緒建立單例帶來的複雜性
  • 在某處定義了一定的初始化順序後,可以在遊戲結束的時候按照相反的順序銷燬這些單例

設計單例的基類

在Unity中,我們需要一個基類來為所有單例的操作提供統一的介面,同時,我們還要讓所有單例繼承MonoBehaviour,只有這樣才能讓單例自由使用協程這一特性。

基類設計如下,程式碼連結

using System;
using UnityEngine;

namespace MiniWeChat
{
    [RequireComponent(typeof(GameRoot))]
    public class Singleton<T> : MonoBehaviour where T : Singleton<T>
    {
        private static T _instance;

        public static T GetInstance()
        {
            return _instance;
        }

        public void SetInstance(T t)
        {
            if (_instance == null)
            {
                _instance = t;
            }
        }

        public virtual void Init()
        {
            return;
        }

        public virtual void Release()
        {
            return;
        }
    }
}

設計單例的管理類

除了設計基類之外, 還需要設計一個讓所有基類初始化和銷燬的類,我們把這個類叫做GameRoot,並且把它繫結在一個名為GameRoot的GameObject上,並且把這個GameObject放在遊戲進入的Main場景中。

GameRoot類設計如下,程式碼連結

namespace MiniWeChat
{
    public class GameRoot : MonoBehaviour
    {
        private static GameObject _rootObj;

        private static List<Action> _singletonReleaseList = new List<Action>();

        public void Awake()
        {
            _rootObj = gameObject;
            GameObject.DontDestroyOnLoad(_rootObj);
            
            StartCoroutine(InitSingletons());
        }

        /// <summary>
        /// 在這裡進行所有單例的銷燬
        /// </summary>
        public void OnApplicationQuit()
        {
            for (int i = _singletonReleaseList.Count - 1; i >= 0; i--)
            {
                _singletonReleaseList[i]();
            }
        }

        /// <summary>
        /// 在這裡進行所有單例的初始化
        /// </summary>
        /// <returns></returns>
        private IEnumerator InitSingletons()
        {
            yield return null;
            // Init Singletons
        }

        private static void AddSingleton<T>() where T : Singleton<T>
        {
            if (_rootObj.GetComponent<T>() == null)
            {
                T t = _rootObj.AddComponent<T>();
                t.SetInstance(t);
                t.Init();

                _singletonReleaseList.Add(delegate()
                {
                    t.Release();
                });
            }
        }

        public static T GetSingleton<T>() where T : Singleton<T>
        {
            T t = _rootObj.GetComponent<T>();

            if (t == null)
            {
                AddSingleton<T>();
            }

            return t;
        }
    }
}

如何拓展新的單例

有了以上兩個類之後,當我們需要新建立一個類的時候,就可以繼承Singleton<T>來建立新的單例,重寫Init和Release方法,同時在GameRoot的InitSingleton方法的適當順序執行AddSingleton<T>方法即可。具體的使用可以參考該類程式碼連結

相關推薦

Unity3D基礎教程初學者Unity教程如何學習Unity3D

cos 詳解 component lock index unity3d遊戲 design 技術棧 log 【Unity3D基礎教程】給初學者看的Unity教程(零):如何學習Unity3D http://www.cnblogs.com/neverdie/p/How_To_

Unity3D基礎教程初學者Unity教程理解Unity的新GUI系統UGUI

理解UGUI的基礎架構 UGUI是Unity在4.6中引入的新的GUI系統,與傳統的中介軟體NGUI相比,這套新GUI系統有幾個核心亮點: 放棄了Atlas的概念,使用Packing Tag的方式來進行圖集的規劃 放棄了depth來確定UI顯示層級的概念,使用Hierarchy的SiblingIndex

Unity3D基礎教程初學者Unity教程所有指令碼元件的基類 -- MonoBehaviour的前世今生

引子 上一次我們講了GameObject,Compoent,Time,Input,Physics,其中Time,Input,Physics都是Unity中的全域性變數。GameObject是遊戲中的基本物件。GameObject是由Component組合而成的,GameObject本身必須有

Unity3D基礎教程初學者Unity教程詳解Unity3D的協程Coroutine

為什麼需要協程 在遊戲中有許多過程(Process)需要花費多個邏輯幀去計算。 你會遇到“密集”的流程,比如說尋路,尋路計算量非常大,所以我們通常會把它分割到不同的邏輯幀去進行計算,以免影響遊戲的幀率。 你會遇到“稀疏”的流程,比如說遊戲中的觸發器,這種觸發器大多數時候什麼也不做,但

Unity3D基礎教程初學者Unity教程通過製作Flappy Bird瞭解Native 2D的Sprite,Animation

引子 上一次我們講了MonoBehaviour的前世今生,瞭解了遊戲中的每一個GameObjec都是由指令碼控制的,這一次我們開始將Unity中Native 2D中的Sprite,並且使用Animation來讓Sprite動起來。 在接下來的幾篇部落格裡,我會通過做一個Flappy Bird來講解

Unity3D基礎教程初學者Unity教程通過製作Flappy Bird瞭解Native 2D的RigidBody2D和Collider2D

引子 認識RigidBody 當RigidBody2D的質量屬性被設定為0時,剛體的質量變為無限大,此時剛體相當於靜態剛體,永遠一動不動。但是在Unity中你是無法把一個RigidBody2D的質量設定為0的,所以,當你想建立一個靜態剛體時,只需要建立碰撞器,而不需要建立RigidBo

Unity3D基礎教程初學者Unity教程Unity構建健壯模式Singleton

該部落格中的程式碼均出自我的開源專案 : 迷你微信 為什麼需要單例模式 遊戲中需要單例有以下幾個原因: 我們需要在遊戲開始前和結束前做一些操作,比如網路的連結和斷開,資源的載入和解除安裝,我們一般會把這部分邏輯放在單例裡。 單例可以控制初始化和銷燬順序,而靜態變數和場景中的GameObject都無法控制

Unity3D基礎教程初學者Unity教程GameObject,Compoent,Time,Input,Physics

Unity3D重要模組的類圖 最近剛剛完成了一個我個人比較滿意的小專案:【深入Cocos2d-x】使用MVC架構搭建遊戲Four,在這個遊戲中,我使用了自己搭建的MVC架構來製作一個遊戲,做到了比較好的SoC(關注點分離)。但是苦於Cocos2d-x沒有一個比較完善的編輯器,所以我開始學習另一個非常流行

7.13模式Singleton的用法和用處以及破解

vol 創建者模式 code private let .get span test loaded 1):用處   是一種創建者模式,只生成一個實例對象,具有全局唯一性,當一個對象的產生需要比較多的資源時, 如讀取配置(如數據庫連接池、Spring中, 一個Compone

C#設計模式之一模式Singleton Pattern創建型

nal 設計 類庫 開發 避免 sum behavior 並且 負責 原文:C#設計模式之一單例模式(Singleton Pattern)【創建型】一、引言 看了李建忠老師的講的設計模式已經有一段時間了(這段時間大概有一年多了),自己還沒有寫過自己的、有關設計模

android開發學習 ------- android模式 詳解

lan post tail -- and 使用 href details android開發 https://blog.csdn.net/u011418943/article/details/60139644 這篇文章 前因後果 都說出來了 ,值得學習。 htt

設計模式模式Singleton

思想 保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。 類圖 Singleton 類稱為單例類,該類的建構函式是 Private 的,這是為了禁止從 Singleton 類的外部呼叫建構函式,這就堵死了外界利用 new 建立此類的可能。通過 getInstance 方

wif 系列C#之模式Singleton最佳實踐

com value 快捷 lock 詳細介紹 筆記本 改進 奇怪 我不知道 目錄 介紹 第一個版本 ——不是線程安全的 第二個版本 —— 簡單的線程安全 第三個版本 - 使用雙重檢查鎖定嘗試線程安全 第四個版本 - 不太懶,不使用鎖且線程安全 第五版 - 完全懶惰的實例化

JS 設計模式 模式Singleton來封裝對資料的增刪除改查

單例模式單例模式的核心結構中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統中一個類只有一個例項單例模式最初的定義出現於《設計模式》(艾迪生維斯理, 1994):“保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。”單例模式定義:“一個類有且僅有一個例項,並且自行

設計模式—-1模式建立型

概念:  java中單例模式是一種常見的設計模式,單例模式的寫法有好幾種,這裡主要介紹三種:懶漢式單例、餓漢式單例、登記式單例。  單例模式有以下特點:  1、單例類只能有一個例項。  2、單例類必須自己建立自己的唯一例項。  3、單例類必須給所有其他物件提供這一例項。 

J2EE學習如何正確地寫出模式

單例模式算是設計模式中最容易理解,也是最容易手寫程式碼的模式了吧。但是其中的坑卻不少,所以也常作為面試題來考。本文主要對幾種單例寫法的整理,並分析其優缺點。很多都是一些老生常談的問題,但如果你不知道如何建立一個執行緒安全的單例,不知道什麼是雙檢鎖,那這篇文章可能會幫助到你。

Python基礎8python的特性進階篇迭代,列表生成式,生成器,迭代器

python中還包括一些高階特性,以下簡單介紹。 迭代 定義:用for迴圈來遍歷物件的過程,叫做迭代。 作用物件:可迭代物件 如何判斷是否為可迭代物件:isinstance(xxx,Iterable),Iterable型別來源於collections模組。 應用場景: 1

小白的Java教程第二十六章,可勝列舉列舉

###列舉的誕生歷史(瞭解) 在服裝行業,衣服的分類根據性別可以表示為三種情況:男裝、女裝、中性服裝。 private ? type; public void setType(? type){ this.type = type } 需求:定義一個變數來表

翻譯初學者的 Neural Networks / 神經網路 介紹

在這篇文章中,我會向大家簡要的介紹下 Neural Networks / 神經網路; 可以作為 Machine Learning / 機器學習 和 Deep Learning / 深度學習 的入門愛好者參考; 我們文章中會盡量用簡短的,零基礎的方式來向大家介紹。 作為 Black Box /

Unity3d基礎Unity換裝系統(2)

using UnityEngine; using System.Collections; using System.Collections.Generic; public class CombineMesh : MonoBehaviour { void OnGUI() { i