c# - 统一按钮点击不触发事件

标签 c# unity3d unity-ui

我看过 post located here处理相同的问题,但它既没有说明问题所在也没有解决我的问题。

我创建了一个 Canvas 预制件,面板中有许多按钮。我在运行时实例化预制件并获取面板中的所有 Button 对象。然后,我为所有调用相同 clicked() 方法的按钮的 onClick() 事件添加了一个监听器

public class GameOptions
{
    private GameObject canvas;

    public GameOptions(GameObject canvas)
    {
        this.canvas = canvas;
        GameObject.Instantiate(canvas);        
        Text[] textObjects = canvas.GetComponentsInChildren<Text>();
        Button[] buttonObjects = canvas.GetComponentsInChildren<Button>();

        for (int i = 0; i < buttonObjects.Length; i++)
        {
            Debug.Log(buttonObjects[i].name);
            buttonObjects[i].onClick.AddListener(() => clicked());
            buttonObjects[i].onClick.Invoke();
        }
    }

    public void clicked()
    {
        Debug.Log("Clicked!");
    }
}

请注意,当我通过代码调用事件时,将调用 clicked() 并“单击!”正确输出到控制台。

但是,没有一个按钮在单击时触发事件。我还注意到检查器中 OnClick 中的 PersistentCalls.Calls 数组在运行时对所有按钮都有 0 个元素。

我在 Windows 10 64 中使用 Unity 2017.4.3f1。

最佳答案

事实上,您没有抛出任何异常,并且 onClick.Invoke() 正在触发,这表明问题是其他一些元素正在消耗点击。没有你的项目在我面前,我只能提出一些建议。

  • 确保相机和按钮之间没有任何 ui 元素(例如透明面板或图像);您可以在运行时四处移动对象,看看它们是否靠得太近并占用了点击时间。
  • 确保父 Canvas 没有将 Interactable 设置为 false 的 CanvasGroup
  • 寻找任何可能阻挡光线转换的空对象/碰撞器/监听器。

祝你好运!


编辑

在重新阅读您的代码并再次查看链接的帖子后,我发现您的代码中存在错误。

在您的 GameOptions 类构造函数中,您在收集对象时实际上并未引用实例化对象。你写了这个:

this.canvas = canvas;
GameObject.Instantiate(canvas);
Text[] textObjects = canvas.GetComponentsInChildren<Text>();

如果您查看到底发生了什么,您会将字段 canvas 分配给传递给构造函数参数的预制件。进行分配后,您使用参数实例化预制件,而不引用实例化对象。

之后,您将在 prefab 而不是实例化对象本身上调用 GetComponentsInChildren。这就是 onClick.Invoke() 被触发的原因,因为对象存在 在预制件上;它们不是您要查找的对象。

我已经重构了你的构造函数,这应该可以解决你的问题。

public GameOptions(GameObject canvas)
{
    //here we instantiate the canvas item, assigning it to the field
    this.canvas = GameObject.Instantiate(canvas);  

    //then we reference the field item, instead of the parameter item
    Text[] textObjects = this.canvas.GetComponentsInChildren<Text>();
    Button[] buttonObjects = this.canvas.GetComponentsInChildren<Button>();
    for(int i = 0; i < buttonObjects.Length; i++)
    {
        Debug.Log(buttonObjects[i].name);
        buttonObjects[i].onClick.AddListener(() => clicked());
        buttonObjects[i].onClick.Invoke();
    }
}

一些注意事项

  • 您应该使用 Canvas 项而不是 GameObject,即使您从不使用 Canvas 类的任何成员;它使以后阅读起来更容易,并防止您意外构建 new GameOptions(someRandomButton) 当您尝试访问子项时它不会做任何事情。 Canvas 对象继承自 GameObject,因此您将拥有所需的一切。
  • 您应该考虑使用不同的命名方案;这是非常主观的意见,如果你搜索 SO,就会有很多关于这个主题的争论。就我个人而言,我选择在私有(private)字段上使用下划线前缀,例如 private GameObject _canvas;,这让我毫不怀疑我没有忘记 this 因为固有的参数和字段将具有不同且唯一的命名方案。

请对我的建议持保留态度!解决问题的方法有很多种,所以最终选择最适合您的方法。

关于c# - 统一按钮点击不触发事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50573926/

相关文章:

c# - 将模板选择器中的 DataTemplate 设置为动态资源

c# - 在没有 System.Net.Sockets 的情况下将 Unity 连接到 C++ WinSocket

unity3d - Unity脚本执行顺序和Start()

c# - LINQ to SQL where 子句验证字符串包含列表元素

c# - 是我错了还是 Roslyn REPL 保护过度了?

c# - 按属性值对对象列表进行排序

c# - 将 MoveTowards 与持续时间而不是速度一起使用

c# - 重新启动按钮 Unity 3d C#

unity-game-engine - 新的 UI 构建器/工具包和 VR 世界空间