首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >寻找脚本检测playerContainer游戏对象中的子对象的方法

寻找脚本检测playerContainer游戏对象中的子对象的方法
EN

Stack Overflow用户
提问于 2021-12-07 05:27:54
回答 1查看 34关注 0票数 0

我目前正在做一个3D无止境的跑步游戏与选择选择不同的皮肤为玩家。一切都进行得很顺利,直到我遇到了一个问题,在这个问题中,我试图将两个碰撞游戏对象分配给容器中的每个字符,以便当玩家的碰撞盒与powerup发生冲突时,能够检测到它的冲突。

它只检测第一个游戏容器的(Milo)‘硬币检测’游戏对象(即使它已被停用),并且不识别坏蛋playerContainer中的‘硬币检测’碰撞游戏对象(玩家已选择使用该游戏对象)。

因此,我的问题是,我如何能够获得脚本来识别第三个playerContainer游戏对象中活动的子对象,而不是自动检测第一个playerContainer游戏对象的子对象?

从我制作的Magnet脚本中,脚本只检测到第一个playerContainer的“硬币检测”游戏对象。如附图所示:

这是我当前的脚本,玩家可以选择他们的首选字符。

代码语言:javascript
运行
复制
using System.Collections.Generic;
using UnityEngine;

public class EnablePlayerSelector : MonoBehaviour
{

    public GameObject[] players;
    public int currPlayerCount;

    void Start()
    {
        currPlayerCount = PlayerPrefs.GetInt("SelectedPlayer", 0);

        foreach (GameObject player in players)
            player.SetActive(false);

        players[currPlayerCount].SetActive(true);
    }
}

这是一个脚本,我在脚本中禁用了“硬币检测”碰撞游戏对象,并在玩家与powerup发生冲突时激活了它。

代码语言:javascript
运行
复制
using System.Collections.Generic;
using UnityEngine;

public class Magnet : MonoBehaviour
{

    public GameObject coinDetect;

    void Start()
    {
        coinDetect = GameObject.FindGameObjectWithTag("CoinDetect");
        coinDetect.SetActive(false);
        Debug.Log("False");
    }

    private void OnTriggerEnter(Collider other)
    {
        if(other.gameObject.tag == "Player")
        {
            StartCoroutine(coinActivate());
            Destroy(transform.GetChild(0).gameObject);
        }
    }

    IEnumerator coinActivate()
    {
        Debug.Log("Hi");

        coinDetect.SetActive(true);
        yield return new WaitForSeconds(5f);
        coinDetect.SetActive(false);
    }

}
EN

回答 1

Stack Overflow用户

发布于 2021-12-07 08:55:16

您的问题是,您正在执行GameObject.FindGameObjectWithTag("CoinDetect"),它将返回您当前场景中第一次遇到的CoinDetect。因此,除非在EnablePlayerSelector.Start之前执行,否则它将始终是第一个,因为到那时它们仍然都是活动的。

您可能已经可以通过遵循一般的经验规则来解决问题了:

  • 在不依赖于Awake中的其他组件的情况下执行这些操作
  • 执行您希望依赖于Start中其他组件的事情

通过这种方式,您已经涵盖了大多数用例,并且确保组件在Start中访问组件之前是自初始化的(Start)。

因此,只需将EnablePlayerSelector.Start转换为Awake,就可以了。

在非常特殊的情况下,您可能仍然需要调整脚本执行顺序或使用事件。

不过,我宁愿在碰撞的时刻直接向PlayerContainer请求当前的请求,而不是这样做:

代码语言:javascript
运行
复制
// put this on each player root object
public class Player : MonoBehaviour
{
    // reference these via the Inspector
    [SerializeField] private GameObject coinDetector;
    [SerializeField] private GameObject playerrange;
    // ... and in general any information bout this Player that is relevant for other scripts

    // Readonly accessor property
    public GameObject CoinDetector => coinDetector;
}

然后宁愿拥有

代码语言:javascript
运行
复制
public class EnablePlayerSelector : MonoBehaviour
{
    [SerializeField] private Player[] players;
    [SerializeField] private int currPlayerCount;

    public Player CurrentPlayer => players[currPlayerCount];

    // In general do things where you don't depend on other scripts already in Awake
    // This way you could actually already solve your issue by keeping things where you do
    // depend on others in Start
    private void Awake()
    {
        currPlayerCount = PlayerPrefs.GetInt("SelectedPlayer", 0);

        for(var i = 0; i < players.Length; i++)
        {
            players[i].gameObject.SetActive(i == currPlayerCount);
        }
    }
}

然后最后再做。

代码语言:javascript
运行
复制
public class Magnet : MonoBehaviour
{
    public float effectDuration = 5f;

    private IEnumerator OnTriggerEnter(Collider other)
    {
        var playerSelector = other.GetComponentInParent<EnablePlayerSelector>();
        if(!playerSelector) yield break;
        
        Debug.Log("Hi");
        Destroy(transform.GetChild(0).gameObject);
        
        var coinDetect = playerSelector.CurrentPlayer.CoinDetector;

        coinDetect.SetActive(true);
        yield return new WaitForSeconds(effectDuration);
        coinDetect.SetActive(false);
    }
}

或者,如果本例中的other引用带有Player组件的对象,您也可以直接这样做。

代码语言:javascript
运行
复制
public class Magnet : MonoBehaviour
{
    public float effectDuration = 5f;

    private IEnumerator OnTriggerEnter(Collider other)
    {
        if(!other.TryGetComponent<Player>(out var player)) yield break;
        
        Debug.Log("Hi");
        Destroy(transform.GetChild(0).gameObject);
        
        var coinDetect = player.CoinDetector;

        coinDetect.SetActive(true);
        yield return new WaitForSeconds(effectDuration);
        coinDetect.SetActive(false);
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70255337

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档