PUN2:通过 RPC 调用指定一个实例化的玩家游戏对象
Posted
技术标签:
【中文标题】PUN2:通过 RPC 调用指定一个实例化的玩家游戏对象【英文标题】:PUN2: Specify an instanced player gameObject through RPC call 【发布时间】:2021-10-26 15:13:23 【问题描述】:我知道您不能通过 RPC 调用传递 gameObject 引用,因为每个客户端对每个实例都使用它自己的唯一引用。有没有办法通过 RPC 调用引用所有客户端上的特定游戏对象?
这是我想要完成的一个示例
if(Input.GetKeyDown("r"))
PhotonView.RPC("ChangeReady", RPCTarget.AllBuffered, gameObject)
[PunRPC]
void ChangeReady(GameObject PLAYER)
PlayerScript PSCRIPT = PLAYER.GetComponent<PlayerScript>();
if (PSCRIPT.READY)
PSCRIPT.GetComponent<PlayerScript>().READY = false;
else
PSCRIPT.READY = true;
我正在尝试为玩家创建一个就绪检查系统,以便他们可以打开和关闭就绪状态,并将信息传输给其他客户端。不确定如何引用特定的游戏对象,因为如前所述,这在 RPC 中是不可能的。
我该怎么做呢?
【问题讨论】:
【参考方案1】:有几种方法可以做到这一点,如果你只想设置一个就绪状态:
a) 使用CustomProperties
,它允许您将特定于玩家的数据存储在键值对中。然后,您可以在本地检查玩家游戏对象上的这些值,并使用您的 RPC 更改它们的行为。这是一个例子:
bool ready = (bool)PhotonNetwork.player.customProperties["Ready"];
Hashtable hash = new Hashtable();
hash.Add("Ready", true);
PhotonNetwork.player.SetCustomProperties(hash);
Follow this link for info on CustomProperties
b) 通过在你的 Monobehaviour 上实现 IPunMagicInstantiateCallback
来使用 OnPhotonInstantiate
void OnPhotonInstantiate(PhotonMessageInfo info)
// e.g. store this gameobject as this player's charater in Player.TagObject
info.sender.TagObject = this.GameObject;
TagObject 可帮助您将 GameObject 与特定玩家相关联。因此,一旦它们被实例化,就会自动调用,并且您的 GameObject 可以绑定到玩家并使用 Player.TagObject
检索并执行您的就绪状态逻辑(通过 RPC 或任何其他方式)
Follow this link for info about OnPhotonInstantiate
【讨论】:
【参考方案2】:见Photon RPC and RaiseEvent => "你可以添加多个参数只要PUN可以序列化它们" -> 见Photon - Supported Types for Serialization
=> 不,这是不可能的。
解决方案
您总是需要一种方法来告诉其他设备您指的是哪个对象,因为它们与您的引用不同。
如果您指的是您的光子播放器的对象,但您可以改为发送
PhotonNetwork.LocalPlayer.ActorNumber
另一方面,通过ActorNumber
获取GameObject
。
有多种方法可以做到这一点。
我曾经通过像这样的中心类来做到这一点
public class PhotonUserManager : IInRoomCallbacks, IMatchmakingCallbacks
private static PhotonUserManager _instance;
private readonly Dictionary<int, GameObject> _playerObjects = new Dictionary<int, GameObject>();
public static bool TryGetPlayerObject(int actorNumber, out GameObject gameObject)
return _instance._playerObjects.TryGetValue(actorNumber, out gameObject);
[RuntimeInitializeOnLoadMethod]
private static void Init()
_instance = new PhotonUserManager();
PhotonNetwork.AddCallbackTarget(_instance);
public void OnCreateRoomFailed(short returnCode, string message)
public void OnJoinRoomFailed(short returnCode, string message)
public void OnCreatedRoom()
public void OnJoinedRoom()
Refresh();
public void OnLeftRoom()
_playerObjects.Clear();
public void OnJoinRandomFailed(short returnCode, string message)
public void OnFriendListUpdate(List<FriendInfo> friendList)
public void OnPlayerEnteredRoom(Player newPlayer)
Refresh();
public void OnPlayerLeftRoom(Player otherPlayer)
if(_playerObjects.ContainsKey(otherPlayer.ActorNumber))
_playerObjects.Remove(otherPlayer.ActorNumber);
public void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
public void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
public void OnMasterClientSwitched(Player newMasterClient)
private void Refresh()
var photonViews = UnityEngine.Object.FindObjectsOfType<PhotonView>();
foreach (var view in photonViews)
var player = view.owner;
//Objects in the scene don't have an owner, its means view.owner will be null => skip
if(player == null) continue;
// we already know this player's object -> nothing to do
if(_playerObjects.ContainsKey(player.ActorNumber)) continue;
var playerObject = view.gameObject;
_playerObjects[player.ActorNumber] = playerObject;
这会自动收集加入玩家拥有的GameObject
。当然有一个限制:如果玩家自己生成任何东西并拥有它......它可能会失败,因为那时每个玩家有多个PhotonView
s => 在这种情况下使用具有最低 NetworkIdendity 的那个。在 Photon 中,viewID 由第一个数字 = ActorNumber
+ 3 个数字 id 组成;)
以后做
if(!PhotonUserManager.TryGetPlayerObject(out var obj))
Debug.LogError($"Couldn't get object for actor number receivedActorNumber");
作为另一种选择,您可以使用OnPhotonInstantiate
public class SomeComponentOnYourPlayerPrefab : PunBehaviour
public override void OnPhotonInstantiate(PhotonMessageInfo info)
// only set if not already set in order to not
// overwrite the tag for a player that spawns something later
if(info.sender.TagObject == null)
info.sender.TagObject = gameObject;
然后再做
var obj = PhotonNetwork.LocalPlayer.Get(receivedActorNumber).TagObject;
【讨论】:
以上是关于PUN2:通过 RPC 调用指定一个实例化的玩家游戏对象的主要内容,如果未能解决你的问题,请参考以下文章
markdown Hadoop原生的基于Writable Sequence列化的RPC框架应用实例