The fact that you're not throwing any exceptions, and the onClick.Invoke()
is firing suggests that the issue is that some other element is consuming the clicks. Without having your project in front of me, I can only make some suggestions.
- Ensure that there are no ui elements in between the camera and the buttons(such as transparent panels or images); you can move around objects at run time to see if they're too close and consuming the click.
- Make sure that a parent canvas does not have a
CanvasGroup
with Interactable
set to false.
- Look for any empty objects/colliders/listeners that could be blocking raycasts.
Good luck!
Edit
After re-reading your code, and giving the linked post another once-through I have realized a mistake in your code.
In your GameOptions
class constructor, you aren't actually referencing the instantiated object when collecting the objects. You wrote this:
this.canvas = canvas;
GameObject.Instantiate(canvas);
Text[] textObjects = canvas.GetComponentsInChildren<Text>();
If you look through what is exactly happening, you're assigning the field canvas
to the prefab that was passed into the parameter of the constructor. After you make the assignment, you instantiate the prefab with the parameter, without any reference to the instantiated object.
After that you're calling GetComponentsInChildren
on a prefab not the instantiated object itself. This is why onClick.Invoke()
is being fired, because the objects exist on the prefab; they're just not the objects you're looking for.
I have refactored your constructor, which should solve your issue.
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();
}
}
A Few Notes
- You should use a
Canvas
item instead of GameObject
, even if you never use any members of the Canvas
class; it makes it easier to read later on down the road, and prevents you from accidentally constructing new GameOptions(someRandomButton)
which just wouldn't do anything when you tried to access the children. The Canvas
object inherits from GameObject
so you would have everything you need.
- You should consider using a different naming scheme; this is highly subjective opinion, and there is a lot of debate on the subject if you search SO. Personally I opt for the underscore prefix on private fields such as
private GameObject _canvas;
, this makes me have zero doubt that I haven't forgotten a this
because inherently the parameters and fields would have distinct and unique naming schemes.
Take my advice with a grain of salt! There are many many ways to approach a problem, so ultimately go with what is most comfortable for you.