Unity问题与解决方案:Photon同步数据的四种方式

2023-10-25 17:48

本文主要是介绍Unity问题与解决方案:Photon同步数据的四种方式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

从我目前get到的点钟,大概是有三个方法,第一个方法是使用PhotonNetwork.RPC方法,该方法接收方法名,发送对象(PhotonPlayer或PhotonTarget)和方法参数,并调用声明[PUNRPC]的相关方法,但根据源码:

//<summary>
/// Internal to send an RPC on given PhotonView. Do not call this directly but use: PhotonView.RPC!
/// </summary>
internal static void RPC(PhotonView view, string methodName, PhotonTargets target, bool encrypt, params object[] parameters)

很明显该方法并不被推荐适用(Do not call this directly but use: PhotonView.RPC!

第二个方法则是按照PhotonView同步的方式,模仿PhotonTransformView等写一个自己的脚本,如果要仿照的话,PhotonRigidbodyView的实现较为简单,可以参考,来看一下原码:

using System;
using UnityEngine;
using Object = System.Object;/// <summary>
/// This class helps you to synchronize the velocities of a physics RigidBody.
/// Note that only the velocities are synchronized and because Unitys physics
/// engine is not deterministic (ie. the results aren't always the same on all
/// computers) - the actual positions of the objects may go out of sync. If you
/// want to have the position of this object the same on all clients, you should
/// also add a PhotonTransformView to synchronize the position.
/// Simply add the component to your GameObject and make sure that
/// the PhotonRigidbodyView is added to the list of observed components
/// </summary>
[RequireComponent(typeof(PhotonView))]
[RequireComponent(typeof(Rigidbody))]
[AddComponentMenu("Photon Networking/Photon Rigidbody View")]
public class PhotonRigidbodyView : MonoBehaviour, IPunObservable
{[SerializeField]bool m_SynchronizeVelocity = true;[SerializeField]bool m_SynchronizeAngularVelocity = true;Rigidbody m_Body;void Awake(){this.m_Body = GetComponent<Rigidbody>();}public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info){if (stream.isWriting == true){if (this.m_SynchronizeVelocity == true){stream.SendNext(this.m_Body.velocity);}if (this.m_SynchronizeAngularVelocity == true){stream.SendNext(this.m_Body.angularVelocity);}}else{if (this.m_SynchronizeVelocity == true){this.m_Body.velocity = (Vector3)stream.ReceiveNext();}if (this.m_SynchronizeAngularVelocity == true){this.m_Body.angularVelocity = (Vector3)stream.ReceiveNext();}}}
}

从中不难看到,实现的关键是实现IPunObservable接口和接口对应的方法,该实现通过判断stream的读写状态来执行SendNextReceiveNext,要注意发送和接收的数据流和接收逻辑必须是一一对应的,否则会出现值无法对应的情况。

另外一个特别需要注意的问题!如果是基础数据类型,是可以直接SendNext和ReceiveNext的,但是如果是自定义类型,需要在Photon中进行注册,相关文档在PhotonUnity的Document中有,可以去看一下链接,这里列出序列化的代码实例:

如对于我自定义的一个增益属性类Plugin

public class Camp
{public int camp;
}

有两种注册方式(其实差别不大,只是其中一个使用了Photon提供给我们的流)来进行注册,这里只展示第一种

即扩展该类,添加序列化和反序列化的静态方法:

public class Camp
{public int camp;public static byte[] SerializableClass(object plugin)//参数必须是object{Campp = (Camp) plugin;int intlen = Marshal.SizeOf(typeof(int));/** 创建字节序列*/byte[] bytes = new byte[intlen];/** 序列化*/int index = 0;Protocol.Serialize(p.camp, bytes, ref index);return bytes;}public static object DeserializeClass(byte[] bytes){Plugin plugin = new Plugin();int index = 0;Protocol.Deserialize(out plugin.camp, bytes, ref index);return plugin;}
}

随后在任意位置注册一次即可:

PhotonPeer.RegisterType(typeof(Plugin), (byte) 'a',SerializableClass,DeserializeClass);

注意关于第二个是类似占位符的形式,已经注册过的byte不能再次注册,以及被官方注册过的字节有:W/V/Q/P这四种,分别代表Vector3,Vector2,QuaternionPhotonPlayer

然后关于一些其他的字节之间相互转化的方法可以参考一下极客学院的关于Photon的一个公开课,链接,这里就不详细展开了


然后我基于build模式和最近rx系列的思路写了一个传输类,能简化一下stream传输的逻辑,也附在这吧


public class PhotonTranser
{private PhotonStream stream;public static PhotonTranser create(PhotonStream stream){return new PhotonTranser(stream);}private PhotonTranser(PhotonStream stream){this.stream = stream;}public PhotonTranser sendnext(object value,bool realSend){if (realSend &&stream.isWriting) {stream.SendNext(value);}return this;}public PhotonTranser sendnext(object value){if (stream.isWriting){stream.SendNext(value); }return this;}public PhotonTranser receive(Func<object, object> value,bool realRecv){if (realRecv &&!stream.isWriting){value(stream.ReceiveNext());}return this;}public PhotonTranser receive(Func<object, object> value){if (!stream.isWriting){value(stream.ReceiveNext());    }return this;}public void finish(){}}

按照该类的实现,PhotonRigidbodyView中的OnPhotonSerializeView实现就可以改为:

PhotonTranser.create(stream).sendnext(this.m_Body.velocity, this.m_SynchronizeVelocity).sendnext(this.m_Body.angularVelocity,this.m_SynchronizeAngularVelocity).receive(new Func<object, object>(delegate(object o){this.m_Body.velocity = (Vector3) o;return null;}), this.m_SynchronizeVelocity).receive(new Func<object, object>(delegate(object o){this.m_Body.angularVelocity = (Vector3) o;return null;}),this.m_SynchronizeAngularVelocity  ).finish();

感觉这样下来会就比较直观,不过由于C#半路出家..一些语法不是很了解,不清楚有没有更简单的实现方式,比如lambda等(猜的),有人有思路可以提供一下

第三种方法有条件,就是只能在用PhotonNetwork.Instantiate实例化对象的时候传递,具体的方式可以参考一下我的这一篇博客:

Photon实例化(PhotonNetwork.Instantiate参数详解)

这篇关于Unity问题与解决方案:Photon同步数据的四种方式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/284190

相关文章

Java中注解与元数据示例详解

《Java中注解与元数据示例详解》Java注解和元数据是编程中重要的概念,用于描述程序元素的属性和用途,:本文主要介绍Java中注解与元数据的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参... 目录一、引言二、元数据的概念2.1 定义2.2 作用三、Java 注解的基础3.1 注解的定义3.2 内

将sqlserver数据迁移到mysql的详细步骤记录

《将sqlserver数据迁移到mysql的详细步骤记录》:本文主要介绍将SQLServer数据迁移到MySQL的步骤,包括导出数据、转换数据格式和导入数据,通过示例和工具说明,帮助大家顺利完成... 目录前言一、导出SQL Server 数据二、转换数据格式为mysql兼容格式三、导入数据到MySQL数据

Java中List转Map的几种具体实现方式和特点

《Java中List转Map的几种具体实现方式和特点》:本文主要介绍几种常用的List转Map的方式,包括使用for循环遍历、Java8StreamAPI、ApacheCommonsCollect... 目录前言1、使用for循环遍历:2、Java8 Stream API:3、Apache Commons

C++中使用vector存储并遍历数据的基本步骤

《C++中使用vector存储并遍历数据的基本步骤》C++标准模板库(STL)提供了多种容器类型,包括顺序容器、关联容器、无序关联容器和容器适配器,每种容器都有其特定的用途和特性,:本文主要介绍C... 目录(1)容器及简要描述‌php顺序容器‌‌关联容器‌‌无序关联容器‌(基于哈希表):‌容器适配器‌:(

C#提取PDF表单数据的实现流程

《C#提取PDF表单数据的实现流程》PDF表单是一种常见的数据收集工具,广泛应用于调查问卷、业务合同等场景,凭借出色的跨平台兼容性和标准化特点,PDF表单在各行各业中得到了广泛应用,本文将探讨如何使用... 目录引言使用工具C# 提取多个PDF表单域的数据C# 提取特定PDF表单域的数据引言PDF表单是一

四种Flutter子页面向父组件传递数据的方法介绍

《四种Flutter子页面向父组件传递数据的方法介绍》在Flutter中,如果父组件需要调用子组件的方法,可以通过常用的四种方式实现,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录方法 1:使用 GlobalKey 和 State 调用子组件方法方法 2:通过回调函数(Callb

一文详解Python中数据清洗与处理的常用方法

《一文详解Python中数据清洗与处理的常用方法》在数据处理与分析过程中,缺失值、重复值、异常值等问题是常见的挑战,本文总结了多种数据清洗与处理方法,文中的示例代码简洁易懂,有需要的小伙伴可以参考下... 目录缺失值处理重复值处理异常值处理数据类型转换文本清洗数据分组统计数据分箱数据标准化在数据处理与分析过

大数据小内存排序问题如何巧妙解决

《大数据小内存排序问题如何巧妙解决》文章介绍了大数据小内存排序的三种方法:数据库排序、分治法和位图法,数据库排序简单但速度慢,对设备要求高;分治法高效但实现复杂;位图法可读性差,但存储空间受限... 目录三种方法:方法概要数据库排序(http://www.chinasem.cn对数据库设备要求较高)分治法(常

Vue项目中Element UI组件未注册的问题原因及解决方法

《Vue项目中ElementUI组件未注册的问题原因及解决方法》在Vue项目中使用ElementUI组件库时,开发者可能会遇到一些常见问题,例如组件未正确注册导致的警告或错误,本文将详细探讨这些问题... 目录引言一、问题背景1.1 错误信息分析1.2 问题原因二、解决方法2.1 全局引入 Element

虚拟机与物理机的文件共享方式

《虚拟机与物理机的文件共享方式》文章介绍了如何在KaliLinux虚拟机中实现物理机文件夹的直接挂载,以便在虚拟机中方便地读取和使用物理机上的文件,通过设置和配置,可以实现临时挂载和永久挂载,并提供... 目录虚拟机与物理机的文件共享1 虚拟机设置2 验证Kali下分享文件夹功能是否启用3 创建挂载目录4