C# 如何在UNet(Unity)中对客户端调用[Command]

C# 如何在UNet(Unity)中对客户端调用[Command],c#,unity3d,multiplayer,unity3d-unet,C#,Unity3d,Multiplayer,Unity3d Unet,我正在使用UNet制作一个Unity 2D多人游戏。我的问题是客户端无法将[命令]发送到服务器。我在UnityEdit上调试,并为我的android手机安装了一个内置的apk 首先,我使用UnityEditor作为主机,手机作为客户端,控制台上会出现Debug.Log(SkinName) 然后我使用UnityEdit作为客户端,手机作为主机,调试日志(SkinName)不会出现 我尝试使用[ClientRpc]而不是[Client],但这只会让情况变得更糟,客户端和主机都无法同步。我不知道我是否

我正在使用UNet制作一个Unity 2D多人游戏。我的问题是客户端无法将
[命令]
发送到服务器。我在UnityEdit上调试,并为我的android手机安装了一个内置的apk

首先,我使用UnityEditor作为主机,手机作为客户端,控制台上会出现
Debug.Log(SkinName)

然后我使用UnityEdit作为客户端,手机作为主机,调试日志(SkinName)
不会出现

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

我访问了其他线程/论坛和其他UNet教程来寻找解决方案,但这就是我想到的

注意:在我访问的其他线程中,人们大多建议取消选中本地播放器权限,这就是导致问题的原因,但在本例中,它是
选中的

代码:

使用UnityEngine;
使用系统集合;
使用UnityEngine。联网;
使用脊柱;
使用脊柱。团结;
使用Spine.Unity.Modules;
SetupLocalPLayer类:网络行为{
[同步变量]
公共字符串名称;
公共字符串[]字符名;
公共字符串[]SlotNames;
公共字符串[]AttachmentSuffix;
无效开始(){
传人皮肤();
SyncSkin();
if(IsLocalLayer){
var skeletonrenderer=GetComponent();

对于(intz=0;zOk),我可以看到您正在尝试同步每个玩家使用的皮肤,以便每个玩家在每个客户端上都有正确的皮肤

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

首先让我们看看语法

您绝对应该使用
[ClientRpc]
而不是
[Client]
,并且该方法应命名为
rpctrTransmistskins
。如果脚本附加到播放机预置,并且在网络标识上检查了本地播放机权限,则该方法将起作用。
[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]);
            }
        }
    }
void Start(){
//首先,在每个版本的播放器上获取SkeletonRenderer。
//请注意,现在它不应该是本地变量,而是脚本中的一个字段
skeletonrenderer=GetComponent();
//现在做本地玩家特定的事情
if(IsLocalLayer){
//将皮肤名称传输到播放器的其他版本
CmdSendSkinRpc(GameController.control.skinName);
//然后将蒙皮指定给播放器的本地版本

对于(int z=0;z建议也添加unet标记。添加,你能帮我吗,先生?它困扰了我好几天:(我希望我可以,我已经尝试过unet系统,但失败了。这就是为什么我认为你最好撒一个更大的网。对不起,伙计。顺便问一下,在这个脚本中我应该使用[SyncVar]?不,这里不需要。SyncVar只从服务器>客户端同步,而且经常同步。据我所知,您只需要在启动时同步一次。事实上,我认为您可以摆脱SkinName。我尝试了代码,结果是,在主机上,两个播放器的外观相同。[链接]现在在主机上可以了,但在客户端发生了这种情况。[link]。蓝头发的角色应该是一个黑发的家伙,并给出了此错误NullReferenceException:对象引用未设置为对象SetupLocalPLayer.rpCtrTransmistSkins(System.String TransmittedSkinName)(位于Assets/Scripts/SetupLocalPLayer.cs:52)
    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]);
            }
        }
    }