Reputation: 23
I know this is a very long question, but I tried my best to be as clear as possible with this weird problem. Any help or suggestions would be appreciated. Let me know if I can provide any more resources.
I am trying to create a sort-of navigation system where the user can still see what path they are on. I have three sets of buttons:
When the user clicks on a button, the button must change color and stay that color until a different button of THE SAME SET (mentioned above) is pressed.
I have three lists: one for buttons, one for disciplines, one for modules. The button list is static, while the other two are destroyed and added to as needed (the list adding/clearing does work). When I instantiate disciplines or modules, the previous ones are all destroyed (and the list is cleared) and then each instance is added to the list. Each instance has an onClick listener (made in the script, it does not work to make the listener Editor-side) which calls this general method:
public void ChangeAllWhite(List<GameObject> list)
{
foreach (var button in list)
{
button.GetComponent<Image>().color = orangeColor;
}
}
and then calls one of these three methods to change that instance color: public void YearColorChange(GameObject buttonToChange) { ChangeAllWhite(yearButtons); buttonToChange.GetComponent().color = selectedColor; }
public void DisciplineColorChange(GameObject buttonToChange)
{
ChangeAllWhite(disciplineButtons);
buttonToChange.GetComponent<Image>().color = selectedColor;
}
public void ModuleColorChange(GameObject buttonToChange)
{
ChangeAllWhite(moduleButtons);
buttonToChange.GetComponent<Image>().color = selectedColor;
}
This is the code to instantiate the disciplines (same as module pretty much) after the previous ones have been destroyed:
foreach (string item in disciplines)
{
GameObject disciplineInstance = Instantiate(DisciplineItem);
disciplineInstance.transform.SetParent(DisciplineLayoutGroup.transform, false);
disciplineInstance.GetComponentInChildren<Text>().text = item;
disciplineButtons.Add(disciplineInstance);
disciplineInstance.GetComponent<Button>().onClick.AddListener(() =>
{
UnityEngine.Debug.Log("debug discipline");
AppManager.instance.classroomInfo.SetDiscipline(item);
StartCoroutine(AppManager.instance.web.GetModules(AppManager.instance.classroomInfo.year, item));
DisciplineColorChange(disciplineInstance);
//needs year, discipline
});
}
I don't get any errors, but the colors don't change. When I called the methods from an OnClick on the editor-side, it breaks and/or doesn't work. I think what is happening is that OnClick methods from previously instantiated (and now deleted) instances are trying to do something and then it just doesn't do anything. Any suggestions are welcome!
Upvotes: 0
Views: 6079
Reputation: 12373
Your code seems incredibly over-complicated.
Alternately, you must build a class that has the colors (animations, images, fonts, whatever) you want as a property and add that component to your buttons and use that. (In an ECS system, "adding a component" like that is a bit like extending a class in normal OO programming; you're just adding more behavior to the Button.)
So you would have your own cool
`SugarfreeButton`
and then you can do stuff like
sugarfreeButton.Look = YourLooks.Possible;
sugarfreeButton.Look = YourLooks.CannotChoose;
sugarfreeButton.Look = YourLooks.Neon;
etc. You really HAVE to do this, you can't be dicking with setting colors etc in your higher-level code.
It's only a few lines of code to achieve this.
I've attached a completely random example of such "behaviors you might add to a button" at the bottom of this - DippyButton
HorizontalLayoutGroup
or the vertical one). Do everything flawlessly in storyboard, and then just drop them inside that in the code with absolutley no positioning etc. concerns in the code.Unfortunately, u won't be able to do anything in Unity UI until extremely familiar with the two layout groups (and indeed the subtle issues of LayoutElement
, the fitters, etc.).
So these "lobby heads" (whatever the hell that is!) entirely take care of themselves.
In your example, when one is instantiated, on its own, it would find out what the currently selected "year" is. Does it make sense? They should look in the discipline database (or whatever) and decide on their own what their value should be (perhaps based on their position (easy - sibling index) in the layout group, or whatever is relevant.
You will never be able to engineer and debug your code the way you are doing it, since it is "upside down". In unity all game objects / components should "look after themselves".
Random code examples from point (1) ... DippyButton
using UnityEngine;
using UnityEngine.UI;
// simply make a button go away for awhile after being clicked
public class DippyButton : MonoBehaviour
{
Button b;
CanvasGroup fader;
void Start()
{
b = GetComponent<Button>();
if (b == null)
{
Destroy(this);
return;
}
b.onClick.AddListener(Dip);
fader = GetComponent<CanvasGroup>();
// generally in Unity "if there's something you'll want to fade,
// naturally you add a CanvasGroup"
}
public void Dip()
{
b.interactable = false;
if (fader != null) { fader.alpha = 0.5f;
}
Invoke("_undip", 5f);
}
public void _undip()
{
b.interactable = true;
if (fader != null) { fader.alpha = 1f; }
}
}
Upvotes: 0