Unity 3D переменная передачи бул между двумя объектами - PullRequest
0 голосов
/ 19 марта 2020

как я могу передать простую логическую переменную между двумя различными объектами? Я могу попробовать это, но не сработало ...

Первый скрипт:

  public class CollisionController : MonoBehaviour
{
    public PlayerMovement movement;
    public bool active = false;



    private void OnCollisionEnter(Collision collision)
    {
        if(collision.collider.tag == "Obstacle")
        {
            active = true;
        }
    }
}

Второй скрипт (который читает логическую переменную "active" )

   public class EmptyControllerColl : MonoBehaviour
{
    public CollisionController controller;
    public PlayerMovement movement;

    public bool activeLocal = false;

    private void Start()
    {
        GetComponentInChildren<CollisionController>();
    }
    void Update()
    {


        activeLocal = controller.active;

        if(activeLocal == false)
        {
            Debug.Log("Nothing...");
        }

        if(activeLocal == true)
        {
            Debug.Log("Game over");

        }
    }
}

Когда переменная bool "Active" меняет свой статус, переменная "activeLocal" не меняет статус .. Как я могу решить эту проблему?

Столкновение Контроллер «подключается» к объекту Cube.

EmptyControllerColl «подключается» к emptyGameObject (родительскому объекту Cube).

Ответы [ 2 ]

1 голос
/ 19 марта 2020

Эта строка

_ = 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;
    }
}
0 голосов
/ 19 марта 2020
using UnityEngine;

public class CollisionController : MonoBehaviour
{
    void Start()
    {
        // Calls the function ApplyDamage with a value of 5
        // Every script attached to the game object
        // that has an ApplyDamage function will be called.
        gameObject.SendMessage("ApplyDamage", 5.0);
    }
}

public class EmptyControllerColl : MonoBehaviour
{
    public void ApplyDamage(float damage)
    {
        print(damage);
    }
}

https://docs.unity3d.com/ScriptReference/GameObject.SendMessage.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...