我看过 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/