ue4多人联网的实例
?
一.聯(lián)機游戲通用概念
1.多人游戲類型
| 回合制游戲(棋盤) | “不做要求” | 協(xié)商(限制較少) | 高 | 有限(需自實現(xiàn)) |
| 基于會話的實時游戲(cs) | 需要 | 協(xié)商(<?1?hour) | 中 | 高(內(nèi)置的) |
| 大型多人在線游戲 持續(xù)世界游戲(魔獸始界mmo) | 需要 | “永久”存在 | 低 | 有限(需自實現(xiàn)) |
2.基于會話的實時游戲
- 查找
- 連接
- 同步
3.客戶端-服務(wù)器模型(Client-Server模型,C/S模型)
?
二.理解Gameplay框架?
Gameplay框架 游戲規(guī)則、玩家輸出與控制、相機和用戶界面等核心系統(tǒng)。 ——虛幻引擎4文檔
1.框圖:
GamePlay架構(gòu)的后半部分就自底向上的逐一分析了各個層次的邏輯載體,按照MVC的思想,我們可以把整個游戲的GamePlay分為三大部分:表現(xiàn)(View)、邏輯(Controller)、數(shù)據(jù)(Model)。一圖勝千言:
2.神話故事
創(chuàng)世紀
UE創(chuàng)世,萬物皆UObject,接著有Actor。
UObject:
相傳在很久很久以前,UE在一片混沌虛無,有感于天地間C++原始之氣,便擷取凝實一團C++之氣,降下無邊魔力,灑下秩序之光,便為這個世界生成了堅實的土壤UObject,并用UClass一一為此命名。
藉著UObject提供的元數(shù)據(jù)、反射生成、GC垃圾回收、序列化、編輯器可見,Class Default Object等,UE可以構(gòu)建一個Object運行的世界。
Actor:
世界有了土壤之后,但還少了一些生動色彩,如同女媧造人一般,UE取一些UObject的泥巴,派生出了Actor。
在UE眼中,整個世界從此了有了一個個生動的“演員”,眾多的“演員”們,一起齊心協(xié)力為觀眾上演一場精彩的游戲。
脫胎自O(shè)bject的Actor也多了一些本事:Replication(網(wǎng)絡(luò)復(fù)制),Spawn(生生死死),Tick(有了心跳)。
Actor無疑是UE中最重要的角色之一,組織龐大,最常見的有StaticMeshActor, CameraActor和 PlayerStartActor等。Actor之間還可以互相“嵌套”,擁有相對的“父子”關(guān)系。
Actor的概念在UE里其實不是某種具象化的3D世界里的對象,而是世界里的種種元素,用更泛化抽象的概念來看,小到一個個地上的石頭,大到整個世界的運行規(guī)則,都是Actor.
Component:
世界紛繁復(fù)雜,光有一種Actor可不夠,自然就需要有各種不同技能的Actor各司其職。在早期的遠古時代,每個Actor擁有的技能都是與生俱有,只能父傳子一代代的傳下去。隨著游戲世界的越來越絢麗,需要的技能變得越來越多和頻繁改變,這樣一組合,唯出身論的Actor數(shù)量們就開始爆炸了,而且一個個也越來越胖,最后連UE這樣的神也管理不了了。終于,到了第4個紀元,UE窺得一絲隔壁平行宇宙Unity的天機。下定決心,讓Actor們輕裝上陣,只提供一些通用的基本生存能力,而把眾多的“技能”抽象成了一個個“Component”并提供組裝的接口,讓Actor隨用隨組裝,把自己武裝成一個個專業(yè)能手。
Pawn:
在眾多的Actor中有一類可以被控制的木偶(傀儡),即Pawn,它是由Actor派生出來用來表示肉體的;在Pawn中還有一類更為特殊級即Charater,?它不僅繼承了Pawn的屬性,還擁有人形"肉體"行走的動畫等.
Controller:
光有肉體的Pawn一無是處,需要靈魂即Controller的驅(qū)使下來能發(fā)揮用處;Controller可以分為PlayerController和AiController,由PlayerController驅(qū)使的Pwan就是玩家角色,由AIController驅(qū)使的Pwan就是機器人;
PlayerState:
由于Controller(靈魂)可以附身到其他的Pawn上,所以需要有個東西去記錄,這個Pawn(肉體)或者這個Controller(靈魂)的信息,我們一般稱呼它為PlayerState(記憶).有這樣一個受持續(xù)控制的由Pawn,Controller以及PlayerState所組成的集合,就可以"為所欲為"了.
GameMode:
但是這個世界中很多東西是不可以改變的就比如說GameMode(世界的規(guī)則),尤其是在網(wǎng)絡(luò)游戲中,GameMode只存在服務(wù)器上,客戶端無權(quán)修改.
Level
在UE的世界中,我們之前已經(jīng)有了空氣(C++),土壤(UObject),物件(Actor)。而現(xiàn)在UE又施展神力創(chuàng)建了一片片大陸(Level),在這片大陸上(.map文件),Actor們秩序井然,各種地形拔地而起,植被繁茂,天空霧云繚繞,圣光普照,這也是玩家們降生開始精彩冒險的地方。
可以從ULevel的前綴U看出來Level(大陸)也確實是繼承于UObject(土壤)的。那既然同屬于Object下面的各Actor們都擁有了一定的智能能力(支持藍圖腳本),Level自然也得體現(xiàn)出大地的意志,所以默認帶了一個土地公(ALevelScriptActor),允許我們在關(guān)卡里編寫腳本,可以對本關(guān)卡里的所有Actor通過名字呼之則來,關(guān)卡藍圖實際上就代表著該片大陸上的運行規(guī)則。
在Level已經(jīng)有了管理者之后,一開始大家都挺滿意,但漸漸的就發(fā)現(xiàn),好像各個Level需要的功能好像都差不多,都是修改一下光照,物理等一些屬性。所以為了方便起見,UE便給每一個Level也都默認配了一個書記官(Info),他一一記錄著本Level的各種規(guī)則屬性,在UE需要的時候便負責(zé)相告。更重要的是,在Level需要有其他管理人員一起協(xié)助的時候,他也記錄著“GameMode”的名字來讓UE可以指派
前面我們說過,有一些Actor是不“顯示”的(沒有SceneComponent),是不能“擺放”到Level里的,但是它依然可以在關(guān)卡里出力。其中一個家族系列就是AInfo和其之類。今天我們只簡單介紹一下跟Level直接相關(guān)的一位書記官:AWorldSettings。
其實雖然名字叫做WorldSettings,但其實只是跟Level相關(guān),我猜可能是在上古時代,當時整個世界只有一塊大陸,人們就以為當前的大陸就是整個世界,所以給這塊大陸的設(shè)置就起名為WorldSettings,后來等技術(shù)進步了,發(fā)現(xiàn)必須有其他大陸了,這個名字已經(jīng)用得太多反而不好改了,就只好遺留下來了。當然也有可能是因為當Level被添加進World后,這個Level的Settings如果是主PersistentLevel,那它就會被當作整個World的WorldSettings。
注意,Actors里也保存著AWorldSettings和ALevelScriptActor的指針,所以Actors實際上確實是保存了所有Actor。
World
終于,到了把大陸們(Level)拼裝起來的時候了。可以用SubLevel的方式:
3.和網(wǎng)絡(luò)相關(guān)的部分
palyerstate記錄buff以及血量等
4.整體類圖
?
三.Unreal聯(lián)網(wǎng)游戲基礎(chǔ)
?
Unreal Engine 4使用標準的C/S體系結(jié)構(gòu)
結(jié)論一:服務(wù)器是權(quán)威的永遠不要相信客戶端
客戶端將動作或數(shù)據(jù)發(fā)送至服務(wù)器,服務(wù)器經(jīng)驗證后再做出反應(yīng)
舉幾個例子 當在多人對戰(zhàn)中作為客戶端移動角色時,實際上并沒有自己移動角色,而是告訴服務(wù)器您要移動它。
然后,服務(wù)器會為其他所有人更新角色的位置。
為防止本地客戶端出現(xiàn)“滯后”的感覺,通常還允許玩家直接在本地控制其角色,但服務(wù)器仍“監(jiān)控”并會在必要時覆蓋本地玩家的位置。
同樣的,聊天也是先將消息發(fā)送到服務(wù)器,再由服務(wù)器更新給所有客戶端。
1.簡述原理
Actor的Transform實際上是根組件的Transform,因此對Actor的同步實際上就是對根組件的同步。
在客戶端和服務(wù)器的連接后,會在連接的Socket上面建立一個個Channel,服務(wù)器上面的每一個對象都對應(yīng)著一個ActorChannel,
通過這個Channel,客戶端和服務(wù)器的Actor建立通信通道,然后會進行數(shù)據(jù)同步和RPC調(diào)用,以及發(fā)起屬性通知。
在Actor中,有一個標記bReplicateMovement被用來標記Actor是否同步,這個屬性在藍圖的屬性面板上面也有,如果標記為True,那么會進行相關(guān)的同步操作。
Actor的Transform屬性是通過一個特殊的結(jié)構(gòu)體ReplicatedMovement來進行傳遞的,里面包含了相關(guān)的需要同步的屬性,在ReplicatedMovement中的屬性值發(fā)生改變的時候,會調(diào)用OnRep_ReplicatedMovement進行事件通知。
ReplicatedMovement 僅僅是一個用來同步的中間值,并不是Actor的原始數(shù)據(jù),對Actor的Transform操作并不會直接作用于 ReplicatedMovement,
那么Actor的真實數(shù)據(jù)是怎么同步到 ReplicatedMovement然后再同步到客戶端的呢?
在服務(wù)器對Actor進行同步的時候,會調(diào)用PreReplication事件,在這個事件中會使用GatherCurrentMovement函數(shù)從當前的Actor信息填充ReplicatedMovement結(jié)構(gòu)體。
ReplicatedMovement同步到客戶端之后,會調(diào)用OnRep_ReplicatedMovement事件通知,在這個事件中,通過PostNetReceiveVelocity和PostNetReceiveLocationAndRotation來設(shè)置位置、旋轉(zhuǎn)和速度。
2.Gameplay框架在多人聯(lián)機下的劃分
Server Only:這些對象僅存在于服務(wù)器上
Server & Clients:這些對象存在于服務(wù)器與所有客戶端上
Server & Owning Client:這些對象僅存在于服務(wù)器與擁有其的客戶端上
Owning Client Only:這些對象僅存在于擁有其的客戶端上
3.UE4的廣播和同步
ue4 的Actor和ActorCompoennt和的同步與廣播都建立在上面勾選 bRelicated的前提下
復(fù)制是服務(wù)器將信息/數(shù)據(jù)傳遞給客戶端的行為。
參與復(fù)制的最基礎(chǔ)的類是AActor 類繼承于AActor后,使它們能夠根據(jù)需要復(fù)制屬性。
但并不是所有繼承于AActor的類都必須復(fù)制
標記為復(fù)制的Actor在服務(wù)器上生成時,也將在所有客戶端上生成并復(fù)制;但其在客戶端上生成時則僅存在于此客戶端。
(1).RepNotify /Replication – 變量同步
1】None:表示變量不具備同步功能
【2】Replicated: 表示當進入網(wǎng)絡(luò)裁剪范圍內(nèi)的時候服務(wù)器會同步變量到客戶端(如果之前就在網(wǎng)絡(luò)裁剪范圍內(nèi),則會與連接的客戶端相應(yīng)變量值比較,如果值不一樣,同步下去)。
【3】RepNotify:?表示當進入客戶端網(wǎng)絡(luò)裁剪范圍內(nèi)的時候,服務(wù)器會同步變量到客戶端,并且觸發(fā)相應(yīng)的“Notify”函數(shù)(如果之前就在網(wǎng)絡(luò)裁剪范圍內(nèi), 會與該客戶端相應(yīng)變量值比較,如果值不一樣,則觸發(fā)“Notify”函數(shù)), 如下面所示:
?
不帶通知事件的變量同步:
?
UPROPERTY(Replicated)float a;virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;void AMyProject2Character::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const {Super::GetLifetimeReplicatedProps(OutLifetimeProps);DOREPLIFETIME(AMyProject2Character, a); }帶通知事件的變量同步
UPROPERTY(ReplicatedUsing = OnRep_NotifyXXX)float a;UFUNCTION()void OnRep_NotifyXXX();virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;void AMyProject2Character::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const {Super::GetLifetimeReplicatedProps(OutLifetimeProps);DOREPLIFETIME(AMyProject2Character, a); }(2).RPC– 函數(shù)同步
略
4.Role和RemoteRole
在這里我先說明一點,UE4的客戶端代碼和服務(wù)器代碼是同一套代碼(有點牛),服務(wù)器可能缺少了渲染等少數(shù)功能。
[1]ROLE_None時,根本不存在任意角色
[2]ROLE_SimulatedProxy 網(wǎng)絡(luò)游戲中別的玩家在本地客戶端的一個角色代理
[3]ROLE_AutonomousProxy 網(wǎng)絡(luò)游戲中自己的玩家在本地客戶端的一個角色代理
[4]ROLE_Authority: 網(wǎng)絡(luò)游戲在服務(wù)器上的角色
?
?
?
驗證一:自治和模擬以及權(quán)威:
服務(wù)器:小灰人在服務(wù)器上都是權(quán)威的所以設(shè)置成藍色:
客戶端:小灰人會把自治的變成綠色,模擬的小灰人變成紅色
c++代碼:
void AMyProjectCharacter::BeginPlay() {Super::BeginPlay();UWidgetComponent* nameWidgetComponent = this->FindComponentByClass<UWidgetComponent>();if (nullptr == nameWidgetComponent)return;UUserWidget* nameUserWidget = nameWidgetComponent->GetUserWidgetObject();if (nullptr == nameUserWidget)return;UTextBlock* textBlock = Cast<UTextBlock>(nameUserWidget->GetWidgetFromName(FName("TextBlock_46")));if (nullptr == textBlock)return;FString name = "name_none";if (GetLocalRole() == ENetRole::ROLE_AutonomousProxy){name = "ROLE_AutonomousProxy";}else if (GetLocalRole() == ENetRole::ROLE_SimulatedProxy){name = "ROLE_SimulatedProxy";}else{}textBlock->SetText(FText::FromString(name));}?
結(jié)論:服務(wù)器都是權(quán)威的,客戶端都是不可信的
驗證二:GameMode在服務(wù)器不在客戶端
結(jié)論:按N,服務(wù)器顯示trrue客戶端顯示false;
?
?
驗證三:驗證actor開啟復(fù)制通道實現(xiàn)的同步
不開的話客戶端過不去,客戶端會抖動,防止滯后
結(jié)論:不開啟的會導(dǎo)致不一致的情況發(fā)生
?
參考文獻:
https://www.udemy.com/course/unrealmultiplayer/
https://www.bilibili.com/video/BV1ED4y1D7Sf
https://www.youtube.com/watch?v=09yWANtKmC8
https://blog.csdn.net/weixin_37864449/article/details/89096536
總結(jié)
以上是生活随笔為你收集整理的ue4多人联网的实例的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ckfinder的使用及了解config
- 下一篇: 病毒木马查杀实战第017篇:U盘病毒之专