簡體   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