首先要道歉。
非常抱歉,本來答應前幾天回複,不過最近每天真是太忙了,計劃表中每天都要實現一個功能,所以直到今天早上才查看並修改。
代碼功能先放在一邊,首先有幾個問題要說明。
1.代碼不可運行。
不知道是不是Unity版本不對,
或是什麼別的原因,
代碼拷進來之後根本無法運行,
提示錯誤連篇。
於是我開始大幅度修改,
直到成功運行。
不過版本問題先放在一邊,
話說發過來的版本中Init方法中的Window都沒有調用Show方法,
不知道原本是如何啟動並執行。
2.在半個小時的修改過程中,
我主要做了以下幾件事:
-----------------------------
①.重新命名變數。
比如說那個map_a,
非局部變數應使用駱駝峰式命名。
②.抽取方法。
當看到OnGUI中格式代碼(StartHorizontal)和功能代碼混在一起,
一個方法就有三四十行的時候,
我有些失去耐心了。
提取方法我使用了以下幾種方法:
(1).重複資料刪除代碼。比如說那個DestroyImmediately,提取成了assertNull,
還順便取消原來的"gobj"變數。
(2)化繁為簡。比如說我將兩個Button的功能提取為兩個方法,簡明扼要。
(3)便於理解。將長代碼拆分成不同的功能部分,一來簡化代碼,其次將不同的
功能區域區分開,便於閱讀。
③.減少花括弧數目。
這一點你在編程時也能感受到,
當五六七八個花括弧疊在一起時,
無論是閱讀還是欣賞都毫無意義。
如果你之前習慣Java或是Android編程,
那我要提醒一句,
在Unity或是C#中,
這麼玩可不行。
雙重for迴圈無法精簡,那就將裡面的if和else拆分開就可以了。
使用continue或是break什麼的代替,
很容易就能減少花括弧的數量。
④.減少臨時變數數目。
obj和gobj的命名問題先放在一邊,
但這兩個臨時變數多次出現在不同方法,
這一點就足以證明程式不夠精簡,
運行起來也會毫無疑問效率較低。
盡最大可能減少臨時變數的出現,
尤其是重複出現時,
就該思考是否有什麼方法可以彌補這一點。
⑤.取消多餘行數/添加符號空格。
這一點如果你之前習慣使用成熟的編譯器可能無法體會,
但在指令碼編程中,
符號是否有空格就決定了其旁邊的變數名是否可以被搜尋到,
也就決定了是否可以使用Ctrl + H來重新命名。
要知道指令碼語言大部分無法被Refactor。
成千上萬行的指令碼,如果無法使用Ctrl+H來重新命名,
那修改代碼的效率自然可以想象。
至於行數的作用,
最主要的就是分隔功能塊。
如果這一點無法保證,
那代碼注釋再多也無濟於事。
⑥.添加/取消注釋。
之前你跟我說My Code的注釋太少,
我承認這一點。
在一個人編程的時候,
我並不太過在意注釋問題,
因為我崇尚一條真理:
——最好的注釋就是沒有注釋。
為什嗎?
因為將所有注釋應該寫明的東西,
用完整的命名,有條理的順序,以及規範的格式就可以表現。
脫離這一點,
試圖使用注釋來彌補其他方面的弊端,
那自然是欲蓋彌彰。
除此之外,
代碼中盡量不要出現中文,
這也是成熟團隊的一個預設標準。
-----------------------------
這隻是一個檢驗,
我並不只是想看看應試者是否能夠"實現"什麼東西,
更重要的是希望看到你們如何來"實現"。
你們每個人並不是對Unity都非常瞭解,
正因如此,
類似as關鍵詞的使用或是介面選擇之類的問題我並未列在上述表單之中。
但編程能體現的是一個編程者對於程式的理解,
以及他的經驗。
功能在我看來是最簡單不過的東西,
一個功能,研究一天,一星期或是一個月一年總該有結果,
但實現的過程,
卻並非一朝一夕可以完善的。
團隊編程最重要的就是相互之間的默契,
而代碼,就是程式員之間的交流語言,
一注釋一空格之間就足以表明諸多要素。
我自己熱愛編程,
每次編程都能夠樂在其中,甚至大多數情況都無法自拔。
因為我將編程的過程看作是寫詩,
如何去構造,如何去描述,如何選詞酌句,
都是需要大量的實踐與思考才能至善至美的。
在這個過程中,
我可以很明顯地可以感受到沉浸其中所帶來的快樂的。
拋開這一點不提,
程式員最討厭的莫過於Bug。
而絕大多數的Bug並非在於邏輯錯誤,
而是在於編程規範。
如何減少Bug,
也是編程水平提升的重要一步。
至此,
再次為我遲到的回複致以歉意。
並推薦幾本書,供你日後編程作為參考:
《Clean Code》
《Refactoring To Patterns》
《敏捷編程系列》
更改後代碼:
using UnityEngine;using UnityEditor;using System.Collections;public class MapGenerator: EditorWindow {/// <summary>/// The height of the meta prefab./// </summary>int prefabHeight = 1;int prefabWidth = 1;const int horizontalNumber = 8;const int verticalNumber = 8;/// <summary>/// The map array./// </summary>public Object[,] mapArray = new Object[verticalNumber,horizontalNumber];[MenuItem ("MyTools/MapGenerator")]static void Init () {MapGenerator window = (MapGenerator)EditorWindow.GetWindow(typeof (MapGenerator));window.Show();}void OnGUI () {// setting of prefabGUILayout.Label ("Basic Settings", EditorStyles.boldLabel);prefabHeight = EditorGUILayout.IntField ("PrefabHeight:",prefabHeight);prefabWidth = EditorGUILayout.IntField ("PrefabWidth:",prefabWidth);EditorGUILayout.Space();// the area of map editorGUILayout.Label ("MapEditor", EditorStyles.boldLabel);for(int j = 0;j < horizontalNumber;j++){EditorGUILayout.BeginHorizontal();for(int i = 0;i < verticalNumber;i++)mapArray[i,j] = EditorGUILayout.ObjectField(mapArray[i,j],typeof(Object), true);EditorGUILayout.EndHorizontal(); }EditorGUILayout.Space();// the area of buttonEditorGUILayout.BeginHorizontal();if (GUILayout.Button("Create"))Create();if (GUILayout.Button("Reset"))Reset();EditorGUILayout.EndHorizontal();}private void Create(){for(int j = 0;j < horizontalNumber;j++){for(int i = 0;i < verticalNumber;i++){if(null == mapArray[i,j])continue;assertNull(GameObject.Find("Tile" + j + i));Vector3 pVector = new Vector3(i*prefabWidth, (horizontalNumber-j)*prefabHeight, 0);generateObject(pVector,j,i);}}}private void Reset(){prefabWidth = 1;prefabHeight = 1;for(int j = 0;j < horizontalNumber;j++){for(int i = 0;i < verticalNumber;i++){if(null == mapArray[i,j])continue;assertNull(GameObject.Find("Tile" + j + i));mapArray[i,j] = null;}}}/// <summary>/// Generate object and assign some properties/// </summary>/// <param name='pos'>/// Generate position./// </param>/// <param name='h'>/// Index of height/// </param>/// <param name='w'>/// Index of weight./// </param>protected void generateObject(Vector3 pos,int h,int w){Object obj = Instantiate(mapArray[h,w],pos, Quaternion.identity);obj.name = "Tile" + h + w;(obj as GameObject).transform.localScale = new Vector3(prefabWidth,prefabHeight,1);}/// <summary>/// Asserts the gameObject is null./// </summary>/// <param name='gameObject'>/// Game object./// </param>protected void assertNull(GameObject gameObject){if(gameObject)DestroyImmediate(gameObject);}}
By Elezor 2013.8.24