我目前正在做一个3D无止境的跑步游戏与选择选择不同的皮肤为玩家。一切都进行得很顺利,直到我遇到了一个问题,在这个问题中,我试图将两个碰撞游戏对象分配给容器中的每个字符,以便当玩家的碰撞盒与powerup发生冲突时,能够检测到它的冲突。
它只检测第一个游戏容器的(Milo)‘硬币检测’游戏对象(即使它已被停用),并且不识别坏蛋playerContainer中的‘硬币检测’碰撞游戏对象(玩家已选择使用该游戏对象)。
因此,我的问题是,我如何能够获得脚本来识别第三个playerContainer游戏对象中活动的子对象,而不是自动检测第一个playerContainer游戏对象的子对象?
从我制作的Magnet脚本中,脚本只检测到第一个playerContainer的“硬币检测”游戏对象。如附图所示:
这是我当前的脚本,玩家可以选择他们的首选字符。
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发生冲突时激活了它。
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);
}
}
发布于 2021-12-07 08:55:16
您的问题是,您正在执行GameObject.FindGameObjectWithTag("CoinDetect")
,它将返回您当前场景中第一次遇到的CoinDetect
。因此,除非在EnablePlayerSelector.Start
之前执行,否则它将始终是第一个,因为到那时它们仍然都是活动的。
您可能已经可以通过遵循一般的经验规则来解决问题了:
Awake
中的其他组件的情况下执行这些操作Start
中其他组件的事情通过这种方式,您已经涵盖了大多数用例,并且确保组件在Start
中访问组件之前是自初始化的(Start
)。
因此,只需将EnablePlayerSelector.Start
转换为Awake
,就可以了。
在非常特殊的情况下,您可能仍然需要调整脚本执行顺序或使用事件。
不过,我宁愿在碰撞的时刻直接向PlayerContainer
请求当前的请求,而不是这样做:
// 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;
}
然后宁愿拥有
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);
}
}
}
然后最后再做。
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
组件的对象,您也可以直接这样做。
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);
}
}
https://stackoverflow.com/questions/70255337
复制相似问题