【问题标题】:Make a gameObject follow another gameObject's behavior?让一个游戏对象跟随另一个游戏对象的行为?
【发布时间】:2020-07-13 19:35:52
【问题描述】:

我正在控制一个文本游戏对象。我正在执行诸如SetActive() 之类的操作并更改游戏对象的文本。现在我正在复制同一个对象,我希望复制的对象遵循其主要游戏对象的行为。也就是说 ObjA 是父级,而 ObjB 是一个克隆。如果我通过 objA 的代码更改文本 UI,我希望 objB 自动更改其组件。如何实现这种行为?

【问题讨论】:

    标签: unity3d


    【解决方案1】:

    有多种方法可以做到这一点,但总是通过代码,没有“自动主义”来做到这一点。

    因此,您可以通过代码建立子与父或父与子的关系。

    一种方法可能是那个:

    public class Parent : MonoBehaviour
    {
        public Child child = null;
    
        public void DoSomething()
        {
            this.gameObject.SetActive(true);
            child.DoSomething();
        }
    }
    
    public class Child : MonoBehaviour
    {
        public void DoSomething()
        {
            this.gameObject.SetActive(true);
        }
    }
    

    另一种奇特的方法是使用委托或动作:

    public class Parent : MonoBehaviour
    {
        public Action OnDoSomething = null;
        public Action OnDoSomethingElse = null;
    
        public void DoSomething()
        {
            this.gameObject.SetActive(false);
            OnDoSomething();
        }
    
        public void DoSomethingElse()
        {
            this.gameObject.SetActive(true);
            OnDoSomethingElse();
        }
    }
    
    public class Child : MonoBehaviour
    {
        public Parent parent = null;
    
        public void Awake()
        {
            parent.OnDoSomething += ChildDoSometing;
            parent.OnDoSomethingElse += ChildDoSometingElse;
        }
        public void OnDestroy()
        {
            parent.OnDoSomething -= ChildDoSometing;
            parent.OnDoSomethingElse -= ChildDoSometingElse;
        }
    
        public void ChildDoSometing()
        {
            this.gameObject.SetActive(false);
        }
    
        public void ChildDoSometingElse()
        {
            this.gameObject.SetActive(false);
        }
    }
    

    您可以尝试将自己的方法作为 Action 参数传递,例如 Action<Action>,但请记住,孩子将调用父方法,不会自行操作。因此,在这种情况下,如果您执行以下操作:

    public class Parent : MonoBehaviour
    {
        public Action<Action> OnDoSomething = null;
    
        [ContextMenu("A")]
        public void DoSomething()
        {
            this.gameObject.SetActive(true);
            OnDoSomething(this.DoSomething);
        }
    
        public void DoSomethingElse()
        {
            print("Hello");
        }
    }
    
    public class Child : MonoBehaviour
    {
        public Parent parent = null;
    
        public void Awake()
        {
            parent.OnDoSomething += RepeatedAction;
        }
        public void OnDestroy()
        {
            parent.OnDoSomething -= RepeatedAction;
        }    
    
        public void RepeatedAction(Action actionToRepeat)
        {
            actionToRepeat?.Invoke();
        }
    }
    

    会导致 StackOverflow 异常,导致子调用父,谁调用子,谁再次调用父...你可以看到问题。

    无论如何,最好声明一个包含所有方法的抽象基类,并让两个类都从该类继承并实现这些方法。

    【讨论】:

    • 小心!!永远不要通过 lambda 表达式添加侦听器 (() =&gt; ...) .. 你不能删除这些回调,所以一旦这个对象被销毁你就会得到每次父调用 OnDoSomething 等时都会出现 NullReferenceExceptions 您应该改为通过例如添加它们parent.OnDoSomething += DoSomething; 以后也删除不再需要的侦听器private void OnDestroy(){ parent.OnDoSomething -= DoSomething; }
    • here again ;) 现在下一个问题是您将侦听器附加到 OnEnable 并在 OnDisable 中删除它... 但是 这正是您想要的在父级上收听 .. 激活和停用游戏对象 ...因此,如果您删除 OnDisable 中的侦听器,您将不再获得启用事件;)而坚持使用 AwakeOnDestroy 因为您实际上想要这些回调对象的整个生命周期;)
    猜你喜欢
    • 2015-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多