1. 程式人生 > >Unity客戶端設計系列

Unity客戶端設計系列

對於遊戲開發而言,不同種類的遊戲其架構方式都不同,並不存在什麼完美架構模式某種型別是可以有分別的框架的,比如上帝視角ARPG,比如GAL,比如格鬥,比如跑酷,比如卡牌,比如打飛機遊戲。而他們使用的遊戲架構自然也是不同的。通常來說遊戲專案最合理的方式是由一個主程根據專案需求制定一套新的結構和各部分間的依賴關係,事先想好各個部分的拓展和通訊方式。有了這個過程,也就沒有硬是生搬硬套的再去套用什麼模式(MVC之類).
一、一定程度上的邏輯程式碼的分離,提高程式碼的可維護性和 可重用性。

我對Unity 程式碼結構組織的困惑 ,經過各種查閱 ,發現其實主要是對於MonoBehaviour 上。mono必須是可是化的,要綁在GameObject上。 對於mono只做視覺上的效果,比如視覺上的特定效果(攝像機振動,飄血,特效,道具掉落,buff類),振動,變色,控制動畫,賦值點(控制行為引數資料),控制好它們的依賴,讓他們擁有通用性(比如道具掉落的動畫,UI動畫等),然後這些就不用再開發邏輯的時候去處理這些東西,可以丟一遍了。 而遊戲的主體是一個空GameObject 上的指令碼,它負責管理所有,分發事件。 其他的地方就不要出現MonoBehaviour了。

這樣處理的理由在於生命週期。 mono必須能看到,而邏輯往往會脫離於顯示部分,GameObject 未建立往往就需要有邏輯了。 也就是是說你建立一個人物,因該先建立一個MonoBehaviour類,然後在這個類的初始化程式碼裡建立一個GameObject 然後再套上各式MonoBehaviour,然後依然在這個非MonoBehaviour類處理定時邏輯和其他(定時邏輯,比如技能釋放,我釋放一個技能,由一個技能發射類管理這個技能特效的時效性)。需要時再控制下其他MonoBehaviour播放動畫、控制效果之類。 這就和其他非Unity遊戲架構沒多大區別了。

對於MonoBehaviour的邏輯分離的一個理由在於,比如現在對角色進行控制,使用Character Manager、Controller (也可是說是FSM 、或者Behaviour Tree),來進行角色狀態間的控制,將它放在角色obj上。那通常只能是人物資源的那個GameObject。那麼我有個需求是換狀態的時候切換為完整的另一個資源,那麼要不是Compent複製要不是建立子級GameObject,無論哪個都不太好吧。

   或者,我想隱藏這個人物,包括裡面的動畫啊和純顯示用邏輯,但是基本邏輯又想留著(否則什麼時候才能恢復顯示?),本來直接將GameObject禁用就好了,現在這樣就不行了。或者說,它雖然有狀態,但並沒有顯示,而是一個虛擬物件。但如果它不是MonoBehavior就沒有任何問題了。這就是我所說的使用MonoBehavior的隱患,其實很多人心中都默默的有這樣的感覺吧?這個隱患也是確實存在的。

   當然我也不是說MonoBehavior就完全不能用,比如受創變色(切換以及根據color對所有Renderer賦值以及恢復為原材質)肯定是可以的,還有什麼動畫順序播放,部件繫結。但是涉及到邏輯的部分,真的建議排除掉MonoBehavior。它確實是毒瘤。
此外有些人不喜歡MonoBehavior是因為start發生的不確定性,還有初始化沒有建構函式不便。那你需要端正下思路。你看unity預設的那些元件,你會在乎它們哪個先初始化嗎?你會在乎它有沒有建構函式引數嗎?你不會。因為它們設計成了你不需要考慮這些東西。所以如果你寫MonoBehavior,就應該設法按他們的模式走,讓初始化無需顧忌順序引數直接賦值就能解決,而不是拋棄start awake自己搞個create。
而MonoBehavior的主要優點就在於可以獨立使用,不依賴於環境。你建個預置拖上去設設引數就能看效果。這是它最大也是唯一的優點,它編碼上的不便也都是為了讓這一點成為可能。如果你的MonoBehavior做不到這一點,或者你認為不需要,那費老大勁搞成MonoBehavior又沒用,何苦。
二 、依舊是Unity 資源組織的問題

  • Unity有一些自身的約定,譬如專案裡的Editor,Plugins等目錄作為編輯器,外掛目錄等等。知名的外掛會自己存放一個目錄,譬如NGUI等。
    所以我們自己的程式碼,一般目錄名會以下劃線開頭,譬如 “_Scripts”, “_Prefabs”等。
    對於場景,文件等目錄,用兩條下劃線,以便他們能排在最頂部。
  • 程式碼用C#,別用JS。必要的話用namespace將自己的程式碼括起來。我們是用namespace把自己積攢的公用庫包住。
  • C#的註釋要認真寫,打///就能幫你補全了,沒理由偷懶。
  • 每個程式檔案開頭要用一段註釋寫修改Log,誰改過什麼簡單留一條說明。就算用了Unity的版本管理或者Git,那些log終究會丟失,只有認真把log寫在程式碼裡,才會有意識去認真優化它。
  • Unity的指令碼邏輯,就功能而言大體分為兩種,一種是比較獨立的,譬如爆炸之後1秒鐘消失,這種單獨寫個指令碼繫結到目標上即可。
    更多的是腳本里與其它的指令碼進行互動。Unity裡提供了一種萬金油的方法是SendMessage, 這種方法效能略差,如果你呼叫的頻率不高,隨便用也無妨。另一種方法是直接通過物件的例項去呼叫。

我們的做法是寫幾個公用的控制器,讓它們各司其職,負責各自的事情:
- 寫一個一個GlobalManager.cs來控制遊戲的全域性變數及全域性方法。靜態類模式。譬如當前玩到第幾大關第幾小關,玩家的金幣數量等。
- 寫一個GameController.cs來控制當前關的遊戲程序。單例項模式。遊戲的主迴圈也是用它控制。初始化,勝利、失敗判定等等。
- 寫一個InputController.cs來控制所有的使用者輸入。單例項模式。滑鼠、鍵盤、觸控式螢幕,我們做遊戲是保證同時支援這三種輸入的,因為大部分時間是在PC上測試。
關於GameController與InputController的聯絡,有點讓人糾結。一般來講是在InputContoller裡呼叫GameController.Instance.Foo()執行方法。或者直接對Input寫成Listener的模式,讓GameController去監聽。
- 其它的類似選單控制器,聲音控制器,成就控制器,IAP虛擬道具控制器等等,也是採用類似的方法管理。
- 關於PlayerPref的操作,統一寫成靜態類的get/set模式,程式中哪裡要用則直接讀寫。
- 如果你的專案裡場景的數量少(<5),那麼拖入場景的資源可以很隨意。如果場景數量很多(幾十個,有的解謎遊戲每個關卡就是一個場景),那麼拖入場景的prefab數量一定要少。
- 設計你的prefab資源裡,你要想像當其他人拿到這些資源,是否直接拖入一個空場景裡就能run,頂多再簡單設定幾下。如果你設計的資源不能做到這些,那麼得好好重新想想。

1.邏輯指令碼基於場景劃分
2.抽離靜態配置資料、全域性管理資料以及對局臨時資料的管理
3.使用單例模式建立不依賴於場景的遊戲物件及其上的全域性管理器
4.避免使用GameObject.Find以及SendMessage,宣告物件引用以顯示標明指令碼之間的依賴性,活用delegate解耦合
5.多用組合少用繼承(Component的架構真的是太棒了)
6.資料行為與邏輯表現分離,即V與MC的分離,換句話說多寫class少寫MonoBehavior。(通常初期在快速開發原型時會把一個功能全部實現寫在一個繼承於MonoBehavior的指令碼中,儘早進行重構,抽離出負責資料管理與控制的類,這對於後期功能的增加與修改時很有必要的)
7.善用Coroutine(Coroutine真是太方便了)
8.儘量能夠使用自定義的配置檔案輔助Prefab上指令碼引數的配置。

總的來說記得知乎上看到誰說過cocos2d是程式設計師友好的,而Unity3D是設計師友好的,寫了這麼多年Unity3D程式碼我真是覺得我的思考方式越來越像策劃而不是程式設計師了,使用Unity3D開發,寫程式碼應該只佔了大概50%的工作,另外50%都在編輯器上,如果你用過相信你懂得。

unity是基於元件開發 一上來確實不太適應,也跟同事討論了好久,至今沒什麼太好的結論。說下我們的方案,
一.啟動場景一個 object上掛指令碼主入口,他負責驅動遊戲內所有manager的建立,更新及銷燬。
二.人物,AI等需要繼承的通過持有gameObject來是實現。而不是掛載到gameObject上。
三.基礎功能通過元件實現。掛載到gameObject上。(邏輯表現分離)
總體上就是最基礎層面 負責具體功能的用元件來降低耦合度,這樣也清晰。而一些需要始終存在的或者需要繼承則通過原來的方式,建立指令碼物件,然後持有Object,這是這個object不在負責具體邏輯,只是各個基礎功能的總和。

有句話,我總會仔細的跟很多朋友講到
做遊戲,牛逼的不是實現某一個功能,而是把成百上千的功能放到一起,卻不亂。

而我認為,這條路,必須自己不斷總結反思。別人給的經驗,往往並不一定合適具體的專案。
不管別的,有幾個標準可以檢驗你的程式碼是否合理

1:美術資源 提交後,策劃配表提交後,不需要程式變換,即可立馬看到結果。 比如,一個圖示變了,美術可以打包圖集,提交。 策劃變了一個配表,他可以直接提交配表。 一個新的怪物出現了,讓美術自己提交怪物資源….. 最後他們自己跑遊戲裡一看,發現東西是OK 的。
不管你程式如何設計,這事是最重要的一條。 簡單來說就是 讓美術和策劃能夠提交後直接看到結果。

2:遊戲暫停時,能否直接通過 檢視視窗,看到儘量多的遊戲當前狀態。
以我做的ARPG為例,
再某一下,我一刀揮出去,打到一個怪物了。 再怪物受擊的那一瞬間,我點選暫停。
這個時候我點選怪物這個GameObject,可以看到怪物當前正在播放那個動畫,重力是多少,重力加速度是多少,受擊的效果有哪幾個,數值分別是多少… 可以通過檢視視窗看到當前怪物移動元件是否使用中,AI 元件是不是被停滯掉了
………
這個點是存在爭議的,諸多從C++過來的朋友,cocos寫得多的朋友。並不習慣元件化這樣的東西

3:是否一個類只幹一件事
這個同樣很重要
甚至可以說是需要被確保的。元件化或許這點有些爽。就是基本確保了你寫的某個元件只幹一件事。

相關推薦

Unity客戶設計系列

對於遊戲開發而言,不同種類的遊戲其架構方式都不同,並不存在什麼完美架構模式某種型別是可以有分別的框架的,比如上帝視角ARPG,比如GAL,比如格鬥,比如跑酷,比如卡牌,比如打飛機遊戲。而他們使用的遊戲架構自然也是不同的。通常來說遊戲專案最合理的方式是由一個主

關於客戶設計之數據分類和存儲 的思考

service his defaults def sqli href 思想 number fault 一、關於數據的分類 在Android 客戶端設計過程中,我將數據分為未知,已知(本地),臨時,三者之間根據需求相互轉化。 未知主要來自用戶輸入和服務端輸入。 已知主

經測試,unity客戶發送消息給服務器,然後服務器控制PLC的方案完全是可行的!

服務 png 方案 plc 技術分享 cnblogs http mage .cn 1.unity 2. 3. 4.服務器: 5.PLC 博圖軟件: 6. 7. 8. 9. 手機測試,沒問題。經測試,unity客戶端發送消息給服務器,然後服務器控

搭建unity客戶

layout photo tom listener 普通 ngui 客戶端程序 protoc clas 1.新建個unity的項目ChatClient 2.在unity的Main Camera下掛載個腳本PhotonServerEngine做為與服務器端通信的腳本

unity客戶自動斷開連接

連接服務器 div 默認 true ont gpo 時間 宋體 情況下 問題描述: 當unity失去焦點一段時間後,與photon服務器端斷開連接 問題根源: 默認unity失去焦點後會暫停運行,導致連接超時,服務器端超時斷開連接 解決方案: 連接服務器後,填加一句代碼讓u

Unity客戶框架筆記二(元件實體開發模式的思考)

https://blog.csdn.net/langresser_king/article/details/46324977 Unity客戶端框架筆記二(元件實體開發模式的思考) 2015年06月02日 11:40:13 langresser 閱讀數:4315更多 個

Unity客戶常見面試題(收集的)

一、什麼是渲染管道? 是指在顯示器上為了顯示出影象而經過的一系列必要操作。主要步驟有:把物體從本地坐地轉換到世界座標->檢視 座標->剪裁空間->投影->檢視變換->光柵化(alpha測試、模板測試、深度測試)->寫到幀緩衝區(frame buffer)  

Unity 客戶網路架構 生產者消費者模式

假設我們的資料包是這樣的結構 [Serializable] //序列化物件 [StructLayout(LayoutKind.Sequential, Pack = 1)] // 按1位元組對齊 public class UserMsg {     public int me

Unity客戶框架

自己作為主力開發的第一個Unity專案已經進入尾聲測試階段了,雖然資料還沒有完全達到要求,但是從程式碼層面上看,有很多地方已經可以進行總結和整理。不管專案最終結果如何,在整個開發過程中,自己還是收穫頗多。當然有收穫更有教訓,回頭想想,感覺最大的一個問題就是

unity客戶程式筆試後有感(一)

參加了三七互娛的線上筆試之後,學習良多,特來分享。第一題、unity指令碼的生命週期函式有哪幾個?作用分別是什麼?答:Awake():喚醒事件,只執行一次。OnEnable():啟用事件,只執行一次。當指令碼元件被啟用的時候執行一次。Start():開始事件,只執行一次。Fi

Unity客戶架構-DialogInfo

using UnityEngine; using System.Collections; using System; public class DialogInfo : BaseDialog {

Unity客戶架構-Util

using UnityEngine; using System.Collections; using System.Collections.Generic; using System.Globalization; using System; using Syst

Unity 客戶框架(六):UI框架

public abstract class BaseUI : MonoBehaviour { #region 快取 private Transform _CachedTransform; public Transform cachedTransform

語音助手的安卓客戶設計

一、開發環境配置本論文選用科大訊飛開發平臺提供的語音合成和語音識別技術,完成語音助手軟體的開發,最終在安卓手機上正常執行。在win10完成,使用android studio開發編譯,軟體測試機器為魅藍n

Netty4(三)多連線客戶設計與實現

本文介紹多連線的netty客戶端設計 目標 UML類圖 實現 測試 目標 Netty(二)一文中實現了單連線客戶端,也就是說客戶端只有一個連線,這就不利於高併發RPC的設計,本文嘗試設計一個多連線的客戶端,支援斷線重連

表演的藝術,妖尾回合制戰鬥系統客戶設計

妖尾歷經幾年開發,終於在今年6月底順利上線,筆者從2017年初參與開發,主要負責妖尾戰鬥系統開發。戰鬥作為遊戲的核心玩法系統,涉及很多技術點,希望能借幾篇文字,系統性總結MMORPG戰鬥系統的開發經驗。 本文主要從巨集觀層面總結回合制遊戲戰鬥的美術資源規範,系統框架設計和主要技術點,比如斷線重連,技能表

WCF系列教程之客戶異步調用服務

1.5 void 添加引用 dsl idt pan important 配置 但是 本文參考自http://www.cnblogs.com/wangweimutou/p/4409227.html,純屬讀書筆記,加深記憶 一、簡介 在前面的隨筆中,詳細的介紹了WCF客戶端服務

(轉) 淘淘商城系列——使用FastDFS-Client客戶進行上傳圖片的測試

row 構造方法 無法 空間 依賴 ron 文件下載 信息 utils http://blog.csdn.net/yerenyuan_pku/article/details/72804018 不久之前,我們實現了商品的類目選擇這個功能,但這只是萬裏長征的第一步,我們還有很

tcp 服務客戶程序設計

cti ida ons uint8_t 文件 數據 開頭 ews 信息 一、實驗目的 學習和掌握Linux下的TCP服務器基本原理和基本編程方法,體會TCP與UDP編程的不同,UDP編程:http://blog.csdn.net/yueguanghaidao/articl

Redis 設計與實現(第十三章) -- 客戶

腳本 ons listening last then red logs 可能 reply 概述 對於每個與服務器連接的客戶端,服務器都為它創建相應的redisClient的數據結構,並保持了相應的狀態。Redis Server通過一個鏈表來保存所有的客戶端連接。 本章包括: