首页 > 其他分享 >【unity】NetCode

【unity】NetCode

时间:2023-02-23 16:56:19浏览次数:57  
标签:NetCode 同步 void RPC unity 服务器 NetworkVariable 客户端

前言

之前接触过某些教程中的联机方案和直接用socket来做聊天室。

这俩方案各有利弊。前者提供了现成的网络同步框架,用起来方便,从数据库读写、自定义通信协议到分层处理,很经典,不过实际做起来要考虑各个方面,得面面俱到;而后者提供了相对简单的通信链接,但要想在个人项目中方便使用的话,还需自己封装功能。

在网上搜索时,发现Unity之前提供了一些联机解决方案,如MLAPIUNet,不过它们都被弃用了,现在最新的是Unity.Netcode,所以来学这个了。

Unity提供了对应的入门教程->Get started with NGO

这个没啥好说的。你可以尝试理解并改造教程代码来熟悉其运作方式。

NetworkBehaviour

官方文档指路->NetworkBehaviour

NetworkBehaviour是一个抽象类,继承自MonoBehavior

OnNetworkSpawn

NetworkBehaviour中提供了OnNetworkSpawn,给网络代码做初始化时就应该发生在该方法中。调用顺序如下。

动态生成时,Awake->OnNetworkSpawn->Start
静态放置时,Awake->Start->OnNetworkSpawn

官方文档中提到:

即使该对象尚未Spawn,仍会调用FixedUpdate、Update、LateUpdate。所以要加入如下限制:

private void Update()
{
	if (!IsSpawned)
	{
		return;
	}
	// Netcode specific logic below here
}

OnNetworkDeSpawn

OnNetworkSpawn相对,在它被取消生成时。这是所有网络代码被清理时应该发生的地方,但不要与销毁混淆。在任何东西被摧毁之前都会发生DeSpawn。

下面来记录一下几个和同步相关的类。

RPC

官方指南指路->Sending Events with RPCs

熟悉Web的应该知道Http协议,RPC和Http一样,都是应用层协议。但区别在于:HTTP更适用于Web资源的请求和响应;而RPC更适用于分布式应用程序之间的远程过程调用,相当于调用了远程应用程序中的对应方法。

如何使用

image

如下是我对官方教程中的代码进行的改造,[ClientRPC]类似。

public void Move(int horizontal)
{
	//p2p主机既为服务器,又是客户端,则无需分开处理
	SubmitPositionRequestServerRpc(horizontal);
}

[ServerRpc]//被该特性标记,则调用方法时不在本地执行,而是存入本地队列中,帧结束时向Server发送
void SubmitPositionRequestServerRpc(int horizontal)
{
	Vector3 v = horizontal > 0 ? Vector3.left : Vector3.right;
	Position.Value -= v;
}

注意,为了命名规范,最好把RPC方法命名为FunctionName+ServerRPC/ClientRPC

这个特性还支持标注某个RPC使用不可靠的方法来进行调用,如下。

[ServerRpc(Delivery = RpcDelivery.Unreliable)]

官方文档中称:

可靠的 RPC 将按照触发的顺序在远程端接收,但此顺序保证仅适用于同一NetworkObject上的 RPC。不同的NetworkObject可能调用了可靠的 RPC,但执行顺序不同。更简单地说,仅保证单个NetworkObject按顺序执行可靠的 RPC。
如果您确定某个 RPC 经常更新(即每秒更新几次),则它可能更适合作为不可靠的 RPC。

NetworkVariable

官方文档指路->NetworkVariable

做过自定义消息的应该知道:在服务器和客户端之间通信要约定好消息的格式等。而NetworkVariable<T>帮我们避免了这个问题,以下是官方文档中的描述。

NetworkVariable<T>是一种在服务器和客户端之间同步属性(“变量”)的方法,而无需使用自定义消息或RPC。由于是类型存储值的包装器(“容器”),因此必须使用该属性来访问正在同步的实际值。

当服务器中的NetworkVariable<T>的值发生更改时,任何已连接的客户端会自动同步;在游戏中途加入的客户端会自动同步服务器的当前状态。官方入门教程也展示了这一点。

需要注意官方文档中已写明:NetworkVariable<T>支持大部分非托管类型;如果想要同步托管类型,则需要实现INetworkSerializable,可参考自定义序列化

同时NetworkVariable<T>也对外提供值被修改时触发的回调OnValueChanged,也支持设置服务段和客户端的读写权限。

RPC vs NetworkVariable

官方文档指路->RPC vs NetworkVariable

问题来了:RPCNetworkVariable这两种同步方式有何区别?

RPC用于一瞬间发生的某些事情;而NetworkVariable适用于持久发挥作用的某些状态或变量。

比方说:如果使用RPC来直接控制某扇门的打开,而使用NetworkVariable来记录它的打开状态。那么在主机打开门后,某些客户端才加入游戏的话,这些客户端中对应的门将是关闭状态。这是不合理的,所以在设计阶段要做好分析。

NetworkTime & Ticks

NetworkTime & Ticks

NetworkTime

消息会在服务器和客户端之间传输,传输需要时间,这会造成两个时间:本地时间和服务器时间。

客户端上的LocalTime比服务器上的LocalTime要更早,即更加往后;而客户端上的ServerTime比服务器上的ServerTime更晚,即更加往前,如下。

image

很多游戏中都有按照固定模式移动的环境对象,这个可以不用同步位置来做,用NetworkTime来做。如下。

using Unity.Netcode;
using UnityEngine;

public class MovingPlatform : MonoBehaviour
{
	public void Update()
	{
		// Move up and down by 5 meters and change direction every 3 seconds.
		var positionY = Mathf.PingPong(NetworkManager.Singleton.LocalTime.TimeAsFloat / 3f, 1f) * 5f;
		transform.position = new Vector3(0, positionY, 0);
	}
}

Ticks

FixedUpdate类似,Ticks也按固定速率运行,而且对外提供可注册的回调,如下。

public override void OnNetworkSpawn()
{
	NetworkManager.NetworkTickSystem.Tick += Tick;
}

private void Tick()
{
	Debug.Log($"Tick: {NetworkManager.LocalTime.Tick}");
}

public override void OnNetworkDespawn() // don't forget to unsubscribe
{
	NetworkManager.NetworkTickSystem.Tick -= Tick;
}

注意,如果游戏中要使用FixedUpdate或物理系统,则要把Ticks的速率设置为fixed update time一致。

NetworkTransform

这个组件就是给你自动同步Transform的,不用开发者再去造轮子。

这意味这官方入门教程中,那个通过Position变量来做位置同步的写法没必要,你如果去看了它这个类里的实现,你会发现它内部就是使用NetworkVariable来做Transform同步的。这可能只是想用来解释RPC调用,实际开发中直接用这个组件就可以了。

注意,组件中的Interpolate会以轻微的延迟缓冲传入数据,并对值应用额外的平滑。所有这些因素结合在一起,使转换同步更加顺畅。而插值不会应用到Server上,这可能会导致Host和其他Client所呈现的表现不一致。

你可以继承并重写来把原方法替换成自定义方法。

NetworkAniamtion

这个组件就是给你自动同步Animator的,不用开发者再去造轮子。不过这只适用于最常见的动画系统方案,就是蜘蛛网那一套。如果遇到Playable这一套方案,就得自定义动画同步系统。

你看它的实现就会发现,它里面不包含NetworkVariable,它只使用RPC来进行同步。

NetworkRigidbody

官方文档中这样说:

NetworkRigidbody依赖于NetworkTransformRigidbody。它的主要功能是将Rigidbody组件添加到网络对象上,并确保只有服务器和拥有授权的客户端能修改它。这是通过将Rigidbody设置为运动学模式来实现的,这意味着物理引擎将不再对它进行模拟,而是由网络系统处理其移动和旋转。

你看它的实现就会发现,它什么同步也没做,它里面一个RPCNetworkVariable都没有。
核心代码就下面这一段,大意是:如果当前为服务器或是有权限客户端,就使其刚体运动学开启;否则服从运动学,让NetworkTransform来做运动,避免了无权限客户端上的碰撞检测。

		/// <summary>
		/// Sets the authority differently depending upon
		/// whether it is server or owner authoritative
		/// </summary>
		private void UpdateOwnershipAuthority()
		{
			if (m_IsServerAuthoritative)
			{
				m_IsAuthority = NetworkManager.IsServer;
			}
			else
			{
				m_IsAuthority = IsOwner;
			}

			// If you have authority then you are not kinematic
			m_Rigidbody.isKinematic = !m_IsAuthority;

			// Set interpolation of the Rigidbody based on authority
			// With authority: let local transform handle interpolation
			// Without authority: let the NetworkTransform handle interpolation
			m_Rigidbody.interpolation = m_IsAuthority ? m_OriginalInterpolation : RigidbodyInterpolation.None;
		}

OnCollisionEnter等事件仍是该触发就会触发,但它在与其他联网实例发生冲突时,则不会触发碰撞事件。所以尽量在服务器上侦听OnCollisionEnter函数,并将事件使用ClientRPC来同步到所有客户端。

参考资料

Get started with NGO
NetworkBehaviour
Sending Events with RPCs
NetworkVariable
自定义序列化
RPC vs NetworkVariable
NetworkTime & Ticks

标签:NetCode,同步,void,RPC,unity,服务器,NetworkVariable,客户端
From: https://www.cnblogs.com/OtusScops/p/17138332.html

相关文章

  • Unity UGUI系列九 Text TextMeshPro 详解
    参考[专栏精选]TextMeshPro插件TextMeshPro使用说明TextMeshPro中文字体生成和字体材质更换新一代Unity文本组件TextMeshPro系列教程【Unity学习笔记】TextMeshP......
  • Unity之Burst测试
    关于Burst,看下官方介绍:BurstisacompilerthatyoucanusewithUnity'sjobsystemtocreatecodethatenhancesandimprovesyourapplication'sperformance.It......
  • Unity中mesh 绘制正方体
    绘制正方体:用mesh自带的函数绘制://创建一个mesh网格Meshmesh=newMesh();//添加网格过滤器gameObject.AddComponent<MeshFilter>();......
  • 230222 Radiated Immunity Pre-compliance Test
    Helloeveryone,welcometoMach1DesignEMCchannel.Lasttimewetalkedabouthowtosetuparadiatedimmunitytestusingaverylowcostantennalikethis.......
  • Unity下简易字符串指令调试
    Unity下简易字符串指令调试输入相应的字符串命令即可调用特定的方法,比如让角色等级提升,生成特定数量的Boss等usingSystem;usingUnityEngine;usingSystem.Collectio......
  • Unity Shader标准光照模型的实现
    1Shader"Custom/P_Illumination"2{3Properties{4_BasicColor("基础颜色",Color)=(1.0,1.0,1.0,1.0)5_SpecularColor("高光颜色",Colo......
  • Unity手机移动设备重力感应
    一、引入大家对重力感应应该都不陌生,之前玩过的王者荣耀的资源更新界面就是使用了重力感应的概念,根据手机的晃动来给实体进行晃动。下图的王者荣耀刚开始的界面其实就是使用......
  • 虚拟机VMware安装Fedora15/ubuntu 11,要想使用gnome3/unity 要怎么办呢?
    SelecttheAccelerate3DgraphicsAcceleratedgraphicscapabilitiesapplytoWindowsXP,WindowsVista,andWindows7guests,onhostsrunningWindowsorLinux......
  • Unity2D游戏开发Update与FixedUpdate间的区别
    Update方法是每一帧执行一次,FixeUpdate方法是每0.02秒执行一次,即我们常说的50帧的刷新率,我们在进行物理模拟动作的编写中,常常会写在FixeUpdate中,由于是每0.02秒执行一次,不......
  • Unity客户端框架收集
    转载:https://blog.csdn.net/t163361/article/details/106499225LoxodonFrameworkhttps://github.com/cocowolf/loxodon-frameworkMVVM框架;支持XLua,可以完全使用Lua脚本......