如何从另一个类调用 VRInput 类事件(OnClick、OnDoubleClick、...)?

Posted

技术标签:

【中文标题】如何从另一个类调用 VRInput 类事件(OnClick、OnDoubleClick、...)?【英文标题】:How to call VRInput Class Events (OnClick, OnDoubleClick, ...) from another Class? 【发布时间】:2018-04-16 19:48:19 【问题描述】:

我正在为我的游戏添加重播功能。有了这个功能,我可以捕获用户对游戏的输入,并在稍后将它们反馈给 Unity 以重播游戏。但是VRStandardAssets.Utils.VRInput 类的设计使我无法模仿用户输入。

此类不提供任何公共方法来以编程方式触发其事件(例如 OnClick 或 OnDoubleClick 事件)。所以我决定从它创建一个派生类并编写我自己的公共方法来触发事件。这个策略失败了,因为 VRInput 的方法是私有的,这意味着我不能从派生类中调用它们。

It is recommended 为这种类型的类提供 protected virtual void On[eventName](subclassOfEventArgs e) 方法 为派生类提供一种使用方法处理事件的方法override 但是这个类没有它(为什么这么严格?)。我猜这是 Unity 的糟糕设计。这种糟糕的设计也使得编写单元/集成测试变得困难。

我在这里遗漏了什么吗?在重玩游戏时,我还能做些什么来欺骗其他类认为他们正在处理 VRInput 类吗?

【问题讨论】:

编写游戏应用程序不同于编写标准应用程序。许多工作流程被放弃以使事情变得更容易或更快。他们只是希望您订阅完全没问题的事件。这些事件也是公开的,这意味着您可以轻松地从脚本中调用它们。我认为他们不希望您从VRInput 派生,因为它创建了VRInput 的多个实例,这是不必要的,因为只有一个用户输入。如果这是一个像 UI 按钮事件这样的 UI 控件,那么让它值得派生就好了,因为场景中可能有很多。 您能否详细说明“事件也是公开的,这意味着您可以轻松地从脚本中调用它们”?事件通常被定义为公共的,但这并不意味着其他类可以“调用”它们。他们可以订阅它们。 找到 VRInput 游戏对象:GameObject obj = GameObject.Find("VRInputObj"); 。现在从中获取 VRInput 组件:VRInput vrInput = obj.GetComponent<VRInput>(); 然后调用它的任何事件:vrInput.OnUp != null) vrInput.OnUp.Invoke(); 这不是我手动调用的。他们没有这个想法。该 API 只是在您的场景中制作简单 VR 游戏所需的基本最低 VR 内容,无需任何插件。如果您想要一个复杂的输入系统,您应该自己制作或使用现有的,例如 GoogleVr。 不,您不必这样做。给它相同的类名VRInput。将它放在VRStandardAssets.Utils 命名空间中,然后将它放在旧的位置已经在的位置。而已。您甚至可以利用这段时间添加您一直在谈论的virtual 方法。 【参考方案1】:

事实上,您可以使用这个巧妙的 hack (@ 987654321@):

C# 并不是真正的类型安全,因此您可以共享相同的内存位置。首先声明一个具有两个共享相同内存空间的字段的类:

[StructLayout(LayoutKind.Explicit)]
public class OverlapEvents

    [FieldOffset(0)]
    public VRInput Source;

    [FieldOffset(0)]
    public EventCapture Target;

然后你可以声明一个新的类来拦截并调用另一个事件:

public class EventCapture

    public event Action OnClick;

    public void SimulateClick()
    
        InvokeClicked();
    

    // This method will call the event from VRInput!
    private void InvokeClicked()
    
        var handler = OnClick;
        if (handler != null)
            handler();
    

然后最后注册并调用它:

public static void Main()

    input = GetComponent<VRInput>();

    // Overlap the event
    var o = new OverlapEvents  Source = input ;

    // You can now call the event! (Note how Target should be null but is of type VRInput)
    o.Target.SimulateClick();

这是一个简单的dotNetFiddle,表明它可以正常工作(至少在统一之外)

【讨论】:

【参考方案2】:

建议这种类型的类提供一个受保护的 virtual void On[eventName](subclassOfEventArgs e) 方法来为派生类提供一种使用覆盖来处理事件的方法,但是这个类没有它(为什么这么严格?)。我猜这是 Unity 的糟糕设计。这种糟糕的设计也使得编写单元/集成测试变得困难。

所有代码都是好代码。所有代码也是坏代码。取决于你的评价标准。 Unity 的开发人员可能没有考虑您的用例。作为另一个相互冲突的经验法则,软件也应该尽可能简单和严格,因此在没有已知用例的情况下预测子类可能被认为是过度工程。

关于如何解决这个问题,请参阅How do I raise an event via reflection in .NET/C#?

【讨论】:

以上是关于如何从另一个类调用 VRInput 类事件(OnClick、OnDoubleClick、...)?的主要内容,如果未能解决你的问题,请参考以下文章

如何从另一个类调用方法函数?

如何从另一个类调用@selector 方法

如何从另一个类调用 QMainWindow 组件?

如何从另一个类调用菜单对象?

如何从另一个类调用非静态抽象方法

如何从另一个 Qt Widget 表单类调用 MainWindow 类