繁体   English   中英

当所有玩家具有相同名称时,找到localPlayer

[英]Find localPlayer when all players have same name

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

  1. 比较标签(在某些情况下不太好)
  2. gameObject.Name (从未使用过但它也不可靠)
  3. 分配public GameObject Player; 在检查器中拖放 (当播放器是预制件时面临问题)
  4. 制作public static [PlayerControllerClass] instance; 并设置instance = this in void Start() function。为了从另一个脚本访问playerSpeed ,我做了PlayerControllerClass.instance.playerSpeed = 10;

是否有其他解决方案以适当的方式引用玩家。

注意:我知道我的问题可能与某个特定问题无关,但如果有人会提供帮助,我可以解释一下。

Edit1:例如我想在localPlayer中找到localPlayer ,其中所有玩家具有相同的名称,相同的标签,但只有一个玩家是localPlayer。 我可以从其他脚本访问localPlayer吗?

编辑2:我接受的答案是我感觉最好的。我将使用在预览localPlayerscore text时提供的答案,方法是从一组玩家[ localPlayer ]访问它

你的问题直到编辑后才明确,然后我意识到这是一个网络问题。

我需要在NetworkGame中找到localPlayer,其中所有玩家具有相同的名称,相同的标签但只有一个玩家是localPlayer我可以从另一个脚本访问localPlayer吗?

你可以找到使用NetworkConnection.playerControllers玩家,它重新获得PlayerController List然后循环它并检查它是否有效。 之后,从中获取NetworkBehaviour,检查isLocalPlayer属性。 真的是这样的。

像这样的东西:

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;
}

如果您将NetworkIdentity附加到播放器而不是NetworkBehaviour ,只需获取NetworkIdentity并检查isLocalPlayer属性。 您还可以找到isLocalPlayer然后检查NetworkIdentityisLocalPlayer属性。

if (obj.GetComponent<NetworkIdentity>().isLocalPlayer){}

您可能需要的其他有用的玩家操作:

找到所有玩家

List<GameObject> ListPlayers()
{
    NetworkManager networkManager = NetworkManager.singleton;
    List<PlayerController> pc = networkManager.client.connection.playerControllers;

    List<GameObject> players = new List<GameObject>();
    for (int i = 0; i < pc.Count; i++)
    {
        if (pc[i].IsValid)
            players.Add(pc[i].gameObject);
    }
    return players;
}

按名称查找玩家(也可以按标签或图层更改)

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.Find ,在此之后,你可以使用GetComponent函数来获得被连接到它的脚本。

我注意到你提到你想在场景中引用预制件。 预制件和已经存在的对象之间存在差异,它们都有不同的方式来引用它们。

以下是场景中对象的示例。 您可以在“ 层次结构”选项卡中看到它们:

在此输入图像描述

让我们按名称引用“Canvas”GameObject:

GameObject canvasObj = GameObject.Find("Canvas");

让我们将Canvas脚本附件引用到“Canvas”GameObject:

GameObject canvasObj = GameObject.Find("Canvas");
Canvas canvas = canvasObj.GetComponent<Canvas>();

预制件:

以下是“项目”选项卡中预制件的示例:

在此输入图像描述

将预制件放在名为“Resources”的文件夹中。 您必须这样才能使用Resources API引用它们。

让我们参考“Capsule”预制游戏对象:

GameObject prefab = Resources.Load<GameObject>("Capsule");

要使用它,您必须实例化它:

GameObject instance = Instantiate(prefab);

在实例化后,您只能在预制件上获取组件:

CapsuleCollider cc = instance.GetComponent<CapsuleCollider>();

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

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();
}

然后,您可以创建一个类,如下所示:

public class MyClass : SingletonBehaviour<MyClass>
{
    public void OnInitialize()
    {
        // You can use this instead of awake or start
    }

    public void DoStuff();
}

并称之为:

MyClass.Instance.DoStuff()

当我需要多个引用时,我总是寻求使用GameObject.FindGameObjectsWithTag;当我只需要对系统中可用的特定GameObject的一个引用时,我一直在寻找GameObject.FindWithTag

要在所述GameObject上引用脚本(使用上面的API参考找到),您只需使用GameObject.GetComponent API引用中所述的``。

一个完整的例子是:

  1. 将标记分配给您的Player PlayerA例如PlayerA
  2. GameObject player = GameObject.FindWithTag("PlayerA");
  3. PlayerScript playerScript = player.GetComponent<PlayerScript>();

我希望这有帮助,如果您需要进一步澄清,我将非常乐意提供帮助。

编辑:另一种解决方案:

关注:50或x数量的玩家太平凡无法分配标签。

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

  1. 我会将它们分组在父GameObject下。
  2. 为父ParentPlayer分配一个标签,例如ParentPlayer
  3. 使用GetComponentsInChildren引用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM