【发布时间】:2020-07-13 19:35:52
【问题描述】:
我正在控制一个文本游戏对象。我正在执行诸如SetActive() 之类的操作并更改游戏对象的文本。现在我正在复制同一个对象,我希望复制的对象遵循其主要游戏对象的行为。也就是说 ObjA 是父级,而 ObjB 是一个克隆。如果我通过 objA 的代码更改文本 UI,我希望 objB 自动更改其组件。如何实现这种行为?
【问题讨论】:
标签: unity3d
我正在控制一个文本游戏对象。我正在执行诸如SetActive() 之类的操作并更改游戏对象的文本。现在我正在复制同一个对象,我希望复制的对象遵循其主要游戏对象的行为。也就是说 ObjA 是父级,而 ObjB 是一个克隆。如果我通过 objA 的代码更改文本 UI,我希望 objB 自动更改其组件。如何实现这种行为?
【问题讨论】:
标签: unity3d
有多种方法可以做到这一点,但总是通过代码,没有“自动主义”来做到这一点。
因此,您可以通过代码建立子与父或父与子的关系。
一种方法可能是那个:
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 异常,导致子调用父,谁调用子,谁再次调用父...你可以看到问题。
无论如何,最好声明一个包含所有方法的抽象基类,并让两个类都从该类继承并实现这些方法。
【讨论】:
() => ...) .. 你不能删除这些回调,所以一旦这个对象被销毁你就会得到每次父调用 OnDoSomething 等时都会出现 NullReferenceExceptions 您应该改为通过例如添加它们parent.OnDoSomething += DoSomething; 以后也删除不再需要的侦听器private void OnDestroy(){ parent.OnDoSomething -= DoSomething; }
OnEnable 并在 OnDisable 中删除它... 但是 这正是您想要的在父级上收听 .. 激活和停用游戏对象 ...因此,如果您删除 OnDisable 中的侦听器,您将不再获得启用事件;)而坚持使用 Awake 和 OnDestroy 因为您实际上想要这些回调对象的整个生命周期;)