当涉及到将玩家引用到另一个对象的脚本时,Unity使我感到困惑。我使用了几种方法来引用localPlayer对象:
gameObject.Name
(从未使用过,但也不可靠)public GameObject Player;
(播放器为预制件时会出现问题)public static [PlayerControllerClass] instance;
函数中进行instance = this
并设置void Start()
。为了从另一个脚本访问playerSpeed
,我要做PlayerControllerClass.instance.playerSpeed = 10;
还有其他解决方案,可以通过适当的方式推荐玩家。
注意::我知道我的问题可能与特定问题无关,但是如果有人可以提供帮助,我可以进一步解释。
编辑1:例如,我想在一个网络游戏中找到
localPlayer
,其中所有玩家都具有相同的名称,相同的标签,但是只有一个玩家是localPlayer。我可以从其他脚本访问localPlayer
吗?Edit2:我接受的答案是我感觉最好的答案。我将使用
score text
的{{1}}预览中提供的答案,方法是从一组访问玩家[localPlayer
]
答案 0 :(得分:4)
您的问题直到您进行编辑后才清楚,然后我意识到这是一个网络问题。
我需要在所有玩家都拥有的NetworkGame中找到localPlayer 相同的名称,相同的标签,但只有一个玩家是本地玩家 来自另一个脚本的localPlayer?
您可以找到带有NetworkConnection.playerControllers
的玩家,该玩家重新进入PlayerController
的列表,然后在其上循环并检查其是否有效。之后,从中获取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
属性。您还可以找到GameObject,然后检查NetworkIdentity
和isLocalPlayer
属性。
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
的GameObject,此后,您可以使用GetComponent
函数来获取附加到它的脚本。
我注意到您提到过您也想在现场引用预制件。预制件和已经存在于场景中的对象之间是有区别的,它们都有不同的引用它们的方式。
这里是场景中对象的示例。您可以在层次结构标签中看到它们:
让我们通过名称引用“画布”游戏对象:
GameObject canvasObj = GameObject.Find("Canvas");
让我们参考Canvas
脚本附加到“画布”游戏对象的情况:
GameObject canvasObj = GameObject.Find("Canvas");
Canvas canvas = canvasObj.GetComponent<Canvas>();
预制件:
以下是“项目”选项卡中的预制件示例:
将预制件放在名为“资源”的文件夹中。您必须使用Resources
API来引用它们。
让我们参考“胶囊”预制游戏对象:
GameObject prefab = Resources.Load<GameObject>("Capsule");
要使用它,必须实例化它:
GameObject instance = Instantiate(prefab);
实例化后,您只能在预制件上获得组件:
CapsuleCollider cc = instance.GetComponent<CapsuleCollider>();
答案 1 :(得分:1)
我建议使用Singleton模式。我几乎在我的所有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();
}
然后您可以像这样创建一个类:
public class MyClass : SingletonBehaviour<MyClass>
{
public void OnInitialize()
{
// You can use this instead of awake or start
}
public void DoStuff();
}
并这样称呼它:
MyClass.Instance.DoStuff()
答案 2 :(得分:1)
I have always sought usage of GameObject.FindGameObjectsWithTag when I need multiple references or else GameObject.FindWithTag when I need just the one reference to a specific GameObject available in the system.
To reference a script on said GameObject (found using the API reference above), you simply use `` as described in GameObject.GetComponent API reference.
A complete example would be:
PlayerA
.GameObject player = GameObject.FindWithTag("PlayerA");
PlayerScript playerScript = player.GetComponent<PlayerScript>();
I hope this helps and should you require further clarification, I'll be more than happy to help.
EDIT: Another solution:
Concern: 50 or x
amount of players would be too mundane to assign tags.
Solution: If you have a set of 50 players:
ParentPlayer