Unity之NetCode多人网络游戏联机对战教程(6)--NetworkTransform组件

文章目录

    • 前言
    • NetworkTransform是什么
    • 玩家移动脚本
    • NetworkTransform字段讲解
      • Synchronizing ("Syncing")
      • Thresholds
      • Local space
      • Interpolation
      • Slerp Position
      • Use Quaternion Synchronization
      • Use Quaternion Compression
      • Use Half Float Precision
      • Authority modes
        • Server Authoritative Mode
        • Owner Authoritative Mode
      • Additional Virtual Methods of Interest
    • 后话
    • 官方链接

前言

这次教程主要是讲同步两个玩家的位置信息的一个非常重要的组件NetworkTransform,以及这个组件的作用与说明。


NetworkTransform是什么

同步物体的Transform是Netcode当今多人游戏中最常见的任务之一。这个概念似乎很简单:

  • 确定您要同步的变换轴。
  • 序列化这些值。
  • 将序列化的值作为消息发送给所有其他连接的客户端。
  • 处理消息并反序列化值。
  • 将这些值应用到适当的轴上。

乍一看,上面列出的任务似乎相对简单,但当您开始实现每个任务时,几乎任何经验丰富的Netcode软件工程师都会同意:这可能迅速变得复杂。

例如,上面列出的任务并没有考虑以下几点:

  • 谁控制同步(即每个客户端、服务器或者根据要同步的对象而定可能两者都控制)?
  • 以何种频率同步这些值,以及确定何时需要同步这些值的逻辑应该是什么?
  • 如果您有复杂的父子关系层次结构(父变换带有一个或多个子变换),是应该同步世界空间轴值还是本地空间轴值?
  • 如何优化每次变换更新的带宽成本?

幸运的是,Netcode for GameObjects (NGO) 提供了NetworkTransform组件的实现,它处理了一些变换同步的棘手方面,并可以通过在编辑器中的检视面板中访问的属性轻松配置。


玩家移动脚本

Package Manager --> 左上角+号旁边的包 选择Unity Registry, 搜索Cinemachine 下载并导入

PlayerMove移动到Scripts,在预制体Player上添加该脚本



NetworkTransform字段讲解

Synchronizing (“Syncing”)

这个是用来指定同步位置,旋转,缩放的,需要同步哪些值就勾选哪些

一般情况下,不需要同步GameObject的所有变换值。例如,如果GameObject的缩放从不改变,可以在面板中的Syncing Scale禁用。禁用同步可以节省CPU成本和网络带宽。

Thresholds

您可以使用阈值值来设置最小阈值。这可以用来通过只同步大于或等于阈值值的变化(低于阈值的变化不会同步)来降低同步更新的频率。例如:

如果NetworkTransform启用了插值(Interpolate),您可能会发现可以降低位置阈值的分辨率(增加位置阈值值),而不影响对象运动的"平滑度",同时还减少位置更新的频率(减少每个实例的带宽成本)。增加阈值分辨率(降低位置阈值值)会增加对象的位置同步的潜在频率(可能会增加每个实例的带宽成本)。

阈值值不会被同步,但可以在authoritative实例上进行更新。在使用所有者authoritative模式的实例时,应该牢记这一点,因为更改所有权将使用新所有者实例上当前设置的任何值。如果您计划在运行时更改阈值值并计划更改所有权,那么您可能需要同步阈值值。

Local space

默认情况下,NetworkTransform世界空间同步对象的变换。In Local Space配置选项允许您改为在本地空间中同步变换。子对象的本地空间轴值(主要是位置和旋转)始终是相对于父变换的偏移。而子对象的世界空间轴值包括父对象的轴值。

在具有父对象的NetworkTransform上使用本地空间可以改善在对象重新父对象化时的变换同步,因为重新父对象化不会改变对象的本地空间变换,但会改变世界空间位置。

authoritative实例确实会同步对LocalSpace属性的更改。因此,您可以在运行时在authoritative实例上调整此属性,而非authoritative实例将自动更新。

Interpolation

默认情况下启用了插值(·Interpolation·),如果您希望在非authoritative实例上的变换更新之间实现平滑的过渡,这是推荐的设置。插值会缓冲传入的状态更新,这可能会在authoritative实例和非authoritative实例之间引入轻微的延迟。当禁用插值属性时,变换的更改会立即应用到非authoritative实例上,这可能会导致视觉上的"抖动",或者在延迟较高时似乎会"跳跃"到新应用的状态更新。

在权威实例上在运行时更改插值属性将与所有非权威实例同步。

NetworkTransform组件仅在客户端上进行插值。为了在主机或服务器上实现更平滑的移动,用户可能还希望在服务器端实现插值。尽管服务器不会受到网络引起的抖动影响,但仍然可能会在本地出现一些卡顿(例如,在FixedUpdate中进行的低物理更新率的移动)。

Slerp Position

当设置了这个属性并且同时启用了插值(Interpolation),非authoritative实例将通过Slerp而不是Lerp朝着它们的目标位置插值。通常,这可以在对象遵循圆形和/或基于样条的运动路径时使用,以保留该路径的曲线性。由于在两点之间进行"lerp"插值会在两点之间的线上产生线性进展,因此在某些情况下,位置状态更新的频率可能会导致对象运动曲线的损失。

Use Quaternion Synchronization

默认情况下,使用欧拉角值来同步旋转增量。对于许多情况,使用欧拉角值可能就足够了。然而,有些情况下,同步欧拉角增量会产生不希望的结果。一个情况是当您有复杂的嵌套NetworkTransforms,其中父子变换之间的旋转不同。当您将插值结合在一起(记住插值是有缓冲的,在非权威的当前旋转和目标旋转之间存在固有的延迟时),立即发生在Quaternion中的调整会处理更复杂的变换相关问题(例如吉姆巴锁等)。

启用Quaternion同步时,权威实例仍然会根据欧拉轴值与阈值值进行比较,以确定是否需要更新变换的旋转,但是会更新整个Quaternion,而不仅仅是检测到变化的欧拉轴。这意味着可以确保正确的旋转将应用于非权威实例,并且已经考虑到了使用欧拉角时可能出现的更复杂问题。

Quaternion同步是有代价的。它会增加带宽成本,每个实例增加16字节,以处理更复杂的旋转问题,这种问题在使用嵌套的NetworkTransform(一个或多个父变换和一个或多个子变换)时更常见。但是,当您启用Use Quaternion Synchronization属性时,您会注意到在同步轴选择复选框和一个新的Use Quaternion Compression属性会出现:

当启用Use Quaternion Synchronization时,不再提供旋转同步轴复选框(因为同步变换的四元数将始终更新所有旋转轴),而Use Quaternion Compression成为可见选项。

Use Quaternion Compression

由于同步四元数可能会增加NetworkTransform旋转状态更新的带宽成本,因此有两种方法可以减小四元数同步的总体带宽成本:

  • 四元数压缩(Quaternion Compression):这提供了最高的压缩率(每次更新减少到4字节),但精度损失略高于半浮点精度。

  • 半浮点精度(Half Float Precision):当启用并且禁用四元数压缩时,这提供了中等级别的替代压缩(每次更新减少到8字节),比完全浮点值的精度低,但比四元数压缩的精度高。

四元数压缩是基于最小三算法的,当旋转精度不如带宽成本重要时,可以使用它。您可能有需要某种形式的旋转同步的附属对象/抛射物,但在项目的整体方案中不需要完美对齐。

如果带宽成本和精度都是问题,那么备选的推荐压缩方法是半浮点精度。此外,建议尝试不同的压缩选项,您可能会发现精度的部分损失对于项目的需求是完全可以接受的(并且可以减小所有实例的总体带宽成本,最多减少50%的带宽成本,而不使用完全精度时)。

此属性值可以在权威实例在运行时进行更新,并将同步到所有非权威实例。提醒:在authoritative实例上在运行时更新此值将导致NetworkTransform的完全同步,所有非authoritative实例的插值器将被重置。

Use Half Float Precision

启用此属性将会将任何变换轴值从4字节浮点数转换为2字节半浮点数,但会以精度损失为代价。启用此选项时,所有标记为同步的变换轴都将使用半浮点精度。然而,关于位置和旋转,半浮点精度有一些独特的方面。

由于存在精度损失,位置状态更新仅提供相对于上一个已知完整位置的位置增量。NetworkDeltaPosition可序列化结构会跟踪上一个已知完整位置和当前与上一个已知完整位置的当前增量偏移之间的当前增量。此外,NetworkDeltaPosition会在发送更新时自动纠正精度损失。从先前更新的精度损失将包含在下一个位置更新中。换句话说,非authoritative实例可以在1个tick周期的持续时间内或直到接收到下一个变换状态更新之前,潜在地与authoritative实例具有来自每次应用的更新的分数增量。此外,NetworkDeltaPosition填补了半浮点值的最大值与Unity世界空间的最大边界(全局/项目缩放相关)之间的差距。

推荐的Unity世界空间单位每秒:
每个更新的最大增量不应超过64个Unity世界空间单位。如果您使用默认的tick(30),那么对象不应以等于或超过每秒1920个Unity世界空间单位的速度移动(即30 x 64)。作为参考,默认摄像机的远裁剪平面是1000个Unity世界空间单位,这意味着以1920个Unity世界空间单位的速度移动的物体可能不会在渲染视锥体中被视觉检测到,或者会以短暂的"闪烁"出现。

当启用Use Quaternion SynchronizationUse Half Float Precision并且禁用Use Quaternion Compression时,四元数值通过HalfVector4可序列化结构进行同步,其中每个轴值(x、y、z和w)都存储为半浮点值。这意味着每个旋转更新从完全精度的每次16字节减少到每次8字节。对于旋转,使用半浮点精度提供了比四元数压缩更好的精度,带宽成本是其两倍,但是只有完全精度的一半成本。

当启用Use Quaternion SynchronizationUse Half Float PrecisionUse Quaternion Compression时,四元数压缩将用于代替半浮点精度的旋转。

当在authoritative实例上进行更新时,所有这些属性都将同步到非authoritative实例。

Authority modes

Server Authoritative Mode

默认情况下,NetworkTransform在服务器authoritative模式下运行。这意味着服务器端检测到要同步的变换轴(标记为同步),并将其推送给连接的客户端。这也意味着对变换轴值的任何更改都将被authoritative状态(在这种情况下是服务器端的变换状态)覆盖。

还有一个关于轴同步与初始同步的变换值的概念需要牢记。未标记为同步的任何轴在NetworkObject被生成或客户端第一次同步时仍会被更新为authoritative的初始状态。

举个例子:
假设您只标记了位置和旋转轴来同步,但在NetworkTransform组件的网络预制上排除了所有缩放轴。当您生成网络预制的实例时,初始的权威方缩放值将在生成时同步。从那时起,非authoritative实例(在这种情况下是客户端实例)将保持相同的缩放轴值,即使它们不再更新。

Owner Authoritative Mode

(又名:ClientNetworkTransform)

服务器端权威的NetworkTransform在同步转换和在所有连接的客户端上应用更新之间提供了平衡。然而,有时您希望特定NetworkObject(通常是玩家)在客户端上立即更新位置。NetworkTransform的所有者权威由NetworkTransform.OnIsServerAuthoritative方法决定,该方法在首次初始化NetworkTransform组件时调用。如果该方法返回true(默认值),则它将初始化为服务器权威的NetworkTransform。如果返回false,则它将初始化为所有者authoritativeNetworkTransform(也称为ClientNetworkTransform)。这可以通过从NetworkTransform派生,覆写OnIsServerAuthoritative虚拟方法,并像下面的代码示例中一样返回false来实现:

using Unity.Netcode.Components;
using UnityEngine;

namespace Unity.Multiplayer.Samples.Utilities.ClientAuthority
{
    /// <summary>
    /// 用于同步客户端端的变换更改。这包括主机。不支持纯服务器作为所有者,请使用NetworkTransform。
    /// 用于那些始终由服务器拥有的Transform。
    /// </summary>
    [DisallowMultipleComponent]
    public class ClientNetworkTransform : NetworkTransform
    {
        /// <summary>
        /// Used to determine who can write to this transform. Owner client only.
        /// This imposes state to the server. This is putting trust on your clients. Make sure no security-sensitive features use this transform.
        /// </summary>
        protected override bool OnIsServerAuthoritative()
        {
            return false;
        }
    }
}

ClientNetworkTransform示例:

选择Window --> Package Manager来打开包管理器。

Add(+) --> 从git URL添加…

复制并粘贴以下Git URL:https://github.com/Unity-Technologies/com.unity.multiplayer.samples.coop.git?path=/Packages/com.unity.multiplayer.samples.coop#main

或者修改项目的manifest.json,添加

"com.unity.multiplayer.samples.coop": "https://github.com/Unity-Technologies/com.unity.multiplayer.samples.coop.git?path=/Packages/com.unity.multiplayer.samples.coop#main"

该Transform将所有者客户端的位置与服务器和所有其他客户端同步,从而实现客户端authoritative的游戏玩法。

Additional Virtual Methods of Interest

NetworkTransform.OnAuthorityPushTransformState: 此虚拟方法在权威实例正在将新的NetworkTransformState推送给非authoritative实例时调用。这可以用于更精确地确定用于预测相关任务的非authoritative实例的更新值。

NetworkTransform.OnNetworkTransformStateUpdated: 此虚拟方法在非权威实例接收来自authoritative实例的推送NetworkTransformState更新时调用。这可以用于更精确地确定用于预测相关任务的非authoritative实例的更新值。

NetworkTransform.Awake: 为了提供自定义初始化的能力,此方法已被设置为虚拟方法。如果您覆盖此方法,建议首先调用base.Awake()

NetworkTransform.OnInitialize: 此虚拟方法在相关的NetworkObject首次生成以及所有权更改时调用。

NetworkTransform.Update: 为了提供您对派生NetworkTransform类进行任何自定义的能力,此方法已被设置为虚拟方法。如果您覆盖此方法,要求所有非authoritative实例调用base.Update(),但对于authoritative实例则不是必须的。


后话

有了NetworkTransform这个组件可以为位置同步省了很多功夫,后面讲NetworkTransform的实战应用

官方链接

https://docs-multiplayer.unity3d.com/netcode/current/components/networktransform/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/124589.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

0基础学习VR全景平台篇第118篇:利用动作录制器功能避免重复操作 - PS教程

上课&#xff01;全体起立~ 大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01; 嗨&#xff0c;大家好。欢迎收看蛙色VR系列教程之PS利用动作记录器节约补地时间。 大家拍摄在补地的时候&#xff0c;利用插件选择输入输出选项的时候&#xff0c;每次重复操作…

Transformer的最简洁pytorch实现

目录 前言 1. 数据预处理 2. 模型参数 3. Positional Encoding 4. Pad Mask 5. Subsequence Mask 6. ScaledDotProductAttention 7. MultiHeadAttention 8. FeedForward Networks 9. Encoder Layer 10. Encoder 11. Decoder Layer 12. Decoder 13. Transformer 1…

什么是 HwameiStor?

HwameiStor 是一款 Kubernetes 原生的容器附加存储 (CAS) 解决方案&#xff0c;将 HDD、SSD 和 NVMe 磁盘形成本地存储资源池进行统一管理&#xff0c; 使用 CSI 架构提供分布式的本地数据卷服务&#xff0c;为有状态的云原生应用或组件提供数据持久化能力。 具体的功能特性如下…

GoLong的学习之路(二十)进阶,语法之反射(reflect包)

这个是为了接上之前的语法篇的。按照我的学习计划&#xff0c;这里此时应该有一个小项目来做一个统合。但是吧&#xff0c;突然觉得&#xff0c;似乎也没必要。能学go的大部分肯定都是有其他语言的基础的。 接下来说反射 文章目录 反射介绍reflect包TypeOftype name和type kin…

基于springboot的二次元商品销售网站的设计与开发

大家好我是玥沐春风&#xff0c;今天分享一个基于springboot的二次元商品销售网站的设计与开发&#xff0c;项目源码以及部署相关请联系我&#xff0c;文末附上联系信息 。 开发工具及技术 2.3.1 Spring Boot框架 SpringBoot是一个全新的开源的轻量级框架。简化了Spring应用的…

一张数学地图带你尽览数学分支

我们在学校学习的数学可能也只是数学领域的冰山一角&#xff0c;作为庞大而多样的学科&#xff0c;我今天将通过一张数学地图带你尽览数学分支。 本数学地图对应的视频讲解地址如下&#xff1a; https://www.youtube.com/watch?vOmJ-4B-mS-Y 另外&#xff0c;由于图片较大&a…

React进阶之路(一)-- JSX基础、组件基础

文章目录 React介绍React开发环境搭建项目目录说明以及相关调整 JSX基础JSX介绍JSX中使用js表达式JSX列表渲染JSX条件渲染JSX样式处理JSX注意事项 组件基础组件的概念函数组件类组件事件绑定如何绑定事件获取事件对象传递额外参数 组件状态状态不可变表单处理受控表单组件非受控…

Triples of Cows

题目传送门 引 模拟赛 T 4 T4 T4 , 变换挺妙的, 而且感觉转换后问题就迎刃而解了 解法 强行模拟拆点重连边显然不行,会让图的边数达到 n 2 n^2 n2 级别的 —————————————————————————————————————————————————— 考虑转…

python爬虫怎么翻页 ?

首先&#xff0c;你需要安装相关的库。在你的命令行窗口中&#xff0c;输入以下命令来安装所需的库&#xff1a; pip install requests beautifulsoup4然后&#xff0c;你可以使用以下代码来爬取网页内容并翻页&#xff1a; package mainimport ("fmt""net/htt…

米软科技 | 推进医院智慧管理分级评估体系建立、提升评级

国家卫生健康委办公厅于2021年3月15日发布了“关于印发医院智慧管理分级评估标准体系&#xff08;试行&#xff09;的通知”&#xff08;国卫办医函〔2021〕86 号&#xff09;&#xff0c;该评估体系用于指导医疗机构科学、规范开展智慧医院建设&#xff0c;提升医院管理精细化…

[黑马程序员Pandas教程]——Pandas缺失值处理

目录&#xff1a; 学习目标空值和缺失值查看缺失值 加载数据并通过info函数初步查看缺失值情况df.isnull().sum()空值数量统计Missingno库对缺失值的情况进行可视化探查 安装missingno库missingno.bar(df)缺失值数量可视化missingno.matrix(df)缺失值位置的可视化missingno.he…

【23-24 秋学期】NNDL 作业7 基于CNN的XO识别

一、用自己的语言解释以下概念 局部感知、权值共享池化&#xff08;子采样、降采样、汇聚&#xff09;。会带来那些好处和坏处&#xff1f;全卷积网络&#xff08;课上讲的这个概念不准确&#xff0c;同学们查资料纠正一下&#xff09;低级特征、中级特征、高级特征多通道。N输…

Java提高与实践

IO流 IO流概述 文件字节输入流&#xff1a;每次读取一个字节 package fileStream;import java.io.*;public class HelloFileInputStream {public static void main(String[] args) throws IOException {//创建文件字节输入流 管道&#xff0c;与源文件接通//写法一//InputStr…

getid3 获取视频时长

1、首先&#xff0c;我们需要先下载一份PHP类—getid3https://codeload.github.com/JamesHeinrich/getID3/zip/master 2.我在laravel6.0 中使用 需要在composer.json 自动加载 否则系统访问不到 在命令行 执行 composer dump-autoload $getID3 new \getID3();//视频文件需要放…

『 C++类与对象 』多继承与虚继承

文章目录 ⌨️多继承的概念语法 &#x1f5b1;️ ⌨️棱形继承⌨️虚继承虚继承是如何解决数据冗余和二义性的(不谈虚表概念)?&#x1f5b1;️ ⌨️多继承的概念 多继承指的是一个派生类是由多个基类继承而来的; 而在生活当中也有类似的例子:番茄既可以是水果,也可以是蔬菜;…

内核移植笔记 Cortex-M移植

常用寄存器 PRIMASK寄存器 为1位宽的中断屏蔽寄存器。在置位时&#xff0c;它会阻止不可屏蔽中断&#xff08;NMI&#xff09;和HardFault异常之外的所有异常&#xff08;包括中断&#xff09;。 实际上&#xff0c;它是将当前异常优先级提升为0&#xff0c;这也是可编程异常/…

K8S知识点(五)

&#xff08;1&#xff09;资源管理介绍 Pod控制器的作用&#xff0c;就是为了最终产生各种各样的Pod&#xff0c;Pod里面运行容器&#xff0c;容器里面运行程序 程序需要数据持久化&#xff0c;可以用数据存储卷来存储 Pod想要让外部访问需要通过Service代理&#xff0c;外部…

SAP-PP-报错:工作中心 7333_JQ 工厂 7331 对任务清单类型 N 不存在

创建工艺路线时报错&#xff1a;工作中心 7333_JQ 工厂 7331 对任务清单类型 N 不存在&#xff0c; 这是因为在创建工作中心时未维护控制键值导致的

latex加密符号怎么打|同态加密|Paillier

最近在写论文的时候遇到了一点阻碍&#xff0c;因为论文中需要用到paillier加密算法&#xff0c;想用一个公式表达加密的过程&#xff0c;但是不知道怎么打加密符号。 加密符号如下所示&#xff1a; 其中a是被加密的数字 $[\![a]\!] $ 公式&#xff1a; \begin{equation} …

【编程语言发展史】SQL的发展历史

目录 目录 SQL概述 SQL发展历史 SQL特点 SQL基本语句 SQL是结构化查询语言(Structure Query Language)的缩写&#xff0c;它是使用关系模型的数据库应用语言&#xff0c;由IBM在70年代开发出来&#xff0c;作为IBM关系数据库原型System R的原型关系语言&#xff0c;实现了…
最新文章