unity如何寫出前後端通用的代碼?

如題,unity官方好像搞過一個network的項目,前後端可以一起寫,願望是美好的,如果這樣將減少很多前後端交流成本,加快開發速度,但是目前好像還不能實現,如果伺服器端需要對客戶端的數據做檢驗,比如碰撞這類的,服務端需要實現剛體組件的功能嗎?有更好的不用重寫unity已經實現的功能的辦法么?


謝萬士辰邀,我的觀點是不要圖簡單,對某平台依賴越來越深,盡量保持全棧技術可以拆分拼接,避免從上到下深度依賴一套。哪天有個環節不適應你就痛苦了,換又不是不換又不是,越走越遠,越用越窄。

如果我只會C#和unity,我網路部分寧可廢點神找其他的具體c#的網路庫。好歹保持點自立根生的能力,別越用越退化了


占坑,先說說現狀,以後細答。

============================時間2017年6月10日============================

現在,我們團隊正打算用類似UNet的方案,這周,我用這個方案寫了個小Demo。

Demo的玩法是多玩家在同一個場景內採集資源、互相攻擊、自我增益等等,主要是為主體遊戲驗證同步方案。

實現起來涉及到的框架功能如下:

1. 創建房間

2. 建立連接Peer

3. 創建、同步網路數據對象NetworkPlayer

4. 由NetworkPlayer創建本地對象

5. 使用SyncVar同步屬性(Host擁有修改許可權,Client僅能定時接收到同步)

例如HP

6. 使用NetworkTransform方案同步屬性(Client有修改許可權,並同步給Host及其他Client)

例如Position

7. Client使用Cmd調用Host邏輯

例如使用道具

8. Host使用Rpc調用網路對象邏輯,並下發至所有Client上的對應網路對象

例如使用道具成功

9. Client對Host發送Message

例如請求LocalPlayer所在位置的地圖數據

10. Host對指定Client發送Message

例如返回對方所請求的地圖數據

那麼,在寫起來的時候是什麼一種感覺呢?

早上起床,我對著鏡子刷著牙,然後開始認真思考自己是LocalPlayer還是RemotePlayer,我現在刷牙這麼認真,會不會不同步出去,如果不同步出去我豈不是白刷了。

寫代碼時感覺要精分,上一行是Host,下一行可能就是Client了,上一行是Local,下一行可能就是Client了。

實際書寫碰到的不習慣:

1. 整條工作流非常長

相當於在C/S架構中,同時寫Client、Server並且制定協議,在寫Client的過程中還需要寫Local、Remote,再往後還有View層的相關表現,導致一個功能的實現可能需要同時編寫6個以上的文件

2. 在收發Cmd/Rpc、修改SyncVar時,需要腦子清醒

考慮自己是Host還是Client,是否有許可權做相關操作

考慮自己是Local還是Remote,分別做什麼樣的處理

3. 在即是Host又是Client的情況下,代碼共用所導致部分變數共用,部分代碼寫起來很猥瑣,例如:

bool isA = false;
void A()
{
if(isA) { return; }
isA = true;
RpcOnA();
}
void RpcOnA()
{
//BUG!!!!如果是Host的話,isA此時為true
if(isA) { return; }
isA = true;
//Do Something
}

//正確打開方式
void RpcOnA()
{
if(!isHost)
{
if(isA) { return; }
isA = true;
}
//Do Something
}

分析原因:

-&>1. C/S架構的工作流是,前後端先定介面,再寫各自的邏輯,而現在我的Demo是前後端同時、同一個人寫,所以工作流顯得長

-&>2. 由於共用代碼的緣故,工作流是前後端同時寫,導致思維混亂,實現起來完全可以避免

分析好Host/Client的功能、介面

在初始的時候就就行Local/Remote的區分初始化、包括分支處理。

-&>3. 無解,除非不存在isHost isClient的情況,由於C/S的架構本身就是前後端分離,所以不會有這種問題。

使用建議:

1. 實現做好結構分析、設計

2. 分離出數據、邏輯、表現

3. 數據:確定Host、Client的持有、同步需求

玩家們的背包數據在Host,每個Client擁有自己的背包數據,之間需要進行數據同步

4. 邏輯:確定Host、Client的職責、許可權、交互介面

對背包的增減需要授信,所以邏輯在Host,同時對Client進行數據變化的推送

5. 表現:根據需求針對網路對象,在初始化期間進行對應表現邏輯注入

LocalPlayer注入至HUDPlayer,RemotePlayer注入至RemotePlayerManager

相同的事件,兩邊對進行不同的表現邏輯處理。


摻和一下。我覺得吧,這個問題問的,以及已有的諸多回答,思路上都是有問題的。

你是使用語言和環境來構建產品,產品才是核心,而不是為了編碼特性(方便、通用之類的)來為產品選擇技術方案。

Unity提供的網路庫能不能用?能,但是這玩意得看你需求,你想拿來做個moba或者mmo我勸你還是算了。你要是搞個卡牌什麼的,自己寫一套或者網上找一套基於C#標準實現的網路庫也都很簡單,複雜的mmo當然最好還是上C++。伺服器簡單記個排行榜分數什麼的,那還是用人家直接提供的快。

至於什麼碰撞啊,物理啊,想在伺服器端重用unity組件,都是有代價的,性能也好,部署也好,可能都會很麻煩,這也得看你需求,你後台跑windows server,用c#寫一個伺服器,驗證沒有實時性要求,也不是不能用。單純的問如何達到代碼通用沒有意義,很可能你為了代碼通用做了一堆功夫,還不如自己寫個簡單的碰撞系統來的簡單(大部分遊戲其實只需要計算剛體是否碰上,沒啥實際物理要求)

歸根結底,得先把你產品想清楚了再來選擇。


雖然這是一個很蠢的提問(不要問我為什麼了)。我就文不對題吧。

部分代碼通用可以考慮腳本語言,比如lua。

本來讓服務端直接用c#是最正常的方案,但是c#是封閉語言,確實有限制,這點挺無可奈何的。總之就是現在unity客戶端很難直接用同一語言,只能用嵌入語言或者代碼翻譯器(不知道有沒有)

浮點誤差確實無法避免,雖然大部分浮點誤差是使用不當造成的,但即使正確使用,不同設備上還是可能會有一點點誤差(小數點最後一位)

但這點誤差有很多辦法可以消除,也不是就非得改成整型。整型呈現的時候還是要換算成浮點,定期將浮點數據取下有效數字,可能性能還好一些。

而且上面說這種誤差是極小概率事件,是在實際運行的網路日誌中發現的,大部分情況對遊戲毫無影響,可以考慮無視。


關鍵字,Photon engine,有提供基於UNet的實現。

詳情不清楚,我用的是nodejs。題主自行研究下。


Unity確實可以寫前後端通用的代碼,我之前做個一個卡牌類手游就是這樣做的,不過官方的Network以前功能限制很大,現在雖然改進了一些但是在國內還是面臨延遲等各種問題,基本還是沒什麼人用的。回到題主的問題上來,我以前在Unity4.x時代是用uLink來做前後端通用的代碼的,前後端戰鬥邏輯計算用一套通用演算法,只是發送用戶操作的數據。至於剛體碰撞這些肯定是不用操心的,既然後端也是unity開發的,在伺服器端也都是有剛體碰撞這些組件的,不需要重寫,實際上題主仔細學下官方的network思路就知道了,同樣的人物、NPC,在伺服器端一般只是比客戶端少Render之類的表現層的東西,最後build為不帶圖形界面的後台運行程序就可以了。真的感興趣的話可以了解一下uLink,現在5.x時代還是可以用的,他完全按照官方的思路進行了拓展,加了uLobby等很多專業網路架構的模塊,會比直接用官方的好很多。


不太現實。主要問題是市面上還沒有任何物理引擎是消除了浮點數誤差的,也就是會有可能造成不一致,如果物理部分自己實現,應該是可以的,之前做過戰鬥用lua寫 可以兩邊通用的,也可以用c寫,王者榮耀似乎用的是這個方法實現的幀同步,達到多個客戶端跑一套代碼和數據得到同樣的結果


用c++來寫後端的邏輯。

然後復用這些c++代碼作成類庫作為plugin提供給unity3d前端。相當於不要用c#來寫邏輯。

優點:基本上遊戲核心邏輯是一套代碼

缺點:調試不那麼方便/C++開發成本比較高


模塊化,我正在設計一套MMORPG客戶端服務端通用模塊,common.dll dbdata.dll clientmsgpack.dll 大致分為基礎組建類庫,_比如位元組流寫入,讀取類,編碼轉換,日誌,常用演算法.crc16,md5,tcp客戶端服務端,, 配置文件類庫,讀取通用的遊戲配置文件,如地圖信息,怪物,npc配置文件。 封包協議庫,定義客戶端與服務端通訊協議結構。 資料庫結構類,如角色資料庫信息,角色背包,技能數據,腳本lua tabel序列化個人變數。 現在暫時分了這麼多通用的類庫,,還引用了大量的開源庫,execl.log4. fastsocket .lua。踩了坑後再補充。


我的做法是spawn的時候判斷是不是host,如果是host我給他創建一個brain不是的話brain就是null。brain由gameobject負責tick,進行邏輯計算。brain會對gameobject操作,而這些操作除了對本身的gameobject起作用也會通過unet同步給其他客戶端。而gameobject的回調比如動畫事件通過我自己寫的eventsystem調用brain相應註冊的方法,而這些事件註冊是在brain創建的時候註冊的,當然如果是沒有brain的gameobject這些消息發出來是沒人接受。這樣寫你就不用精分了。


根本沒有這個必要。前後台本來目的差別很大。非要強行弄成通用的,有點捨近求遠的感覺。


我也在找這樣的東西,Unity應該把它的代碼做成多種編程語言的包,可以嵌入別的伺服器。

如果用第三方物理引擎自己寫剛體組件,2d的大概可以用box2d,3d的不清楚。

如果物理演算法也自己寫,不用擔心浮點數誤差,我就是自己寫物理演算法,伺服器用Java,客戶端用C#,甚至伺服器用的double類型計算,客戶端用的float類型計算,還沒來得及改成一致的,都沒見過因為誤差導致前後端結果不一致,前後端計算結果不一致都是因為程序bug導致計算的過程不一樣而產生的。


推薦閱讀:

Unity asset store有哪些值得購買的插件?
獨立開發者要不要從unity轉到ue4?
用MonoDevelop寫代碼有什麼提高效率的竅門?
學習UNITY3D有一段時間了,想獨立做個遊戲(找工作用於展示),沒有素材和思路怎麼辦?
為什麼unity只有將數據序列化之後才能顯示再Inspector面板上?

TAG:Unity遊戲引擎 |