Button prefab is causing wrong prefab to trigger
Okay, so I'm having a very weird issue and it is causing me to pull my hair out! Have spent hours trying to work this out.
So, I have a prefab called 'ShopItem' this prefab is a UI button with four child objects being UI image or a UI panel. When the prefab is created it gets a listener attached to the on click method. The click handler works, but it seems to only trigger whatever the last instance in the hierarchy.
Above you can see the two objects when the game is running, with the game hierarchy shown. These two objects were instantiated using the below script (ignore the messy code this just a test):
void Start() {
var item = Instantiate(ShopItemPrefab);
item.name = "Shop Item 1";
item.GetComponent<Transform>().SetParent(canvas.GetComponent<Transform>());
item.GetComponent<Transform>().localPosition = new Vector3(-173f, 162f, 1f);
item.GetComponent<Transform>().localScale = new Vector3(1f, 1f, 1f);
item.GetComponent<Button>().onClick.AddListener(handleClick);
var item2 = Instantiate(ShopItemPrefab);
item2.name = "Shop Item 2";
item2.GetComponent<Transform>().SetParent(canvas.GetComponent<Transform>());
item2.GetComponent<Transform>().localPosition = new Vector3(175.5f, 162f, 1f);
item2.GetComponent<Transform>().localScale = new Vector3(1f, 1f, 1f);
item2.GetComponent<Button>().onClick.AddListener(handleClick);
}
void handleClick() {
EventSystem.current.currentSelectedGameObject.GetComponent<ShopItem>().MarkAsSelected();
}
The MarkAsSelected method is then called on the (supposedly) clicked object and basically marks a boolean as true and changes the background sprite.
Looking at the Gif above I'm clicking the left box, but the right one is the one that gets triggered. Now the weired thing is that neither objects overlap. However, if in the hierarchy view I move 'Shop Item 2' above 'Shop Item 1' and then click the same box it correctly selects it, but clicking the right box will now trigger the left box.
I hope that makes sense! The confusing thing for me is that I don't understand how this is happening, neither instance is linked together and it's not like this is running inside a loop where their may be problems with the variable scopes.
Thank you in advanced for you help, if you have any questions I'm happily answer them. I just don't know why this is happening!
I've tried to recreate your problem to the best of my ability because from first glance it all appeared to be fine. Using your code you provided without changing anything within it I got the results you desired just as I expected I would with no issue. I believe you error might be co$$anonymous$$g from another segment of code not provided. Perhaps within the ShopItem under $$anonymous$$arkAsSelected()?
In my recreation, my ShopItem prefab was created first with an empty GameObject with only a Button component added after. Then four children, two panels - one foreground, and one background -, an image for the coin, and a text. $$anonymous$$y $$anonymous$$arkAsSelected only changed the color of the background panel to a random color.
Oh thats weird. I'm not at home currently but if I remember correctly the $$anonymous$$arkAsSelected method is the following
public void $$anonymous$$arkAsSelected() {
this.selected = true;
this.background = this.selectedBackground;
}
this.selected does nothing special it's just a flag so if I needed to I could check if it selected, this.background is a reference to the prefabs background image and this.selectedBackground is a reference to the selected image sprite.
The only thing I can think of is that however you're setting background, it's somehow being set wrong. When you get the chance, find out what happens when you click the right shop item before any hierarchy changes. Then experiment, and see what happens when clicking both boxes after moving 'Shop Item 2' above 'Shop Item 1'.
In my head right now I'm envisioning the way you get this.background might be done in someway using GetComponentInChildren, which would get the first child of whatever type found everytime. Which could explain the functionality change when the hierarchy changes. If this is incorrect, than I'm not sure. As again the code you've provided has worked perfectly in my recreation without any modifications.
Answer by VizuaaLOG · Aug 22, 2017 at 07:40 PM
Okay! I just worked it out. I think it was the way I had created my prefab, having the button as the parent and then the background etc as children of it was causing the click to not be detected. I'm not sure whether it was because the image component was not on the button, so it was technically not rendered?
I have recreated the prefab with an empty object that is just the wrapper, and then instead of having a child background object, this is instead a component on the button.
Below is what I have been trying to get for hours!!! Thank you to @Malace and @tablekorner for helping me figure this out :)
Answer by Malace · Aug 22, 2017 at 04:43 PM
I think the problem is your using the same message for both buttons. So both buttons are firing one event. Which as listeners to that single event. Means your handleClick is run by both buttons no matter which one gets pressed.. Causing whichever one runs last to be your final value of currently selected.
Try 2 events and if your result is as desired. You will need an event that can determine which button triggered the event to set the proper current selection. ie: Just change
item2.GetComponent<Button>().onClick.AddListener(handleClick);//To
item2.GetComponent<Button>().onClick.AddListener(handleClick2);// and register a second event for the second button.
I get what you're saying but according to the docs EventSystem.current.currentSelectedGameObject should return the last clicked object, so running it through the same handler shouldn't matter.
Also, this is just testing code, once I get this sorted the creation of the buttons will be performed in a loop because there will an unknown amount of items in the shop you can buy.