使用Unity的50個建議

關於這些建議算法

這些建議並不適用於全部的項目編程

  • 這些建議是基於我與3-20人的小團隊項目經驗總結出來的
  • 結構、可重複使用性、明晰度都是有價的——團隊規模和項目規模決定了是否值得付這個價。
  • 一些建議也許公然違抗了傳統的Unity開發。例如:使用專業化的組合而不是使用實例就很不像Unity的做風,價格也很高。即便看上去挺瘋狂的,但我仍是看到了這些建議給開發者帶來了利益。

過程方面數組

1.避免分支資產 對於任何資產咱們應該只有一個版本。若是你非要把一個預設,場景,或網格分支開來,那麼情遵循一個過程,這個過程必須清楚的代表哪個纔是正確的版本。錯誤的分支應該有一個顯著的名字,例如,使用雙下劃線前綴__MainScene_Backup。預設的分支須要一個特定的過程來使其安全。(詳見預設部分)安全

2.持有項目副本 任何一個使用版本控制的團隊成員都應該持有項目的副本,用於測試檢查。在變更以後,副本,這一干淨的版本,應該更新並測試。任何人都不能對乾淨的副本作任何改變。當找回丟失的東西的時候,這一點就會發揮做用。數據結構

3.考慮使用外部關卡工具來編輯關卡 Unity並非完美的關卡編輯器。例如,咱們曾經使用TuDee來爲3D遊戲創建關卡,這是個能讓咱們輕鬆創建磚塊的工具(捕捉網格、多倍數的90度旋轉、2D視圖、快速選擇磚塊)。從XML文件轉爲預設的實例是簡單的。你能夠從Guerrilla Tool Development得到更多的啓發。架構

4.在XML中保存關卡而不是在場景中 這是一個極好的技術編輯器

  • 它使咱們沒必要從新設置每個場景
  • 它使裝載更加迅速(在場景之間共享大部分對象的狀況下)
  • 它讓合併場景更加容易(即便用Unity基於文本的場景,但太多的數據仍就致使合併在任何狀況下都是不切實際的)
  • 它使跟蹤關卡的數據軌跡更爲簡單

固然你也可使用Unity做爲關卡編輯器(雖然你不須要),你須要寫一些代碼來序列化和反序列化你的數據,在編輯器內和運行的時候裝載關卡,而後在編輯器裏保存關卡。你可能還須要模仿Unity的ID系統來維護對象之間的參照。ide

5.編寫自定義的檢查代碼 寫自定義檢查至關簡單,可是Unity的系統有不少弊端工具

  • 它不支持利用繼承
  • 它不支持定義字段類型關卡的檢查組件,只支持類的關卡。例如,若是每一個遊戲對象都有字段類型SomeCoolType,你想在檢查過程當中以不一樣的描述顯現出來,那你就須要爲全部的類寫檢查的代碼。

你能夠完全的從新執行檢查系統來解決這些問題。用一些映像技巧,這並不想看起來那麼難,具體方法將在文章末尾提供。佈局

6.使用命名爲空的遊戲對象做爲場景文件夾 仔細安排你的場景使它容易找到對象。、

7.在000條件下維護預設和文件夾(空的遊戲對象) 若是一個轉變專門用於定位一個對象,那麼它應該在原點。這樣,在本地和世界空間運行出錯的風險就更小,代碼也會更簡單。

8.減小GUI組件的偏移 偏移量應該始終用在父組件的佈局組件裏;它們不該該依靠更上一級的組件定位。偏移量不該經過互相抵消來正確顯示,這基本上是爲了防止如下事件:

父容器定位在(100, -50),子容器,應該定位在(10, 10),而後定位在(90, 60)[相對於父容器]。

這種錯誤在容器隱藏,或者是根本沒有可視化表現的狀況下是常見。

9.把你的世界基準定義在y = 0。這樣更容易把對象放在地面上,在遊戲邏輯、AI以及物理方面把世界當作一個2D空間(適當時)。

10.讓遊戲的每一個場景運行流暢。這大大減小了測試時間,要讓全部的場景運行流暢,你須要作兩件事:

首先,你要找到一種方法仿製全部的數據,這些數據在以前下載的場景裏是須要但倒是不可用的。

第二,產生的對象必須堅持場景負載之間的下列語句

1
2
3
4
5
6
7
8
9
myObject = FindMyObjectInScene();
 
if (myObjet == null )
 
{
 
    myObject = SpawnMyObject();
 
}

美術方面

11.把人物和站立物體的支點放在底部,而不是中心。這樣易於將人物和物體精準的放在地面上。同時在遊戲邏輯、AI以及物理方面,這也能讓3D工程像2D同樣簡單,固然是在某些合適的狀況下。

12. 讓全部的網格面向同一方向(正或負Z軸)。這適用於那些有朝向概念的人物或者事物的網格。若是全部的東西都面朝一個方向,那麼許多算法均可以獲得簡化。

13.從一開始就肯定尺寸。

14.製做二聚平面用以GUI組件和手動建立粒子。

15.製做和使用的測試技術

l  網格

l  各類純的顏色:白色,黑色着色試驗,50%的灰,紅,綠,藍,黃,洋紅,青藍。

l  陰影檢測梯度:黑色到白色,紅色,綠色,紅色,藍色,綠色,藍色。

l  黑白棋盤

l  平滑和崎嶇的法線貼圖

l  照明設備(如預製)快速創建測試場景

16.對於一切均可以使用預製。遊戲場景中的惟一對象不該該是預製,而應該是文件夾。即便是隻使用一次的特殊對象也應該是預製。這使得不改變場景也能夠輕鬆實現轉變。(這也讓使用EZGUI構建sprite地圖時更加可靠)

17. 使用不一樣的預製來專業化,不使用專門的實例。若是你有兩個類型的敵人,他們的惟一區別是他們的財產不一樣,那麼對財產分別做預製,而後再將其連接,這讓下面兩點成爲可能:

l  在一個地方對任何類型作改變

l  在不改變場景的狀況下作出變化

若是你有太多的敵人類型,那麼就不用在編輯器重作出專業化實例了。一種代替方法是作程序,或者使用對全部的敵人使用一個核心文件/預製。一個降低動做能夠用於不一樣的敵人,一個運算能夠基於敵人位置或玩家進程。

18.將預製之間連接,實例之間不連接。當把預製拖放到場景時,預製的連接能夠獲得保證,而實例則不能夠。連接到預製能夠在任什麼時候候減小場景的創建,也能夠減小場景變化的需求。

19.儘量在實例之間自動創建鏈接。若是你須要連接實例,創建編程連接。例如,玩家預製能夠在GameManager啓動時本身註冊,或者GameManager在啓動時能夠找到玩家預製實例。

l  若是你想添加其餘腳本的話,就不要把網格放在預製的根源。

l  用連接預製代替嵌套預製。

20.使用安全的流程來分支預製。咱們以玩家預製爲例來解釋:

以下是一個有風險的改變玩家預製的方法:

1.   複製玩家預製

2.   重命名該副本 __Player_Backup

3.   改變玩家預製

4.   若是一切順利,刪除 __Player_Backup

不要把把副本命名爲Player_New,而且改變它!

有些狀況更加複雜。例如,某個改變可能涉及兩我的,按照上述步驟直到Person 2完成的時候,可能會破壞掉全部人的工做場景。若是足夠快的話,仍會是這樣。由於變化須要的時間更長,你能夠仿照下面的方法:

Person 1

1.   複製玩家預製

2.   重命名爲__Player_WithNewFeature或者__Player_ForPerson2.

3.   在副本上修改,而且提交到Person 2

Person 2:

1.   在新預製上作修改

2.   複製玩家預製,命名爲 __Player_Backup.

3.   拖動__Player_WithNewFeature的實例到場景

4.   拖動這個實例到原來的玩家預製

5.  若是一切順利,刪除__Player_Backup 和 __Player_WithNewFeature.

拓展組件和 MonoBehaviourBase

21.拓展你本身的基本單一行爲,並推導出全部它的組件。這讓你實現一些通用功能,如類的安全調用和其餘更復雜的調用。

22.定義調用的安全方法StartCoroutine和實例化。定義一個委託任務,並用它來定義不依賴於字符串名稱的方法,例如:

1
2
3
4
5
6
7
public void Invoke(Task task, float time)
 
{
 
    Invoke(task.Method.Name, time);
 
}

23.使用共享界面的拓展組件。有時候能夠很方便的獲得執行某個界面的組件,或者使用組件找到對象。下面的執行使用typeof來代替這些功能的通用版本。通用版本不能使用這些接口,可是typeof能夠。請參考:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//Defined in the common base class for all mono behaviours
 
public I GetInterfaceComponent<I>() where I : class
 
{
 
    return GetComponent( typeof (I)) as I;
 
}
 
public static List<I> FindObjectsOfInterface<I>() where I : class
 
{
 
    MonoBehaviour[] monoBehaviours = FindObjectsOfType<MonoBehaviour>();
 
    List<I> list = new List<I>();
 
     foreach(MonoBehaviour behaviour in monoBehaviours)
 
    {
 
       I component = behaviour.GetComponent( typeof (I)) as I;
 
        if (component != null )
 
       {
 
          list.Add(component);
 
       }
 
    }
 
     return list;
 
}

24.使用拓展組件使語法更加方便,例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static class CSTransform
 
{
 
    public static void SetX( this Transform transform, float x)
 
    {
 
       Vector3 newPosition =
 
          new Vector3(x, transform.position.y, transform.position.z);
 
  
 
       transform.position = newPosition;
 
    }
 
    ...
 
}

25.使用備用的GetComponent以供選擇。有時候強制組件依賴關係使人頭疼(經過RequiredComponent)。例如:這使得在檢查器中難以改變組件(即便它們是相同的基本類型)。做爲替代品,當一個組件須要輸出一條沒有被發現的錯誤信息時,下面的GameObject拓展就可使用了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static T GetSafeComponent<T>( this GameObject obj) where T : MonoBehaviour
 
{
 
    T component = obj.GetComponent<T>();
 
  
 
    if (component == null )
 
    {
 
       Debug.LogError( "Expected to find component of type "
 
          + typeof (T) + " but found none" , obj);
 
    }
 
  
 
    return component;
 
}
 

術語/語法

26.避免使用不一樣的語法來作同一件事。許多狀況下,能夠有多種語法來作一件事。這時,請選擇一種貫穿項目的始終,由於:

  • 有些語法不能很好地協同工做。只使用一種語法使得設計可以朝着一個方向進行,而且不適合其餘語法。

  • 從始至終使用一種語法能讓團隊成員更好地瞭解項目進程,可讓架構和代碼更容易理解,更少出錯。

例子:

·協同VS.狀態機。

·嵌套問題VS.相關問題VS.預製

·數據分離策略

·2D遊戲狀態中使用sprites的方法

·預製結構

·生產策略。

·查找對象的方法:按類型VS.名稱VS.標記VS.層VS.參考(「連接」)。

·組對象的方法:類型VS.名稱VS.標籤VS.層VS.數組引用(「連接」)。

·尋找對象VS.自注冊

·控制執行規則(使用Unity的執行規則設置VS.產生邏輯VS.清醒/啓動和更新/晚更新依賴VS.手工方法VS.任何規則結構)

·選擇對象/位置/用鼠標選擇目標:選擇管理VS.自我管理

·保持變化場景之間的數據:經過PlayerPrefs,或者加載一個新場景時不會被破壞的物體

·結合方式(混合,添加和分層)動畫

 

產生對象

28.遊戲運行時,不要讓產生對象弄亂你的層次。當遊戲運行時,在場景對象中設置他們的父對象將使東西更容易找到。你可使用一個空的遊戲對象,甚至是單例來使訪問代碼更容易。將這個對象成爲DynamicObjects。

數據結構設計

29.爲方便起見請使用單例下述可使任何數據自動繼承單例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Singleton<T> : MonoBehaviourwhere T : MonoBehaviour
{
    protectedstatic T instance;
  /**
       Returnsthe instance of this singleton.
    */
    publicstatic T Instance
    {
       get
       {
         if (instance == null )
          {
            instance = (T) FindObjectOfType( typeof (T));
   
             if (instance == null )
             {
               Debug.LogError( "An instance of " + typeof (T) +
                  " is needed in the scene, but there is none." );
             }
          }
   
         return instance;
       }
    }
}

單例對管理頗有用,好比粒子管理、音頻管理、GUI管理

30.對於組件,毫不要公開那些不該在檢查面板中調整的變量。不然,它建個可能被設計師改變,尤爲是在不清楚它的用處的時候。在某些罕見的狀況下,這是不可避免的。在這種狀況下,請使用雙下劃線甚至四個下劃線來做爲變量的名稱前綴,以警告那些想要作修改的人。

public float __aVariable;

31.把界面從遊戲邏輯中分離出來

32.分離狀態和簿記簿記變量是爲了高效、方便,並可從狀態中恢復。經過分離這些,你能夠更容易的:

·保存遊戲狀態

·調試遊戲狀態

一種方法是:爲每一個遊戲邏輯類定義一個保存數據類

1
2
3
4
5
6
7
8
9
10
11
[Serializable]
PlayerSaveData
{
    public float health; //public forserialisation, not exposed in inspector
}
  Player
{
    //... bookkeeping variables
    //Don’t expose state in inspector. State isnot tweakable.
    private PlayerSaveData playerSaveData;
}

33.獨立專業化設置。考慮兩個有着相同網格,但Tweakables不一樣(例如不一樣強度和不一樣速度)的敵人,有不一樣的方式來分離數據。我傾向於下述方式,特別是當對象被催生或者遊戲保存的時候。(Tweakables不是狀態數據,而是配置數據,因此不須要保存,當加載或催生對象的時候,Tweakables會自動分別加載)

·定義每一個遊戲邏輯類的模板類。例如,對敵人,咱們還定義了Enemytemplate。全部的分化Tweakables都存儲在Enemytemplate

·在遊戲邏輯類裏,定義一個變量的模板類型。

·作一個敵人的預製件,和兩個模板預製weakenemytemplate和strongenemytemplate。

·加載或催生對象時,設置合適模板的模板變量。

這種方法能夠變得至關複雜的(有時是沒必要要的,複雜的,因此要當心!)。

例如,爲了更好地利用通用多態性,咱們能夠這樣定義類:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class BaseTemplate
{
    ...
}
   
public class ActorTemplate : BaseTemplate
{
    ...
}
   
public class Entity<EntityTemplateType>where EntityTemplateType : BaseTemplate
{
   EntityTemplateType template;
    ...
}
   
public class Actor : Entity<ActorTemplate>
{
    ...
}

34.字符串不要用於顯示文字以外的任何事。特別是,不要使用字符串識別對象或預製等。動畫是個不幸的例外,一般訪問它們的字符串名稱。

35.避免使用公共指數耦合陣列。例如,不要定義武器陣列,子彈陣列,和顆粒陣列,你的代碼看起來像這樣:

1
2
3
4
5
6
7
8
9
10
11
public void SelectWeapon(int index)
{
   currentWeaponIndex = index;
   Player.SwitchWeapon(weapons[currentWeapon]);
}
   
public void Shoot()
{
   Fire(bullets[currentWeapon]);
   FireParticles(particles[currentWeapon]);
}
這裏的問題並非徹底在於代碼,而是在檢查面板中不犯錯誤地設置出來。

相反,定義一個類,封裝三個變量,使一個數組:

1
2
3
4
5
6
7
[Serializable]
public class Weapon
{
    publicGameObject prefab;
    publicParticleSystem particles;
    publicBullet bullet;
}

這段代碼看上去更整潔,最重要的是,在檢查面板裏創建數據時不容易出錯。

36.避免使用序列之外的數組結構。例如,一個玩家可能有三種攻擊類型,每一個都使用當前的武器,可是產生不一樣的子彈和行爲。你可能想把三個子彈放在一個數組中,用這種邏輯:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void FireAttack()
{
    ///behaviour
   Fire(bullets[0]);
}
   
public void IceAttack()
{
    ///behaviour
   Fire(bullets[1]);
}
   
public void WindAttack()
{
    ///behaviour
   Fire(bullets[2]);
}
枚舉可讓代碼看起來更好…
public void WindAttack()
{
    ///behaviour
   Fire(bullets[WeaponType.Wind]);
}

可是不是在檢查面板中。

最好使用獨立的變量,名稱能夠有助於顯示應該放入哪些內容。使用一個類來讓它整潔。

1
2
3
4
5
6
7
[Serializable]
public class Bullets
{
    publicBullet FireBullet;
   public Bullet IceBullet;
   public Bullet WindBullet;
}

PS:假設沒有其餘的火、冰、風等數據。

37.在序列化類中將數據分組以使事物在檢查面板中看起來更整潔。一些實體可能有幾十個tweakables,這就使得在檢查面板中尋找正確的變量成爲一場噩夢。如下步驟會讓事情變簡單:

·對變量組定義獨立的類,使其公開並序列化。

·在主類裏,爲如上定義的每一類型定義公共變量

·不要在Awake 或 Start初始化這些變量,由於他們是序列化的,Unity會處理那些。

·你能夠像之前同樣經過定義賦值指定缺省值

·這將在檢查面板中將變量按可摺疊單位分組,便於管理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[Serializable]
public class MovementProperties //Not aMonoBehaviour!
{
   public float movementSpeed;
   public float turnSpeed = 1; //default provided
}
   
public class HealthProperties //Not aMonoBehaviour!
{
   public float maxHealth;
   public float regenerationRate;
}
   
public class Player : MonoBehaviour
{
   public MovementProperties movementProeprties;
   public HealthPorperties healthProeprties;
}

文本

38.若是你的故事文本不少,那麼請將文本放在一個文件中。不要放在檢視面板的編輯器裏。要讓它在不打開Unity的狀況下就能夠編輯,特別是在不用保存場景的狀況下。

39.若是你打算本地化,把全部字符串獨立到一個地方。方法不少,其一是定義每一個字符串都有公共字符串字段的文本類,默認設置爲英語。例如:其餘語言子屬於它,而後用語言賦值從新初始化字段。

更先進的技術將讀取電子數據表,而後基於所選語言爲選擇正確的字符串提供邏輯。

 

測試和調試

40.執行圖形記錄器調試物理,動畫,和AI,這可使調試至關快。

41.執行HTML記錄器。在某些狀況下,記錄仍然是有用的。記錄能夠更容易地解析(彩色編碼,多個視圖,記錄截圖),可使日誌調試更愉快。

42.執行你本身的FPS計數器。是的,沒人知道Unity的FPS計數器到底測量什麼,但不是幀速率。執行你本身的,這樣數量就能夠協調直覺和視覺檢查了。

43.快捷鍵實現屏幕截圖。許多bugs是可見的,而且經過圖片能夠更容易發現。

44.實施快捷方式打印玩家的世界位置。這易於發現bug的位置。

45.執行debug選項使測試更容易,例如

·解鎖全部項目

·禁用敵人

·禁用GUI

·讓玩家無敵

·禁用全部的遊戲

46.對於足夠小的團隊,爲每個成員作一個有debug選項的預製。將用戶標示符放在一個不被認可的文件裏,而且在遊戲運行時讀取,緣由是:

·團隊成員偶爾會不認可他們的debug選項,還可能影響到別人。

·改變debug選項不改變場景

47.維持全部遊戲元素的場景。例如:一個你能夠與全部敵人,全部對象互動的場景等等。這能夠很容易地測試功能,不用耗費太多精力。

48.爲調試快捷鍵定義常量並保持固定的位置。

49.記錄你的設置。絕大多數的文件都應該編碼,可是某些東西應該記錄在代碼以外。讓設計師經過設置找代碼是在浪費時間。記錄設置能提升效率(若是是最近的記錄)。

按下列方式記錄:

·層使用(碰撞,裁剪,和光線投射–本質,哪一層裏應該有什麼)

·標籤使用

·GUI深度層(應該顯示什麼)

·場景設置

·語法偏好

·預製結構

·動畫層

·命名標準和文件夾結構

50. 遵循文件的命名規則和文件夾結構。統一的命名和文件夾結構更利於查找和辨認。相信你也但願建立本身的命名規則和文件夾結構。這裏提供一個例子供參考。

 

命名的通常原則:

1.是什麼就叫什麼。一隻鳥就應該就應該叫作「Bird」。

2.選擇容易發音和記住的名字。若是你在作瑪雅語的遊戲,不要命名QuetzalcoatisReturn。

3.保持一致。選了一個名字就堅持到底。

4.使用Pascal案例,就像這樣: ComplicatedVerySpecificObject。不要使用空格、下劃線或者連字符,可是也有一個例外(請參閱命名同一事物的不一樣方面)。

5.不要用版本號或者表示進程的詞彙(WIP,final)。

6.不要用縮寫:DVamp@W 應該是 DarkVampire@Walk。

7.在設計文件中使用術語。若是文件中把die animation稱做Die,那麼請用DarkVampire@Die,而不是DarkVampire@Death.

8.把特定描述放在左邊。是DarkVampire而不是VampireDark;是PauseButton而不是 ButtonPaused。

9.有些名字會造成序列。在這些名字中使用數字。例如:PathNode0, PathNode1。要從0開始,而不是從1開始。

10.不會造成序列的名字就不要使用數字。好比Bird0, Bird1, Bird2應該被叫作Flamingo, Eagle, Swallow.

11.給臨時對象命名請使用雙下劃線前綴__Player_Backup.

命名同一事物的不一樣方面

在覈心名稱與描述性事物之間使用下劃線,例如

·GUI按鈕狀 EnterButton_Active, EnterButton_Inactive

·紋理 DarkVampire_Diffuse, DarkVampire_Normalmap

·天空盒 JungleSky_Top, JungleSky_North

·LOD組  DarkVampire_LOD0, DarkVampire_LOD1

不要使用本規則來區分不一樣類型的項目,例如rock_small,rock_large應該是smallrock,largerock。

結構

場景、工程文件夾以及腳本文件夾的組織應當遵循相似的模式。

文件夾結構

Materials

GUI

Effects

Meshes

   Actors

      DarkVampire

      LightVampire

      ...

   Structures

      Buildings

      ...

   Props

      Plants

      ...

   ...

Plugins

Prefabs

   Actors

   Items

   ...

Resources

   Actors

   Items

   ...

Scenes

   GUI

   Levels

   TestScenes

Scripts

Textures

GUI

Effects

...

場景結構

Cameras

Dynamic Objects

Gameplay

   Actors

   Items

   ...

GUI

   HUD

   PauseMenu

   ...

Management

Lights

World

   Ground

   Props

   Structure

   ...

腳本文件夾結構

ThirdParty

   ...

MyGenericScripts

   Debug

   Extensions

   Framework

   Graphics

   IO

   Math

   ...

MyGameScripts

   Debug

   Gameplay

      Actors

      Items

      ...

   Framework

   Graphics

   GUI

   ...

怎樣從新執行Inspector Drawing

1.爲全部的編輯定義基類

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
BaseEditor<T>: Editor
where T :MonoBehaviour
{
    override public void OnInspectorGUI()
    {
       T data = (T) target;
   
       GUIContent label = new GUIContent();
       label.text = "Properties" ; //
   
       DrawDefaultInspectors(label, data);
   
       if (GUI.changed)
       {       
          EditorUtility.SetDirty(target);
       }
    }
}
2.使用反射和遞歸來繪製組件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public staticvoid DrawDefaultInspectors<T>(GUIContent label, T target)
    where T : new ()
{
    EditorGUILayout.Separator();
    Type type = typeof (T);    
    FieldInfo[] fields = type.GetFields();
    EditorGUI.indentLevel++;
   
    foreach(FieldInfo field in fields)
    {
       if (field.IsPublic)
       {
          if (field.FieldType == typeof (int))
          {
             field.SetValue(target,EditorGUILayout.IntField(
             MakeLabel(field), (int)field.GetValue(target)));
         
          else if (field.FieldType == typeof (float))
          {
             field.SetValue(target,EditorGUILayout.FloatField(
             MakeLabel(field), (float)field.GetValue(target)));
          }
   
          ///etc. for other primitive types
   
          else if (field.FieldType.IsClass)
          {
             Type[] parmTypes = new Type[]{field.FieldType};
   
             string methodName = "DrawDefaultInspectors" ;
   
             MethodInfo drawMethod =
               typeof (CSEditorGUILayout).GetMethod(methodName);
   
             if (drawMethod == null )
             {
                Debug.LogError( "No methodfound: " + methodName);
             }
   
             bool foldOut = true ;
   
            drawMethod.MakeGenericMethod(parmTypes).Invoke( null ,
                new object[]
                {
                   MakeLabel(field),
                   field.GetValue(target)
                });
          }    
相關文章
相關標籤/搜索