终于有时间了,打算在这个周末认认真真的研究虚幻引擎网络架构,同时我在Safaribooksonline上面发现了一本能让我的生活变得轻松的书Multiplayer Game Programming by Rough Cuts,这个周末好好享用哟。
好了,承接上一次的内容:为什么虚幻引擎的网络架构这么的高效?
1.从他的架构模式继续广义的客户端-服务器模型(Generalized Client-Server model):
在这个模型中服务器还是控制着游戏状态的变化,客户端运行着和服务器一样的代码判断游戏的运行状态。服务器通过复制replication的方式将游戏状态信息发送到客户端,客户端和服务器也可以replication交换信息。
当然为了最小化的复制内容,我们分类出了仅有调用函数的Actors。
2.从最早Tim Sweeney阐明的虚幻网络架构,Unreal 3- Unreal 4我并未发现有太大的变化。
在引擎中通常可以有以下内容可以进行复制Variable, Function ,Actor,Object, game state, tick。
-Client 是一个Unreal.exe的运行实例,维持着一组和世界中发生事件的近似游戏状态子集,并且可以渲染世界的近似视图。
- Server是一个正在运行的实例,负责每一个独立关卡并把游戏状态传给客户端。
3.Unreal发生在Server和Client之间的更新循环
- 如果我是Server,我可以将自己的状态传给所有的客户端。
-如果我是Client,我可以把我请求的运动发送给服务器,并从服务器收到游戏状态信息,发送到客户端上渲染到屏幕上。
4.关于虚幻中的实时状态更新:event Tick(float DeltaTime)
每次Tick影响到游戏所有Actors的更新,实现了他们的物理等变量或事件,例如Position+=velocity*DeltaTime;
因此在Tick对于作用于Actor可以
- 修改Actor的变量
- 创建Actor
- 销毁Actor
你会好奇我为什么花费那么多能量来阐述虚幻中的更新呢?因为服务器管理游戏状态就是在管理世界中的所有Actors的状态。因此服务器被看做是一个真正的游戏状态,客户端上的游戏状态可以说是服务器端的近似状态,需要被督导和斧正。存在于客户端的对象,不能被当作代理,因为他们只是一个代理的近似。
例如你的iPhone机器上跑了自己的角色Pawn,那其实不是真正的Pawn,而是一个向服务器端的Pawn的Clone,仅为你呈现而已。悲哀吧,你只能在客户端玩到一个阿凡达。
5.为了节省性能,我们得对Actor进行一些分类:这些标志可以表明这个Actor的那些环节将会被replication
在一个关卡中,有一些Actor的状态不会产生什么变化,我们知道他们是一成不变的,所以复制没有意义只会浪费不必要的带宽和浪费。我们使用两种标志位将bNoDelete || bStatic 的Actor进行排除,这两种标志位的Actor一般或是StaticMesh等或者GameInfo。
那么Actor为了进行replication还需要进行哪些特殊的标注呢?
在服务器和客户端都存在的Actor我们标注其为Authority。对于服务器端是一直都会保存其为Authority权威,而对于客户端是进行优先级进行区分的:例如在网络复制中同步到客户端,如果一个溅血粒子效果的表现的重要性,肯定不及玩家射出的子弹。根据优先级我们可以分为:
DumbProxy(哑代理):传送门,拾取物品
SimulatedProxy(仿真代理):射弹等可以使用物理在客户端进行预测的Actor。说明这是个临时Actor,在客户端模拟物理和动画。
AutonomousProxy(自治代理) :说明这是一个本地玩家,可以进行一些本地预测运动(给予玩家控制)。可以执行本地脚本,只可在本地客户端可见,不会在服务器和单人玩家游戏中见到。
Authority:可以执行脚本,进入状态,所有在服务器端的Actor。当在本地,这个Actor只在本地生成以便减少带宽,例如特效。 在服务器端,所有Role=ROLE_Authority和RemoteRole设置成同一种代理类型。在客户端和服务器端是相反的。
// Net variables. enum ENetRole { ROLE_None, // No role at all. ROLE_SimulatedProxy, // Locally simulated proxy of this actor. ROLE_AutonomousProxy, // Locally autonomous proxy of this actor. ROLE_Authority, // Authoritative control over the actor. }; var ENetRole RemoteRole, Role;
用以下的举例来结束这一片内容:
a.因为Actor.AmbientSound变量是从服务器发送给客户端的
if(Role==Role_Authority)
AmbientSound;
b.Actor.AnimSequence,只有当actor被渲染成为mesh时才会从服务器发送给客户端
if(DrawType==DT_Mesh && RemoteRole<ROLE_SimulatedProxy) AnimSequence;
c.Server传送给client velocity为代理模拟。当被初始化为mover时
if((RemovetRole==ROLE_SimulatedProxy && (bNetInitial||bSimulatedPawn))||bIsMover)velocity;