简体   繁体   English

Unity 3d 在两个对象之间传递 bool 变量

[英]Unity 3d pass bool variable between two objects

how i can pass a simple boolean variable between two different object?我如何在两个不同的对象之间传递一个简单的布尔变量? I can try this but didn't work...我可以试试这个,但没有用...

First script:第一个脚本:

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



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

Second script (that read the boolean variable "active")第二个脚本(读取布尔变量“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");

        }
    }
}

When the variable bool "Active" change its status, the variable "activeLocal" don't change status.. How can I resolve this problem?当变量 bool "Active" 改变其状态时,变量 "activeLocal" 不会改变状态.. 我该如何解决这个问题?

Collision Controller is "connect" to Cube Object.碰撞控制器“连接”到立方体对象。

EmptyControllerColl is "connect" to emptyGameObject (parent of Cube). EmptyControllerColl 是“连接”到 emptyGameObject(Cube 的父级)。

This line这条线

_ = GameObject.Find("cubo Variant").GetComponent<CollisionController>().active;

makes no sense.没有意义。 First of all there is no field or variable declared with the name _ so this shouldn't even compile at all.首先,没有使用名称_声明的字段或变量,因此它根本不应该编译。 And secondly what do you need this for?其次,你需要这个做什么? Rather store the according reference once in the controller field and reuse it later.而是将相应的引用存储在controller字段中一次,然后再使用它。

Then for your usecase there is no need at all to store the value in a local variable ... this makes things only more complicated.然后对于您的用例,根本不需要将值存储在局部变量中……这只会使事情变得更加复杂。 Simply where you need it get the value from controller.active .只需在需要的地方从controller.active获取值。

Also do not use == for tags.也不要使用==作为标签。 Rather check via CompareTag .而是通过CompareTag检查。 The problem is that == silently fails if you have any typo or the tag doesn't exist at all.问题是如果您有任何拼写错误或标签根本不存在, ==默默地失败。 CompareTag rather throws an error that the given tag is not valid. 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事件驱动 - A 部分

In general you should avoid poll checks for a bool value in Update and rather come up with a more event driven solution!通常,您应该避免在Update对 bool 值进行轮询检查,而应提出更多事件驱动的解决方案! An example could look like:一个例子可能如下所示:

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;
        }
    }
}

Now you would register a listener for this event like现在您将为此事件注册一个侦听器,例如

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;
    }
}

This now is way more efficient since you don't all time run an Update method.这现在效率更高,因为您并不总是运行Update方法。 Instead the HandleControlerActiveStateChanged is only called when the value of active is actually changed.相反,只有当active的值实际更改时才会调用HandleControlerActiveStateChanged


Event Driven - part B事件驱动 - B 部分

And then actually in your case there is need to use a bool at all you could use a simple event Action instead and remove all the bools entirely:然后,实际上你的情况有必要使用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();
        }
    }
}

Now you would register a listener for this event like现在您将为此事件注册一个侦听器,例如

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;
    }
}
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 https://docs.unity3d.com/ScriptReference/GameObject.SendMessage.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM