游戲開發(fā)學(xué)習(xí)筆記


14.Unity游戲開發(fā)中的生命周期

時間:2017/12/5
主題:經(jīng)驗(yàn)總結(jié)
內(nèi)容:

  • C#對象的生命周期

了解對象生命周期前,要先理解類、對象與引用是怎么回事。

  • :是定義在代碼文件中,保存在硬盤上 ,是對象的藍(lán)本,它描述了對象在內(nèi)存中大概是什么樣子的。
  • 對象: 我們都知道.net將值類型存儲在棧中,引用類型存儲在堆中,這樣做的原因是棧中的數(shù)據(jù)是輕量級的,而堆中的數(shù)據(jù)是重量級,目的是在應(yīng)用程序在操作它們的時候比較方便存取,從而提高程序的運(yùn)行速度。創(chuàng)建一個對象實(shí)例,用new+類名+(),就創(chuàng)建了一個對象實(shí)例,創(chuàng)建的這個對象實(shí)例是引用類型,被存儲在托管堆中,以后就不用管它了,new關(guān)鍵字返回一個對象實(shí)例存在的地址,這個存儲地址(引用)變量,被放在棧中,實(shí)際上應(yīng)用程序在運(yùn)行時都是操作的這個引用。
  • 引用:上面說了,就是指 堆數(shù)據(jù)在堆中的地址 存儲在棧上。
下面進(jìn)入題,說下對象的生命周期:

在傳統(tǒng)的非托管C++中,用構(gòu)造函數(shù)創(chuàng)建對象實(shí)例,清除內(nèi)存中的對象實(shí)例用析構(gòu)函數(shù),也就是必須要程序員手寫消滅對象實(shí)例的方法,這樣做的話,如果析構(gòu)函數(shù)執(zhí)行失敗,或是由于程序員的疏忽,忘記了析構(gòu)代碼,那么該對象所占有的內(nèi)存會一直存在內(nèi)存中(直到應(yīng)用程序結(jié)束),那么這樣很容易造成內(nèi)存資源的浪費(fèi),有效的內(nèi)存空間得不到充分的利用,從而造成內(nèi)存泄露。那么在.net框架中,這樣的情況將不再存在,.net中不用程序顯示回收內(nèi)存,自帶的垃圾收集器會幫我們解決這一困擾,那么垃圾收集器是如何工作的呢?
還是先說下創(chuàng)建對象實(shí)例時的內(nèi)存管理:實(shí)際上內(nèi)存分配存在一個內(nèi)存指針,它總是指向下一個對象應(yīng)該放置位置,即當(dāng)創(chuàng)建一個對象實(shí)例,看內(nèi)存指針在哪里,就將這個對象實(shí)例放在指針指向的位置,然后指針再移動到下一個可以存放對象的地址,等待下一個對象的到來。

創(chuàng)建一個對象實(shí)例要經(jīng)過三步:
  1. 計算新的對象實(shí)例要用多少地址

  2. 如果堆中的地址夠用,就將調(diào)用構(gòu)造函數(shù)創(chuàng)建這個對象將把它放在內(nèi)存指針指向的位置

  3. 返回對象的引用,并將指針指向下一個對象應(yīng)該存放的地址。

接下來到了垃圾回收了! 如果在計算新對象所用空間時發(fā)現(xiàn)空閑內(nèi)在已經(jīng)不夠用了,那么.net就會調(diào)用垃圾收集程序做一次垃圾收集。CLR逐個排查不可達(dá)的對象,對么在托管堆中這個排查會浪費(fèi)大量的時間,為了優(yōu)化這個排查過程,將堆上的每一個對象對歸屬為某一個代中。CLR將內(nèi)存中的對象分為0~2代(.net2.0中)。其中

0代指的是從來沒有被標(biāo)記過垃圾收集的新對象(一般是函數(shù)域內(nèi)的對象,被視為最先收集的對象)
1代是指在上一次垃圾收集中沒有被回收的對象
2代是在一次以上沒有被回收的對象(一般是應(yīng)該程序的根級)

當(dāng)內(nèi)存中沒有位置了,垃圾收集器就開始依次調(diào)查和收集0代對象中是否有不可達(dá)對象,如果是不可達(dá)的,就將它清除,如果是可達(dá)的對象就將它標(biāo)記為1代;直到可以有足夠的位置存放新對象,這時不一定所有的0代對象對被清除了,那么它們被標(biāo)記為1代;(1代是否被標(biāo)記為2代?)如果被0代對象全部排查過了了,還不夠分配給新對象 ,那么就開始排查1代對象,沒有被回收的1代對象被標(biāo)記為2代。如果排查過1代對象仍然不夠,就開始排查第2代,就是這樣2代對象存在的時間很長。

注意:進(jìn)行垃圾收集時.net會將正在運(yùn)行的進(jìn)程中的線程全部掛起,等待清理完了,再將它們釋放。這樣做的目的是確保應(yīng)用程序在回收過程中不會訪問堆。

無論是指類型的變量或是類類型的變量,其存儲單元都是在棧中分配的,唯一不同的是類類型的變量實(shí)際上存儲的是該類對象的指針,相當(dāng)于vc6中的CType*,只是在.net平臺的語言中將指針的概念屏蔽掉了。我們都知道棧的一大特點(diǎn)就是LIFO(后進(jìn)先出),這恰好與作用域的特點(diǎn)相對應(yīng)(在作用域的嵌套層次中,越深層次的作用域,其變量的優(yōu)先級越高)。因此,再出了“}”后,無論是值類型還是類類型的變量(對象指針)都會被立即釋放(值得注意的是:該指針?biāo)赶虻耐泄芏阎械膶ο蟛⑽幢会尫牛却鼼C的回收)。.NET中的棧空間是不歸GC管理的,GC僅管理托管堆。

我想就我的理解簡要說明一下:
  1. GC只收集托管堆中的對象。
  2. 所有值類型的變量都在棧中分配,超出作用域后立即釋放棧空間,這一點(diǎn)與VC6完全一樣。
  3. 區(qū)別類類型的變量和類的對象,這是兩個不同的概念。類類型的變量實(shí)際上是該類對象的指針變量。如C#中的定義CTypemyType;與VC6中的定義CType* myType;是完全一樣的,只是.net語言將*號隱藏了。與VC6相同,必須用new 關(guān)鍵字來構(gòu)造一個對象,如(C#):CType myType=new CType();其實(shí)這一條語句有兩次內(nèi)存分配,一次是為類類型變量myType在棧中分配空間(指針類型所占的空間,對32位系統(tǒng)分配32位,64位系統(tǒng)則分配64位,在同一個系統(tǒng)中,所有指針類型所占的內(nèi)存空間都是一樣的,而
    不管該類型的指針?biāo)赶虻氖呛畏N類型的對象),另一次是在托管堆(GC所管理的堆)中構(gòu)造一個CType類型的對象并將該對象的起始地址賦給變量myType。正因?yàn)槿绱瞬旁斐闪嗽谕粋€作用域中聲明的類類型的變量和該類型的對象的生存期不一樣。
  • Unity Monobehaviour對象的生命周期

Unity3D 腳本生命周期
Unity 生命周期:http://docs.unity3d.com/Manual/ExecutionOrder.html

1、靜態(tài)構(gòu)造函數(shù)

當(dāng)程序集被加載的時候就被調(diào)用了,如果你的unity處于編輯狀態(tài)時,此時你保存一個腳本(從而迫使重新編譯),靜態(tài)構(gòu)造函數(shù)會立即被調(diào)用,因?yàn)閡nity加載了DLL。并且它將不會再次運(yùn)行,永遠(yuǎn)只會執(zhí)行一次,unity運(yùn)行時,是不會再次執(zhí)行了!在一個已部署的游戲上,這個構(gòu)造器將會在unity加載過程的早期被調(diào)用!

2、非靜態(tài)構(gòu)造器

Unity將會在一個貌似隨機(jī)的時間調(diào)用一個對象的默認(rèn)構(gòu)造器。當(dāng)你編輯一個游戲時,在你保存一個腳本(從而迫使重新編譯)后,這構(gòu)造器將會被立馬調(diào)用!

程序運(yùn)行時被隨機(jī)調(diào)用多次,程序結(jié)束時也被調(diào)用了(自己測試發(fā)現(xiàn))

所以不要使用構(gòu)造器去初始化字段的值,unity的Awake就是專門為這個目的設(shè)計的。

3、Awake

只會被調(diào)用一次,在Start方法之前被調(diào)用! 主要用于字段值的初始化工作,禁用腳本,創(chuàng)建游戲?qū)ο螅蛘?/p>

Resources.Load(Prefab)

對象

4、Start

只執(zhí)行一次,在Awake方法執(zhí)行結(jié)束后執(zhí)行,但在Update方法執(zhí)行前執(zhí)行, 主要用于程序UI的初始化操作,比如獲取游戲?qū)ο蠡蛘呓M件

5、Update

每一幀執(zhí)行的,監(jiān)聽用戶輸入,播放動畫,當(dāng)機(jī)器忙或者性能差的時候,他會停止執(zhí)行,會產(chǎn)生停頓的感覺,例如一個人本來在1米的位置,突然到了5米的位置上,產(chǎn)生了跳幀,而下面的FixedUpdate方法則相反!會一米一米的去執(zhí)行!(自己調(diào)試發(fā)現(xiàn),Update是先于OnGUI執(zhí)行的,且執(zhí)行一次Update之后,會執(zhí)行兩次OnGUI)

6、FixedUpdate

不管當(dāng)前機(jī)器忙不忙,都會保證每一幀執(zhí)行一次!避免跳幀!固定更新。固定更新常用于移動模型等操作。

7、LateUpdate

先執(zhí)行Update,然后才去執(zhí)行l(wèi)ateUpdate(Update方法執(zhí)行完,必定接著執(zhí)行LateUpdate,而Update和FixedUpdate方法的執(zhí)行順序不確定,而且有時候FIxedUpdate執(zhí)行了多幀,而Update卻只執(zhí)行了一幀,這就是因?yàn)樘鴰木壒试斐傻模ㄈQ于你的機(jī)器性能)!),如果現(xiàn)在有100個腳本,分別有100個 Update()函數(shù),其中只有一個LateUpdate,那么在同一幀中,等待100個Update()執(zhí)行完后,才執(zhí)行這一個LateUpdate()。

8、OnGUI

在這里面進(jìn)行GUI的繪制,且GUI是每幀擦除重繪的!僅僅只是繪制!沒有生命周期的概念!所有關(guān)于繪制GUI的代碼,都要直接或者間接地寫到OnGUI方法中!

9、OnDestroy

當(dāng)前腳本銷毀時調(diào)用

10、OnEnable

腳本可用時被調(diào)用、如果腳本是不可用的,將不會被調(diào)用!

如果有三個對象,a1 > a2 > a3 (父子級的關(guān)系),掛有三個腳本s1,s2,s3,三個腳本都有Awake,Start,OnEnable,OnDisable,Update方法,那么unity執(zhí)行的順序?yàn)椋?/p>

awake1,OnEnable1,awake2,OnEnable2,awake3,OnEnable3,Start1,Start2,Start3,Update1,Update2,Update3

如果在腳本s2的Awake方法中設(shè)置腳本s1不可用(s1.enabled=false),那么腳本的執(zhí)行結(jié)果為:

awake1,OnEnable1,OnDisable1,awake2,OnEnable2,awake3,OnEnable3,Start2,Start3,Update2,Update3

如果在腳本s2的Awake方法中設(shè)置腳本s3不可用(s3.enabled=false),那么腳本的執(zhí)行結(jié)果為:

awake1,OnEnable1,awake2,OnEnable2,awake3,Start1,Start2,Update1,Update2

如果在腳本s2的Start方法中設(shè)置腳本s3不可用(s3.enabled=false),那么腳本的執(zhí)行結(jié)果為:

awake1,OnEnable1,awake2,OnEnable2,awake3,OnEnable3,Start1,OnDisable3,Start2,Update1,Update2

總結(jié): 關(guān)鍵是看設(shè)置腳本不可用的位置:

A

(1)如果在父級的Awake方法里面設(shè)置子級的腳本不可用
那么僅僅只會執(zhí)行子級里面的Awake方法,當(dāng)子級被激活后(enabled=true),會先執(zhí)行OnEnable,然后執(zhí)行Start方法,Update等幀序列方法都會開始執(zhí)行

(2) 如果在父級的Start方法里面設(shè)置子級的腳本不可用
那么會執(zhí)行子集里面的Awake,OnEnable和OnDisable方法,當(dāng)子級被激活后(enabled=true),會先執(zhí)行OnEnable,然后執(zhí)行Start方法,Update等幀序列方法也都會開始執(zhí)行

B

(1) 如果在子級的Awake方法里面設(shè)置父級的腳本不可用
那么會執(zhí)行父級里面的Awake,OnEnable和OnDisable方法,當(dāng)父級被激活后(enabled=true),會先執(zhí)行OnEnable,然后執(zhí)行Start方法,Update等幀序列方法都會開始執(zhí)行

(2)如果在子級的Start方法里面設(shè)置父級的腳本不可用
那么會執(zhí)行父集里面的Awake,OnEnable,Start和OnDisable方法,當(dāng)父級被激活后(enabled=true),會先執(zhí)行OnEnable,Update等幀序列方法也都會開始執(zhí)行

如果被激活的腳本之前沒有調(diào)用Start方法,那么當(dāng)此腳本被激活后,會調(diào)用一次Start方法!具體,看生命周期第一幅圖,在文章后面!

11、OnDisable

如果腳本被設(shè)置為不可用將會被執(zhí)行,程序結(jié)束時也會執(zhí)行一次!

OnEnableOnDisable 只受腳本的可用狀態(tài)的影響(enabled)

OnBecameVisibleOnBecameInvisible 是受對象是否可見的影響(如下)!即使腳本設(shè)置為不可用,OnBecameVisibleOnBecameInvisible也會被執(zhí)行,主要是看對象是否在場景中顯示了!

OnBecameVisible 和 OnBecameInvisible :

(1)當(dāng)一開始加載一個對象時:

Game 顯示 Scene 顯示 OnBecameInvisible 不執(zhí)行 OnBecameVisible 執(zhí)行

Game 不顯示 Scene 不顯示 OnBecameInvisible 不執(zhí)行 OnBecameVisible 不執(zhí)行

Game 不顯示 Scene 顯示 OnBecameInvisible 不執(zhí)行 OnBecameVisible 執(zhí)行

Game 顯示 Scene 不顯示 OnBecameInvisible 不執(zhí)行 OnBecameVisible 執(zhí)行

小結(jié):只要Game和Scene中有一個顯示了,OnBecameVisible 就會執(zhí)行!而OnBecameInvisible 一直都不會執(zhí)行

(2)當(dāng)移動對象時:

game 和 scene 對象必須在兩個場景中同時消失 OnBecameInVisible 才執(zhí)行

scene 和 game 只要有一方進(jìn)入了場景 OnBecameVisible 就執(zhí)行了

腳本執(zhí)行順序總結(jié):

假如現(xiàn)在有三個GameObject對象:a1 > a2 > a3 (a1為a2的父節(jié)點(diǎn),a2為a1的父節(jié)點(diǎn),unity執(zhí)行腳本的順序是從上往下執(zhí)行,也就是說先執(zhí)行父節(jié)點(diǎn)上的腳本,再去執(zhí)行子節(jié)點(diǎn)的腳本,子節(jié)點(diǎn)上如果有多個腳本,那么也是自上而下的順序執(zhí)行),這三個對象對應(yīng)各有一個腳本:s1,s2,s3,且這三個腳本代碼都一樣,都有Awake,Start,Update,LateUpdate,F(xiàn)ixUpdate,那么當(dāng)運(yùn)行程序時,程序會進(jìn)行分組,即把s1,s2,s3中的Awake方法組成一組,把Start方法組成一組,把Update方法組成一組,把LateUpdate方法組成一組,把FixUpdate方法組成一組,最后按照Awake,Start,F(xiàn)ixUpdate,Update,LateUpdate(FixUpdate和Update順序不確定)的順序依次執(zhí)行!即把Awake組里面的Awake方法全執(zhí)行完,再去依次執(zhí)行Start,F(xiàn)ixUpdate,Update,LateUpdate組里面的代碼:執(zhí)行順序如下:

Awak1 Awak2 Awak3 Start1 Start2 Start3 FixUpdate1 FixUpdate2 FixUpdate3 Update1 Update2 Update3 LateUpdate1 LateUpdate2 LateUpdate3


image.png

image.png

image.png

13.游戲類型

時間:2017/12/5
主題:經(jīng)驗(yàn)總結(jié)
內(nèi)容:

  • ACT 動作游戲
       Action Game
    
  • ARPG 動作+角色扮演游戲
      Action RPG
    
  • AVG 冒險游戲
      Advanture Game
    
  • AAVG 動作+冒險游戲
      Action Adventure Game
    
  • CAG 卡片游戲
      Card Game
    
  • FPS 第一人稱視點(diǎn)射擊游戲
      First Person Shooting
    
  • FTG 格斗游戲
      Fighting Game
    
  • MMORPG 大型多人在線角色扮演游戲
     Massive Multiplayer Online Role-Playing Game
    
  • MUG 音樂游戲
      Music Game
    
  • PUZ 益智類游戲
      Puzzle
    
  • RAC 賽車游戲
      RACe Game
    
  • RPG 角色扮演游戲
      Role-Playing Game
    
  • RTS 即時戰(zhàn)略游戲
      Real-Time Strategy Game
    
  • SFTG 模擬格斗類游戲
      Simulation FTG
    
  • SLG 模擬/戰(zhàn)略游戲
      SimuLation Game
    
  • SPG 運(yùn)動游戲
      SPort Game
    
  • SRPG 戰(zhàn)略角色扮演游戲
      Simulation RPG
    
  • STG 射擊游戲
      Shooting Game
    
  • TAB 桌面游戲
      TABle
    
  • ETC 其他類游戲

12.C#的類型約束

時間:2017/11/29
主題:經(jīng)驗(yàn)總結(jié)
內(nèi)容:
這是參數(shù)類型約束,指定T必須是Class類型。

public class Singleton<T> where T : class, new()
{

}

.NET支持的類型參數(shù)約束有以下五種:

where T : struct  //T必須是一個結(jié)構(gòu)類型
where T : class  //T必須是一個Class類型
where T : new()  //T必須要有一個無參構(gòu)造函數(shù)
where T : NameOfBaseClass  // T必須繼承名為NameOfBaseClass的類
where T : NameOfInterface  //T必須實(shí)現(xiàn)名為NameOfInterface的接口

11.Unity3D之Vector3.Dot(點(diǎn)積)和Vector3.Cross(叉積)的使用

時間:2017/11/23
主題:經(jīng)驗(yàn)總結(jié)
內(nèi)容:

在Unity3D中, Vector3.Dot 表示求兩個向量的點(diǎn)積; Vector3.Cross 表示求兩個向量的叉積。

點(diǎn)積計算的結(jié)果為數(shù)值,而叉積計算的結(jié)果為向量。兩者要注意區(qū)別開來。

在幾何數(shù)學(xué)中:

1.點(diǎn)積

點(diǎn)積的計算方式為: a·b=|a|·|b|cos<a,b> 其中|a|和|b|表示向量的模,<a,b>表示兩個向量的夾角。另外在 點(diǎn)積 中,<a,b>和<b,a> 夾角是不分順序的。 所以通過點(diǎn)積,我們其實(shí)是可以計算兩個向量的夾角的。

另外通過點(diǎn)積的計算我們可以簡單粗略的判斷當(dāng)前物體是否朝向另外一個物體: 只需要計算當(dāng)前物體的transform.forward向量與 (otherObj.transform.position – transform.position)的點(diǎn)積即可, 大于0則面對,否則則背對著。當(dāng)然這個計算也會有一點(diǎn)誤差,但大致夠用。

2.叉積

叉積的定義: c =a x b 其中a,b,c均為向量。即兩個向量的叉積得到的還是向量!

性質(zhì)1: c⊥a,c⊥b,即向量c垂直與向量a,b所在的平面 。

性質(zhì)2: 模長|c|=|a||b|sin<a,b>

性質(zhì)3: 滿足右手法則 。從這點(diǎn)我們有axb ≠ bxa,而axb = – bxa。所以我們可以使用叉積的正負(fù)值來判斷向量a,b的相對位置,即向量b是處于向量a的順時針方向還是逆時針方向。

根據(jù)上面的性質(zhì)2,我們也同樣的可以計算出兩個向量的夾角。


10.編程感悟

時間:2017/11/16
主題:經(jīng)驗(yàn)總結(jié)
內(nèi)容:
項(xiàng)目進(jìn)行到了改bug階段,改了幾天bug,忽然感覺編程就像挖水道,為了把水引到目的地,我們動用各種工具,分流,改變形態(tài),匯集,調(diào)整,最終打通水路,順利完成目標(biāo),這時的滿足感和成就感令人沉醉.
ssh://developer@192.168.1.252/git/EatChicken3D.git


9.UGui背包系統(tǒng)的實(shí)現(xiàn)

時間:2017/11/14
主題:經(jīng)驗(yàn)總結(jié)
內(nèi)容:

需要的UI組件:

  • Button
    必備組件,背包的格子本質(zhì)上就是一個按鈕,可以觸發(fā)背包的各種事件.
  • Grid Layout Group
    這個組件能讓背包變得更像背包,因?yàn)樗軌虬驯嘲母褡雍芎玫呐帕衅饋?
  • Scroll View
    當(dāng)需要能滾動的背包時就需要這個組件了,比如騎馬與砍殺的背包系統(tǒng)
  • Mask
    這個組件在滾動背包中是必不可少的,只顯示固定的區(qū)域

基本思路:

背包系統(tǒng)的設(shè)計,主要包括兩大方面的設(shè)計,第一.物品類的設(shè)計,主要包括物品基類及各個繼承類的屬性設(shè)計.
第二.背包類的設(shè)計,主要包括背包基類及各個具體實(shí)現(xiàn)類的功能接口的設(shè)計.其他功能如裝備提示,整理排序等也都很好實(shí)現(xiàn).

主要模塊:

  1. 物品類數(shù)據(jù)模型的設(shè)計
  2. 背包類功能接口的設(shè)計
  3. 背包管理器和提示信息,整理排序的設(shè)計.

延伸擴(kuò)展:

背包系統(tǒng)和游戲中很多其他的系統(tǒng)都很相像,如商店系統(tǒng),鍛造系統(tǒng),抽獎系統(tǒng)等,實(shí)現(xiàn)大概思路也都差不多,主要的思想就是設(shè)計好數(shù)據(jù)模型和相應(yīng)的增刪改查工作,說到底,UI只是表現(xiàn)形式而已.


8.Unity3d 單例模式的幾種實(shí)現(xiàn)

時間:2017/11/13
主題:經(jīng)驗(yàn)總結(jié)
內(nèi)容:

今天我們要說的就是GOF23中設(shè)計模式里面的一個,叫做單例模式。
單例模式中,一個實(shí)例不允許有第二個自己存在,要保證實(shí)例唯一。他的一般解釋就是,保證一個類只有一個實(shí)例,并提供一訪問他的全局訪問點(diǎn)。單例模式因?yàn)榉庋b他的唯一實(shí)例,他就可以嚴(yán)格的控制客戶怎樣訪問他以及何時訪問他。下面我們就單例模式在unity引擎開發(fā)中的實(shí)現(xiàn)來做一些簡單說明。

第一種實(shí)現(xiàn)方式:

using UnityEngine;

using System.Collections;

public class SigletonOnlyOne : MonoBehaviour

{

    public static SigletonOnlyOne instance;

    public void Start()

    {

        if (instance==null)

        {

            instance = this;

        }

    }

    public string ShowMsg(string msg)

    {

        return msg;

    }

}
  • 優(yōu)點(diǎn):

不需要重構(gòu)什么,直接編碼。方便其他類使用。

  • 缺點(diǎn):

每個要實(shí)現(xiàn)單例的類都需要手動寫上相同的代碼,代碼重復(fù)對我們來說可不是好事情。同時需要把實(shí)現(xiàn)單例的類手動綁定到游戲?qū)ο笊喜趴梢允褂谩?/p>

第二種實(shí)現(xiàn)方式:

using UnityEngine;

using System.Collections;

/// <summary>

/// 定義單例模板基類。

/// </summary>

/// <typeparam name="T"></typeparam>

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour

{

    private static T instance;

    public static T Instance

    {

        get { return Singleton<T>.instance; }

    }

    public void Awake()

    {

        if (instance == null)

        {

            instance = GetComponent<T>();

        }

    }

    public void OnApplicationQuit()

    {

        instance = null;

        Debug.Log("quit");

    }

}
  • 優(yōu)點(diǎn):

通過代碼重構(gòu),去除掉了重復(fù)的代碼。想具有單例功能的類。只需要繼承模板基類就可以具有單例的作用。

  • 缺點(diǎn):

模板單例不需要綁定到游戲?qū)ο螅潜黄渌_本調(diào)用的需要手動綁定到游戲?qū)ο笊喜趴梢允褂谩?/p>

第三種實(shí)現(xiàn)方式:

using UnityEngine;

using System.Collections;

/// <summary>

/// 定義單例模板基類。

/// </summary>

/// <typeparam name="T"></typeparam>

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour

{

    private static T instance;

    public static T Instance

    {

        get

        {

            if (instance == null)

            {

                GameObject singleton = new GameObject();

                singleton.name = "Singleton";

                instance = singleton.AddComponent<T>();

            }

            return instance;

        }

    }

    public void OnApplicationQuit()

    {

        instance = null;

        Debug.Log("quit");

    }

}
  • 優(yōu)點(diǎn):

不需要手動綁定單例到游戲?qū)ο缶涂梢允褂谩?/p>

  • 缺點(diǎn):

這些都是游戲?qū)ο螅趗nity3d中只能在主線程中進(jìn)行調(diào)用。所以網(wǎng)絡(luò)多線程方面會產(chǎn)生單例的不唯一性,在這里就可以忽略了。

第四種實(shí)現(xiàn)方式:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace ETAFramework
{
    /// <summary>
    /// 普通單例模式
    /// </summary>
    public class Singleton<T> where T : new()
    {

        private static T _instance;
        private static readonly object _syslock = new object();

        public static T getInstance()
        {
            if (_instance == null)
            {
                //雙檢鎖
                lock (_syslock)
                {
                    if (_instance == null)
                    {
                        _instance = new T();
                    }
                    else
                    {
                        return _instance;
                    }
                }
            }
            
            return _instance;
        }
        
    }
}

第五種實(shí)現(xiàn)方式:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

namespace ETAGame
{
    /// <summary>
    /// 單例模式模板類
    /// </summary>
    public static class Singleton<T> where T : class
    {
        /*  Instance    */
        private static T _instance;

        private static readonly object syslock = new object();

        /* Serve the single instance to callers */
        public static T Instance
        {
            get
            {
                if (_instance == null)
                {  
                    lock (syslock)
                    {  
                        if (_instance == null)
                        {  
                            _instance = (T)Activator.CreateInstance(typeof(T), true);

                            return _instance;  
                        }
                        else
                        {  
                            return _instance;  
                        }  
                    }  
                }
                else
                {  
                    return _instance;  
                }  
            }
        }
    }
}

第六種實(shí)現(xiàn)方式:

using System;

public class Singleton<T> where T : class, new()
{
    private static T s_instance;

    public static T instance
    {
        get
        {
            if (Singleton<T>.s_instance == null)
            {
                Singleton<T>.CreateInstance();
            }
            return Singleton<T>.s_instance;
        }
    }

    protected Singleton()
    {
    }

    public static void CreateInstance()
    {
        if (Singleton<T>.s_instance == null)
        {
            Singleton<T>.s_instance = Activator.CreateInstance<T>();
            (Singleton<T>.s_instance as Singleton<T>).Init();
        }
    }

    public static void DestroyInstance()
    {
        if (Singleton<T>.s_instance != null)
        {
            (Singleton<T>.s_instance as Singleton<T>).UnInit();
            Singleton<T>.s_instance = (T)((object)null);
        }
    }

    public static T GetInstance()
    {
        if (Singleton<T>.s_instance == null)
        {
            Singleton<T>.CreateInstance();
        }
        return Singleton<T>.s_instance;
    }

    public static bool HasInstance()
    {
        return Singleton<T>.s_instance != null;
    }

    public virtual void Init()
    {
    }

    public virtual void UnInit()
    {
    }
}


8.Unity3d Awake() 和 Start()的區(qū)別

時間:2017/11/13
主題:經(jīng)驗(yàn)總結(jié)
內(nèi)容:
Awake函數(shù)在這個腳本在場景中加載時就會調(diào)用,至于所有腳本的Awake函數(shù)的調(diào)用順序是未知的。
然后,在所有的Awake函數(shù)調(diào)用完畢后,才開始調(diào)用Start函數(shù)。需要注意的是,Start函數(shù)也不是一定立即執(zhí)行的,它是在該腳本第一次調(diào)用Update函數(shù)之前調(diào)用的,也就是說,如果這個腳本一開始的狀態(tài)是disable的,那么直到它變成enable狀態(tài),在Update函數(shù)第一次執(zhí)行前,才會執(zhí)行Start函數(shù)。
兩個函數(shù)的執(zhí)行順序是時間有時正是某些Bug的產(chǎn)生原因!而且這些Bug往往很難發(fā)現(xiàn)。


8.Unity2017游戲模塊設(shè)計思想

時間:2017/11/2
主題:經(jīng)驗(yàn)總結(jié)
內(nèi)容:

  • 游戲模塊設(shè)計分層

7.Unity2017 Splash設(shè)置

時間:2017/11/1
主題:經(jīng)驗(yàn)總結(jié)
內(nèi)容:

1
2

6.圓形多個物品生成點(diǎn)公式

時間:2017/10/31
主題:經(jīng)驗(yàn)總結(jié)
內(nèi)容:

公式推導(dǎo):

image.png

代碼示例:

image.png


5.萬能游戲框架學(xué)習(xí)筆記

時間:2017/10/25
主題:學(xué)習(xí)筆記
內(nèi)容:

萬能框架設(shè)計模式

設(shè)計模式 工廠模式
設(shè)計模式 策略模式
設(shè)計模式 觀察者模式
設(shè)計模式 單例模式
設(shè)計模式 代理模式
設(shè)計模式 門面模式
設(shè)計模式 建造者模式
設(shè)計模式 組合模式
對模式用法總結(jié)

萬能框架之框架實(shí)現(xiàn)

框架原理講解
框架實(shí)現(xiàn) 消息類 實(shí)現(xiàn)
框架實(shí)現(xiàn)之 事件系統(tǒng),數(shù)據(jù)結(jié)構(gòu) 消息鏈表實(shí)現(xiàn)
框架實(shí)現(xiàn) 各個模塊manager
互動答疑
框架實(shí)現(xiàn) 個模塊基礎(chǔ)類
框架實(shí)現(xiàn) 使用注意事項(xiàng)

萬能框架之socket網(wǎng)絡(luò)通信模塊

網(wǎng)絡(luò)通信 Socket 網(wǎng)絡(luò)的講解
網(wǎng)絡(luò)通信 Socket客戶端的實(shí)現(xiàn)
網(wǎng)絡(luò)通信 Socket 消息的接收 封裝
網(wǎng)絡(luò)通信 Socket 類與框架的整合
網(wǎng)絡(luò)通信之 C# Protobuffer 使用

萬能框架之 資源管理

資源管理 Editor 類使用案例
資源管理之Itween 與Editor
資源管理之 Transform 與Editor
資源管理之AssetBundle 實(shí)現(xiàn) 自動打包工具 編寫
自動打包實(shí)現(xiàn) 及
資源管理之AssetBundle 動態(tài)加載實(shí)現(xiàn)
資源管理之AssetBundle 內(nèi)存管理 及依賴關(guān)系 管理(一)
資源管理之AssetBundle 內(nèi)存管理 及依賴關(guān)系 管理(二)

萬能框架之 RPG游戲?qū)崙?zhàn)

RPG游戲?qū)崙?zhàn) RPG游戲UI 制作
RPG游戲?qū)崙?zhàn) 主角色人物控制 動畫控制
RPG游戲?qū)崙?zhàn) 主角色人物控制 動畫控制 及答疑
RPG游戲?qū)崙?zhàn) 3D數(shù)學(xué)與向量
RPG游戲?qū)崙?zhàn) 矩形 攻擊
RPG游戲?qū)崙?zhàn) NPC 控制
RPG游戲?qū)崙?zhàn) NPC 邏輯控制
完善游戲
RPG游戲?qū)崙?zhàn) 小地圖實(shí)現(xiàn)
RPG游戲?qū)崙?zhàn) 頂點(diǎn)Mesh講解
RPG游戲?qū)崙?zhàn) 人物換裝
RPG游戲?qū)崙?zhàn) BlendShape 動畫
RPG游戲?qū)崙?zhàn) Mesh 頂點(diǎn)操作

萬能框架之 熱更新

熱更新 Lua 變量 控制流
熱更新 Lua 函數(shù)
熱更新 Lua 字典 與數(shù)組
熱更新 Lua 面對對象編程
熱更新 Lua 深層次堆棧講解
熱更新 Lua 框架 消息實(shí)現(xiàn)
熱更新 消息處理中心實(shí)現(xiàn)
熱更新 鏈表實(shí)現(xiàn)
熱更新 各個Base 實(shí)現(xiàn)
熱更新之Lua 加密 實(shí)現(xiàn)
熱更新之Lua 與 C# 通信
熱更新之Lua 與 C# 通信

萬能框架之 python工具篇
Python 基礎(chǔ)知識講解
Python 控制語句講解
工具篇 Python 基礎(chǔ)知識講解
工具篇 Python 控制語句講解
工具篇 Python 數(shù)組
工具篇 Python 字典講解
工具篇 解包APK實(shí)現(xiàn)
工具篇 解包APK實(shí)現(xiàn)
工具篇 簽名實(shí)現(xiàn)
工具篇 Python自動打包全實(shí)現(xiàn)

主程面試技巧篇:

面試技巧之簡歷篇
面試技巧之面試技巧
面試技巧之工作技巧篇

萬能框架目錄說明
根目錄說明

Assetbundle: 全部打包的資源臨時文件夾
ITools: 工程中常用的工具
BuildLua:加密lua python腳本
protoc-gen-lua-master: protobuffer 生成工具。
Python: 包括python 安裝包 和 常用 exe 工具。 可以將bin 放入環(huán)境變量中。
luaEncoder: 對lua 進(jìn)行加密用的工具。

image02

Art: 用到的資源全部放在這里
codeandweb.com:Texturepacker 工具 文件夾
Editor: lua 要wrap的文件
FrameExaple:框架的例子都在這
Lua: 做熱更新寫的lua 腳本都放這里
Plugins: 框架和lua 的dll 全在這
Scripts: 開發(fā)游戲的各個模塊都在這

腳本目錄說明

Animal: 動畫工具
Asset: assetbundle 模塊
Camera: 相機(jī)常用功能
Configer: 全局的配置文件都在這。
DB: sqlite3 常用的功能
Editor: 工具欄的工具全在這。
ForLua: 為了lua 寫的一些功能。
GameLogic: 游戲邏輯
GameManager: 整個游戲控制
Net:常用的 tcp udp通訊類
Particle: 例子常用的工具類
SkyBox: SkyBox 常用工具
Tools: 封裝的各種工具類。
UI: UI 各種工具類。


4.游戲編程中需要重點(diǎn)掌握的設(shè)計模式

時間:2017/10/25
主題:經(jīng)驗(yàn)總結(jié)
內(nèi)容:
設(shè)計模式共有23種,這是基本常識,設(shè)計模式這本書如果從頭學(xué)起來,非常抽象,不容易理解。游戲開發(fā)常用的設(shè)計模式:單例模式,工廠模式,抽象工廠模式,狀態(tài)模式,觀察者模式等這幾個要重點(diǎn)掌握。除了提到的這幾個,還有一個應(yīng)用非常廣泛的設(shè)計模式就是MVC設(shè)計模式,它的全稱:Model,View,Controller,中文意思就是模型,視圖,控制器。它以前主要是應(yīng)用在Web端,現(xiàn)在我們拿來將其應(yīng)用到游戲開發(fā)中。

  • 單例模式
  • 工廠模式
  • 抽象工廠模式
  • 狀態(tài)模式
  • 觀察者模式
  • MVC設(shè)計模式
6種設(shè)計原則
23中設(shè)計模式解析

3.U3D編程進(jìn)階的一些思想

時間:2017/10/24
主題:經(jīng)驗(yàn)總結(jié)
內(nèi)容:
所謂編程,就是選擇好恰當(dāng)?shù)臄?shù)據(jù)結(jié)構(gòu)設(shè)計好數(shù)據(jù)模型,選擇恰當(dāng)?shù)脑O(shè)計模式劃分不同功能的各個模塊,處理好各個模塊的引用關(guān)系,然后在控制模塊的腳本里做好邏輯判斷從輸入產(chǎn)生輸出。

  • 生命周期思想:
    要時刻注意著游戲中各種對象和組件的生命周期,一個對象從出生到銷毀要有一個清晰的認(rèn)識。如果編程時這個認(rèn)識不清,非常容易造成空引用,內(nèi)存占用過多,功能不執(zhí)行等問題。
  • 面向?qū)ο笏枷耄?/strong>
    寫代碼不能想到哪里寫到哪里,寫的時候腦子里要思考怎么才能更好的調(diào)用和維護(hù),這方面比較抽象,只能通過多寫代碼,多做項(xiàng)目來增長經(jīng)驗(yàn)了。
  • 分層思想:
    一個游戲項(xiàng)目的架構(gòu)從大方面可以分為框架層和業(yè)務(wù)層,雙方要保持經(jīng)緯分明,業(yè)務(wù)層只能調(diào)用而不能修改框架層的邏輯,從小方面可以分為數(shù)據(jù)模塊,UI模塊和業(yè)務(wù)模塊,也就是MVC設(shè)計,這三個模塊各自做好自己的事互相之間的交叉要盡量減少。
  • 引用思想:
    不要怕腳本太多,哪怕腳本再多,每個腳本都能取到任何一個對象或數(shù)據(jù)的引用,都能取的到,就看怎么組織代碼了。不同作用的代碼為什么要分開,是為了,其實(shí)只是為了方便管理和維護(hù),你甚至可以把項(xiàng)目的所有腳本都寫到一個類里面,照樣可以跑起來,但是這樣的話維護(hù)起來就非常麻煩了。 把不同作用的代碼分門別類放好,有對數(shù)據(jù)進(jìn)行增刪改查的,有負(fù)責(zé)對象的具體行為的,有和UI進(jìn)行交互的,各司其職。
  • 輸入輸出思想:
    程序就是輸入處理后產(chǎn)生輸出,每個函數(shù)就是輸入輸出,每個類就是大型的函數(shù),每個模塊就是更大型的函數(shù),功能都是輸入輸出。

2.學(xué)什么和怎么學(xué)

時間:2017/10/22
主題:學(xué)習(xí)規(guī)劃
內(nèi)容:
做Unity3d一年多了,感覺我還是非常喜歡這個行業(yè)的.也非常喜歡程序員這個職業(yè),但是最近一段時間心有一些浮躁,想學(xué)的東西有太多,但是時間是一定的,面面俱到注定無法取得很大的成就,因此我把以后的學(xué)習(xí)路線做一個簡單的規(guī)劃,把鋼使在刀刃上.

學(xué)習(xí)內(nèi)容
  • 持續(xù)學(xué)習(xí)的內(nèi)容:
    C#編程, Unity3d游戲開發(fā), 包括各種API, 功能模塊, 設(shè)計思想, 游戲框架構(gòu)等項(xiàng)目編程知識. 這是我的飯碗,一定要不斷加強(qiáng).
  • 需要補(bǔ)習(xí)的內(nèi)容:
    微積分, 線性代數(shù), 數(shù)據(jù)結(jié)構(gòu)和算法, 計算機(jī)圖形學(xué), 操作系統(tǒng), 計算機(jī)網(wǎng)絡(luò)等計算機(jī)底層知識. 學(xué)習(xí)這些基礎(chǔ)知識能提高我的上限.
  • 業(yè)余學(xué)習(xí)的內(nèi)容:
    Shader, C++, Python等未來可能會用到的知識以及獨(dú)立游戲制作需要的其他軟件. 這些知識能讓我掌握職業(yè)主動權(quán).
學(xué)習(xí)時間:

每天下班后2小時和節(jié)假日.

學(xué)習(xí)方式:

看教程,看書,結(jié)合做項(xiàng)目,學(xué)習(xí)過程要形成筆記.方便以后查閱.


1.學(xué)習(xí)筆記的建立和約定

時間:2017/10/22
主題:學(xué)習(xí)規(guī)劃
內(nèi)容:
用來記錄日常學(xué)習(xí)遇到的知識點(diǎn).以后都按照第一條的也就是現(xiàn)在寫的這條的格式進(jìn)行記錄. 為了方便查看,筆記按照從后往前的順序?qū)?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。