1. 程式人生 > >Unity-Slua使用MVC設計思想開發2D遊戲

Unity-Slua使用MVC設計思想開發2D遊戲

        架構是神奇的,為解決需求頻繁變更可以更好的應對。設立規則,開發人員共同去遵守,約定俗成,從而完成一個維護性強的產品;架構也是抽象的,將設計模式作為元件實現一個高內聚、低耦合的適合於產品的流程。         設計架構是為解決某種問題而生的,最重要的還是思想。筆者今年有幸的接觸棋牌行業,使用Unity開發2D手遊。為了熱更,我們公司選用了SLua。公司原本有同事來解決了C#讀取Lua的一系列流程,但是我們在開發遊戲時候,大部分接觸是Lua,開發好遊戲以後維護性低,可複用性程式碼幾乎很少,造成了做新遊戲的時候並沒辦法沿用以前的專案。鑑於此,我們希望重新設計來把專案鬆耦合,達到可複用,這裡我們只是為了解決自己開發的問題而設計的架構,也可以叫約定俗成的流程。下面講述我們推導為解決問題而設計的架構。         在最早開發的時候,我們是每個Lua指令碼實現自己的功能,裡面充斥著大量的全域性變數,查詢bug的時候要去查詢全域性變數的宣告和呼叫;還有包括資料和檢視都是在一個文字內,方便了開發,隨時拿來用,可是一個指令碼任務過重,導致出現一個文字大量的邏輯,呼叫各個模組的變數;同時我們發現,在下一個遊戲中,很多資料是沒有變化的,只是顯示的不同。那麼最大的任務就是將資料從檢視的程式碼分離出去,達到資料可複用。那麼這需要分步驟去解決:         1、一個指令碼可以操控各種各樣的檢視並不合適,違反單一職責原則,由此我們將檢視分離出去,按照場景預製體的形式將包括設定、遊戲、大廳等等檢視分離成一個個的指令碼。為了查詢bug精準,我們把全域性變數設為私有變數,將每一個檢視全部作為獨立檢視處理。由一個管理器管理所有檢視。         2、將檢視中資料從檢視呼叫中分離,資料單獨放一個地方為檢視服務。也全部設定為私有。封裝後,變數受到保護,只有自身修改的許可權         3、將伺服器訊息傳送和接收的指令碼與資料互通,達到伺服器回傳先在資料更新,再傳出。         這解決了資料與檢視混雜到一起的問題。但是檢視全部獨立以後,有些檢視並不是獨立,該怎麼辦?檢視訊息怎麼傳遞?資料如何與檢視打交道?         有些檢視並不是獨立,有些檢視有包含和被包含的關係。有點類似於樹一樣,有根有枝,枝上有葉子。鑑於此,採用了設計模式中的組合模式,來達到檢視組合的效果。而有很多檢視都有顯示,隱藏,更新等功能,對於重複性的程式碼,我們設計了檢視介面。所有檢視都是檢視,所以都繼承(Lua中是以元表實現)於檢視介面:IView。那這個介面有什麼呢?需要做什麼呢?          首先:檢視需要一個識別符號,來達到檢視互相呼叫,那麼這個識別符號我們選用了name,那麼需要一個方法即是繼承效果,而且具有name欄位。通過元表,我們模擬了New方法,構造一個表,來用name標識每一個檢視。          其次,我們有些層級高的檢視需要有很多孩子組合起來達到這個檢視整體效果,需要有Add方法來儲存自己孩子,以便更新時候可以控制子檢視。那麼有Add就要有Remove。但是每一個檢視都有顯示隱藏,更新等功能。由此提取到介面,都通過識別符號來達到此效果。          當檢視組合完成,我們發現我們沒有地方去傳送請求來處理我們的邏輯。那麼這是檢視公有,就提取到介面,建立Request。由此介面和檢視層採取組合模式,完成檢視內部互相呼叫,單一職責原則,耦合性明顯降低。          下面我們就需要處理資料了,資料是唯一的,檢視是顯示資料的,所以資料是核心。最初我們並沒有重視,將資料只設計一個View處理資料類,來處理各種各樣的資料。那麼如何訊息傳遞呢?         我們採取了訊息廣播的形式作為訊息傳遞的媒介,專門有一個指令碼在資料和檢視之間傳遞資料。然後我們就出現了問題:檢視和資料需要判斷各種各樣的訊息型別(字串),冗長的if判斷造成了無法修改的局面。比起以前隨手呼叫全域性變數的時候沒好到哪裡。這麼多的資料混成一團,反而有種煮飯一鍋煮的感覺。除錯bug的時候,我們需要翻幾千行程式碼來查詢。於是我們不得不去想,這些資料處理自己有自己的功能該多好?我們把處理資料的每種型別分離出來,例如打牌的、個人資訊的、房間資訊、任務等等N多模組,這個時候體現了單一職責原則的強大之處。          處理資料的模組有了,檢視有了,我們發現沒有一個指令碼是協調的,如果沒有,如何連線那麼多模組共同處理一個訊息呢?我們設計介面並不合理,那麼需要一箇中間層,達到互相協調的目的。由此引入了一個模組,做協呼叫。這個模組接收檢視層訊息,連線各個處理資料的模組來連線。可是這個協調模組怎麼設計呢?需要做什麼呢?          首先,它需要傳遞檢視的訊息,然後連線處理資料的模組來完成我們的邏輯。可是檢視哪知道有多少處理資料模組,自己也沒持有引用,或者暴漏的方法讓我知道?那麼多處理資料模組呼叫哪個才能處理?由此我們引入了設計模式:策略模式。我們可以隨時替換協調模組,來完成不同的協調功能。那麼我們需要檢視對於協調的緊密聯絡,來決定使用哪個協調器。那麼協調器就有了公共的方法:接收檢視訊息。由此,抽離成介面,供各個協調器使用。那麼這些協調器都屬於協調模組,我們將這個介面作為基類,被協調器繼承。          其次,協調模組,既然是處理邏輯的,勢必要知道有多少處理資料的模組,這些模組就需要將自身暴漏方法呈現給協調器。那麼又有了一個公共方法:協調器需要得到不同的模組。這裡需要得到各個處理資料的模組?可是通過什麼識別呢?          處理資料的模組都是私有封閉性,我們處理資料的模組不相互呼叫,怎麼在更新自身時候先知道其它不屬於自己的資料但卻屬於整個系統的資料呢?處理資料的模組到現在仍然是一盤散沙。我們也需要得到其他模組的資料,以便供自己使用呢。這不就是個公共方法:還要抽離成介面;那麼各個資料的模組怎麼識別不也是公共方法?也分離到介面。處理資料的模組就有了自身的基類。          到此,檢視通過組合模式完成檢視的相互協調,資料通過自己基類完成各個模組更新和相互協調。而兩者勢必需要協調,協調模組應運而生。檢視通過策略模式來與協調器打交道。這裡我們發現一個問題?那資料怎麼去傳遞到檢視?檢視請求協調器,處理完邏輯之後檢視怎麼知道?要知道,處理資料模組,協調模組全都是為檢視服務的。這裡我們引入了設計模式:觀察者模式。資料一旦更新,被觀察者需要被通知到。我們通過Lua訊息廣播機制,去通過註冊監聽的模式,完成了鬆耦合的傳遞訊息。那我們在檢視請求協調器的時候,也用這種好嗎?這裡自己思考一下就無法去想下去了,這樣肯定不行。我們由此引用了面向物件的思想:回撥函式。將一個方法在訊息中傳遞,有協調器處理完後返回這個結果。          這樣,我們為解決檢視與資料混雜在一起,全域性變數隨手呼叫造成的高耦合的問題解決了。而這個設計思想就是幾十年經久不衰的MVC設計思想。我們通過這個設計思想理一下思路:檢視層V是通過組合的模式,拼裝成了一顆參天大樹。資料層M為檢視層留了各種各樣的資料處理方式。為了鬆耦合,我們使用協調模組:控制器C來協調它們兩個,並處理邏輯。

        本人扣扣群:478462732。歡迎大家來交流技術