如何在 UNet(Unity) 的客户端调用 [Command]

How to call [Command] on Client in UNet(Unity)

我正在使用 UNet 开发 Unity 2D 多人游戏。我的问题是客户端无法将 [Command] 发送到服务器。我在 UnityEditor 上调试,并为我的 android phone 构建了一个 apk。

首先我使用UnityEditor作为Host,phone作为Client,Debug.Log(SkinName) APPEARS on the console

然后我用UnityEditor作为Client,phone作为Host,Debug.Log(SkinName) DOES NOT APPEAR.

我尝试使用 [ClientRpc] 而不是 [Client],但这只会让情况变得更糟,客户端和主机都不会同步。我不知道我是否以正确的方式执行了 [ClientRpc]。(我是 UNet 的菜鸟)

我已经访问了其他 threads/forums 和其他 UNet 教程来寻找解决方案,但这就是我想出的。

注意:在我访问的其他线程中,大多数人都建议未选中本地玩家权限,这就是导致问题的原因,但在这种情况下是 CHECKED

代码:

using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
using Spine;
using Spine.Unity;
using Spine.Unity.Modules;

class SetupLocalPLayer : NetworkBehaviour {
[SyncVar]
public string SkinName;

public string[] CharNames;
public string[] SlotNames;
public string[] AttachmentSuffix;

void Start (){
    TransmitSkins ();
    SyncSkin ();
    if (isLocalPlayer) {
        var skeletonrenderer = GetComponent<SkeletonRenderer>();
        for(int z=0;z<SlotNames.Length;z++){
            skeletonrenderer.skeleton.SetAttachment(SlotNames[z],GameController.control.skinName+AttachmentSuffix[z]);
        }
        GetComponent<PlayerManager> ().enabled = true;
        GetComponent<FollowCam> ().enabled = true;
    }
}
void Update () {

}

void SyncSkin(){
    if (!isLocalPlayer) {
        var skeletonrenderer = GetComponent<SkeletonRenderer>();
        for(int z=0;z<SlotNames.Length;z++){
            skeletonrenderer.skeleton.SetAttachment(SlotNames[z],SkinName+AttachmentSuffix[z]);
        }
    }
}

[Command]
void CmdSetSkin(){
    SkinName = GameController.control.skinName;
    Debug.Log (SkinName);
}

[Client]
void TransmitSkins(){
    if (isLocalPlayer) {
        CmdSetSkin ();
    }
}

}

好的,据我所知,您正在尝试同步每个玩家使用的皮肤,以便每个玩家在每个客户端上都有正确的皮肤。

您的代码在语法和结构方面都存在一些问题。

首先让我们看一下语法。

绝对应该使用 [ClientRpc] 而不是 [Client] 并且该方法应该命名为 RpcTransmitSkins。如果脚本附加到播放器预制件并且在网络身份上检查了本地播放器权限,那么它将起作用。 [Client] 完全属于不同的网络 API。

现在让我们看看结构。

基本逻辑是正确的,但实际上,SyncSkin 方法会在接收到传输之前很久就被调用。

Start 方法不会等待传输,所以为什么不将皮肤分配移动到 Rpc,这样其他版本的播放器只会在收到消息后才尝试分配皮肤。

您还拆分了所有客户端需要执行的某些操作,例如获取 SkeletonRenderer

以下是我将如何重构您的脚本。

    void Start (){
        //first, grab the SkeletonRenderer on every version of the player. 
        //note that it should not be a local var now, but a field in the script
        skeletonrenderer = GetComponent<SkeletonRenderer>();

        //now do the local player specific stuff
        if (isLocalPlayer) {

            //transmit the skin name to the other versions of the player
            CmdSendSkinRpc(GameController.control.skinName);

            //then assign the skin to the local version of the player
            for(int z=0;z<SlotNames.Length;z++){
                skeletonrenderer.skeleton.SetAttachment(SlotNames[z],GameController.control.skinName+AttachmentSuffix[z]);
            }
            GetComponent<PlayerManager> ().enabled = true;
            GetComponent<FollowCam> ().enabled = true;
        }
    }

    [Command]
    void CmdSendSkinRpc(string skin){
        RpcTransmitSkins(skin);
        Debug.Log("Transmitting Skin Named: " + skin);
    }

    [ClientRpc]
    void RpcTransmitSkins(string TransmittedSkinName){
        if (!isLocalPlayer) {
            Debug.Log("Receiving Skin Named: " + TransmittedSkinName);
            for(int z=0;z<SlotNames.Length;z++){
                skeletonrenderer.skeleton.SetAttachment(SlotNames[z],TransmittedSkinName+AttachmentSuffix[z]);
            }
        }
    }

不要对 UNET 系统的学习曲线感到沮丧。用多客户端和服务器的术语来思考是非常令人困惑的。即使是这个简单的动作也让我挠头了几分钟 :D