Эта строка
_ = GameObject.Find("cubo Variant").GetComponent<CollisionController>().active;
не имеет смысла. Прежде всего, нет поля или переменной, объявленной с именем _
, так что это вообще не должно компилироваться. А во-вторых, зачем тебе это? Скорее сохраните соответствующую ссылку один раз в поле controller
и используйте ее позже.
Тогда для вашего варианта использования вообще не нужно хранить значение в локальной переменной ... это только усложняет ситуацию. Просто там, где вам нужно, получите значение из controller.active
.
Также не используйте ==
для тегов. Скорее проверьте через CompareTag
. Проблема в том, что ==
молча терпит неудачу, если у вас есть опечатка или тег не существует вообще. CompareTag
скорее выдает ошибку о том, что данный тег недействителен.
public class EmptyControllerColl : MonoBehaviour
{
// Best already drag this in via the Inspector in Unity
[SerializeField] private CollisionController controller;
public PlayerMovement movement;
// As fallback get it ONCE on runtime
private void Awake()
{
// since you say the cube is a child of this empty object you do not use
// Find at all but can simply use GetComponentInChildren
if(!controller) controller = GetComponentInChildren<CollisionController>(true);
}
void Update()
{
// No need to store this in a local field at all
if(!controller.active)
{
Debug.Log("Nothing...");
}
// use if else since both cases are exclusive and you don't even need to check the value twice
else
{
Debug.Log("Game over");
}
}
}
Event Driven - part A
В общем, вы должны избегать проверок опроса для значения bool в Update
и, скорее, придумайте более управляемое событиями решение! Пример может выглядеть следующим образом:
public class CollisionController : MonoBehaviour
{
public PlayerMovement movement;
// Here everyone who wants can add listeners that get called as soon as
// we invoke this event. We will do it everytime the 'active' value is changed
public event Action<bool> OnActiveStateChanged;
// Backing field for 'active'
private bool _active;
// Property that reads and writes '_active'
// Everytime it is assigned it also invokes 'OnActiveStateChanged'
private bool active
{
get { return _active; }
set
{
_active = value;
OnActiveStateChanged?.Invoke(_active);
}
}
private void OnCollisionEnter(Collision collision)
{
if(collision.collider.CompareTag("Obstacle"))
{
active = true;
}
}
}
Теперь вы зарегистрируете прослушиватель для этого события, например
public class EmptyControllerColl : MonoBehaviour
{
// Best already drag this in via the Inspector in Unity
[SerializeField] private CollisionController controller;
public PlayerMovement movement;
// As fallback get it ONCE on runtime
private void Awake()
{
// since you say the cube is a child of this empty object you do not use
// Find at all but can simply use GetComponentInChildren
if(!controller) controller = GetComponentInChildren<CollisionController>(true);
// register a callback. It is allowed an save to unregister first
// which makes sure this is only registered exactly once
controller.OnActiveStateChanged -= HandleControlerActiveStateChanged;
controller.OnActiveStateChanged += HandleControlerActiveStateChanged;
}
private void HandleGameOver()
{
Debug.Log("Game over");
}
private void HandleControlerActiveStateChanged(bool value)
{
if(!value)
{
Debug.Log("Nothing...");
}
else
{
Debug.Log("Game over");
}
}
private void OnDestroy()
{
// always clean up listeners
controller.OnActiveStateChanged -= HandleControlerActiveStateChanged;
}
}
Теперь это намного эффективнее, поскольку вы не все время запускаете Update
метод. Вместо этого HandleControlerActiveStateChanged
вызывается только тогда, когда значение active
действительно изменяется.
Event Driven - part B
И тогда фактически в вашем случае есть необходимость использовать bool
на всех вы могли бы вместо этого использовать простой event Action
и полностью удалить все bools
:
public class CollisionController : MonoBehaviour
{
public PlayerMovement movement;
public event Action OnGameOver;
private void OnCollisionEnter(Collision collision)
{
if(collision.collider.CompareTag("Obstacle"))
{
OnGameOver?.Invoke();
}
}
}
Теперь вы зарегистрируете прослушиватель для этого события, например
public class EmptyControllerColl : MonoBehaviour
{
[SerializeField] private CollisionController controller;
public PlayerMovement movement;
private void Awake()
{
if(!controller) controller = GetComponentInChildren<CollisionController>(true);
controller.OnGameOver -= HandleGameOver;
controller.OnGameOver += HandleGameOver;
}
private void HandleGameOver()
{
Debug.Log("Game over");
}
private void OnDestroy()
{
controller.OnGameOver -= HandleGameOver;
}
}