C# 当所有玩家都有相同的名字时查找localPlayer

C# 当所有玩家都有相同的名字时查找localPlayer,c#,unity3d,networking,reference,C#,Unity3d,Networking,Reference,当涉及到将玩家引用到另一个对象的脚本时,Unity让我感到困惑。我使用了几种方法来引用localPlayer对象: 比较标记(在某些情况下不太好) gameObject.Name(从未使用过,但也不可靠) 分配公共游戏对象玩家在inspector中拖放(当玩家是预制玩家时面临问题) 制作公共静态[PlayerControllerClass]实例并在void Start()函数中设置instance=this 是否有其他合适的方法来引用玩家 注意:我知道我的问题可能与具体问题无关,但如果有人愿意帮

当涉及到将玩家引用到另一个对象的脚本时,Unity让我感到困惑。我使用了几种方法来引用localPlayer对象:

  • 比较标记(在某些情况下不太好)
  • gameObject.Name
    (从未使用过,但也不可靠)
  • 分配
    公共游戏对象玩家在inspector中拖放(当玩家是预制玩家时面临问题)
  • 制作
    公共静态[PlayerControllerClass]实例
    并在
    void Start()
    函数中设置
    instance=this
  • 是否有其他合适的方法来引用玩家

    注意:我知道我的问题可能与具体问题无关,但如果有人愿意帮忙,我可以解释更多

    Edit1:例如,我想在网络游戏中找到
    localPlayer
    ,其中所有玩家都有相同的名字、相同的标签,但只有一个玩家是localPlayer。我可以从另一个脚本访问
    localPlayer

    Edit2:我接受的答案是我感觉最好的答案。我将使用预览
    localPlayer
    score text
    中提供的答案,通过从一组玩家访问它[
    localPlayer
    ]


    我推荐单例模式。我在几乎所有的Unity项目中都实现了它,对象只有一个类,但它是一个单一行为

    using UnityEngine;
    
    
    public abstract class SingletonBehaviour<T> : MonoBehaviour where T : MonoBehaviour
    {
        public bool dontDestroyOnLoad = true;
        private bool isInitialized = false;
    
        private static T instance;
        public static T Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = FindObjectOfType<T>();
                    if (instance == null)
                    {
                        var obj = new GameObject
                        {
                            name = typeof(T).Name
                        };
                        instance = obj.AddComponent<T>();
                    }
                }
    
                return instance;
            }
        }
    
        protected virtual void Awake()
        {
            if (instance == null)
            {
                instance = this as T;
    
                if (dontDestroyOnLoad)
                {
                    DontDestroyOnLoad(this.transform.root.gameObject);
                }
            }
            else if (instance != this)
            {
                Destroy(gameObject);
            }
        }
    
    
        private void OnEnable()
        {
            if (!isInitialized)
            {
                OnInitialize();
                isInitialized = true;
            }
        }
    
        public abstract void OnInitialize();
    }
    

    在编辑之前,你的问题并不清楚,然后我意识到这是一个网络问题

    我需要在网络游戏中找到所有玩家都拥有的本地玩家 相同的名字,相同的标签,但只有一个玩家是本地玩家,我可以访问 来自另一个脚本的localPlayer

    您可以找到具有
    NetworkConnection.playerControllers
    的玩家,该玩家将返回
    PlayerController
    的列表,然后在其上循环并检查其是否有效。之后,从中获取NetworkBehavior并检查IsLocalLayer属性。就是这样

    大概是这样的:

    GameObject FindLocalNetworkPlayer()
    {
        NetworkManager networkManager = NetworkManager.singleton;
        List<PlayerController> pc = networkManager.client.connection.playerControllers;
    
        for (int i = 0; i < pc.Count; i++)
        {
            GameObject obj = pc[i].gameObject;
            NetworkBehaviour netBev = obj.GetComponent<NetworkBehaviour>();
    
            if (pc[i].IsValid && netBev != null && netBev.isLocalPlayer)
            {
                return pc[i].gameObject;
            }
        }
        return null;
    }
    
    您可能需要的其他有用的播放器操作:

    查找所有玩家:

    让我们将
    Canvas
    脚本附件引用到“Canvas”游戏对象:

    GameObject canvasObj = GameObject.Find("Canvas");
    Canvas canvas = canvasObj.GetComponent<Canvas>();
    
    GameObject prefab = Resources.Load<GameObject>("Capsule");
    
    要使用它,您必须实例化它:

    GameObject instance = Instantiate(prefab);
    
    只有在实例化组件之后,才能在预制件上获取组件:

    CapsuleCollider cc = instance.GetComponent<CapsuleCollider>();
    
    CapsuleCollider cc=instance.GetComponent();
    
    当我需要多个引用时,我总是寻求使用,或者当我只需要系统中可用的特定游戏对象的一个引用时,使用GameObject.FindWithTag

    要引用上述游戏对象上的脚本(使用上面的API引用找到),只需使用API引用中描述的``

    一个完整的例子是:

  • 为玩家游戏对象指定标签,例如
    PlayerA
  • gameobjectplayer=GameObject.FindWithTag(“PlayerA”)
  • PlayerScript PlayerScript=player.GetComponent()
  • 我希望这会有所帮助,如果您需要进一步澄清,我将非常乐意提供帮助

    编辑:另一个解决方案:

    担忧:50名或
    x
    玩家的数量太普通,无法分配标签

    解决方案:如果您有一组50名玩家:

  • 我会将它们分组在父游戏对象下
  • 为父游戏对象分配一个标签,例如
    ParentPlayer
  • 使用参考资料

  • 你的意思是在场景和层次选项卡中引用对象?是的,我的意思是我想通过使用GameObject.Find()来访问其他对象,如预设(预设,UI,…),如果对象有唯一的名称:)有
    FindObjectOfType
    ,然后可以使用
    。GameObject
    打开。对于
    localPlayer
    部分,您的网络使用什么
    NetworkBehavior
    具有
    IsLocalLayer
    属性(其他如
    OnStartLocalPlayer
    ,请参阅我将要搜索的关于
    Singleton
    的文档我已经看过多次但没有深入研究过这个词。它不适合所有场景,但它确实使处理GameManager、InventoryManager等类时的工作变得更轻松。这些类都不应该有超过1个实例。请随意使用我文章中的第一个代码片段。它已经可以使用了。谢谢你的回答,你已经接近我所需要的了,但是我需要知道一些事情。是否可以让每个标签都有50个标签,每个标签旁边都有玩家字母,每个玩家的标签都不同于其他人。我不认为这是解决方案。这是真的y视情况而定。如果你有一组50名玩家,我会将他们分组在一个父游戏对象下,给该父游戏对象一个标记,例如
    ParentPlayer
    ,然后使用引用。好的,现在根据我的理解,我必须实例化父游戏对象中的所有玩家(
    EmptyGameObject
    )然后浏览这些游戏对象,以了解哪一个是本地玩家?您是否假设只有一个名为
    localPlayer
    ?谢谢这解释了很多。为回答干杯!对于旧答案:我不擅长编码,但我得到的方式是,从资源文件夹加载预制并不总是最好的方式继续,特别是对于大型预制件(Resource.Load从磁盘加载预制件)。顺便说一句,由于编辑器在内存中加载资源文件夹,所以在编辑器中不会注意到这种减速。如果在inspector中直接引用预制件,unity将创建一个原型实例,并在实例化时从中“加载”(ofc价格是原型占用的内存)。@Nikaas是的,没错。使用。新用户使用AssetBundle的过程有点复杂,但更好。
    GameObject FindNetworkPlayer(string name)
    {
        NetworkManager networkManager = NetworkManager.singleton;
        List<PlayerController> pc = networkManager.client.connection.playerControllers;
    
        for (int i = 0; i < pc.Count; i++)
        {
            if ((pc[i].IsValid) && (name == pc[i].gameObject.name))
                return pc[i].gameObject;
        }
        return null;
    }
    
    GameObject canvasObj = GameObject.Find("Canvas");
    
    GameObject canvasObj = GameObject.Find("Canvas");
    Canvas canvas = canvasObj.GetComponent<Canvas>();
    
    GameObject prefab = Resources.Load<GameObject>("Capsule");
    
    GameObject instance = Instantiate(prefab);
    
    CapsuleCollider cc = instance.GetComponent<CapsuleCollider>();