Apologies in advance for this total noob question – I’m still learning some fundamentals.
I’m building a 2D Dress-Up game, in which I’d like to be able to click a button to activate one gameObject while deactivating any others of its kind. Naturally, putting this logic only into the UI buttons becomes very tedious and quickly overwhelms the runtime when it’s given too many tasks.
As an example, I’ve made the following void (which only seems to work once or twice then stops working in runtime):
void ActiveShirt()
{
if (shirt1White.activeSelf)
{
shirt1Black.SetActive(false);
shirt1Blue.SetActive(false);
shirt1Orange.SetActive(false);
shirt1Purple.SetActive(false);
}
else if (shirt1Black.activeSelf)
{
shirt1White.SetActive(false);
shirt1Blue.SetActive(false);
shirt1Orange.SetActive(false);
shirt1Purple.SetActive(false);
}
else if (shirt1Blue.activeSelf)
{
shirt1Black.SetActive(false);
shirt1White.SetActive(false);
shirt1Orange.SetActive(false);
shirt1Purple.SetActive(false);
}
else if (shirt1Orange.activeSelf)
{
shirt1Black.SetActive(false);
shirt1White.SetActive(false);
shirt1Blue.SetActive(false);
shirt1Purple.SetActive(false);
}
else if (shirt1Purple.activeSelf)
{
shirt1Black.SetActive(false);
shirt1Blue.SetActive(false);
shirt1Orange.SetActive(false);
shirt1White.SetActive(false);
}
A friend said in passing that a “For” Loop might be better suited to handling this kind of functionality, but I am struggling to wrap my head around how to get from declaring gameObjects to expressing them in a Loop…
Does anyone have a recommendation for a better way to accomplish what I’m trying to do? I am grateful for any assistance or feedback!
If I have 4 shirt objects, and I want the player to basically select one to be enabled, I would put them in an array, like this [shirt1, shirt2, shirt3, shirt4]
. When clicking a button to select a shirt, lets say shirt3, I would first disable all shirts
for (int i = 0; i < shirts.Count; i++) {
shirts[i].SetActive(false);
}
And THEN I would enable the shirt that was clicked
clickedShirt.SetActive(true);
2 Likes
Thank you @PixelDough, this is very helpful!
I’m having trouble putting gameObjects directly into an array and calling them that way… I’m getting the error “A field initializer cannot reference the non-static field, method, or property Dressup.shirt1White”
Should I be doing something to the tune of
string[] shirt1Colors = new string[5] { shirt1White, shirt1Black, shirt1Blue, shirt1Orange, shirt1Purple};
or would I need to express the array in a way that made direct reference to the gameObjects?
GameObject[] shirt1White, shirt1Black, shirt1Blue, shirt1Orange, shirt1Purple
It would seem nothing I’m trying so far actually works correctly
the first option looks right! Can you share more of the script you’re writing this in? It seems like you’re trying to declare the value of this array in the same scope you’re declaring the variables you want to be the values. I believe the right way of doing it would be to just have
string[] shirt1Colors;
void Start() {
shirt1Colors = new string[5] { shirt1White, shirt1Black, shirt1Blue, shirt1Orange, shirt1Purple};
}
1 Like
@PixelDough absolutely! Though I’ll truncate it to show only the relevant material to this convo, of course…
public class DressUp : MonoBehaviour
{
[Header("Base Character")]
[SerializeField] GameObject baseCharacter;
[Header("Shirts")]
[SerializeField] GameObject shirt1Black;
[SerializeField] GameObject shirt1White;
[SerializeField] GameObject shirt1Blue;
[SerializeField] GameObject shirt1Orange;
[SerializeField] GameObject shirt1Purple;
string[] shirt1Colors;
void Start()
{
shirt1Colors = new string[5] { shirt1White, shirt1Black, shirt1Blue, shirt1Orange, shirt1Purple };
}
void Update()
{
ActiveShirt();
}
void ActiveShirt()
{
for (int i = 0; i < shirts.Count; i++)
{
shirts[i].SetActive(false);
}
}
}
The problem I’m now getting is “Cannot implicitly convert type UnityEngine.GameObject to string”
Ah, well that would be because you need a GameObject array not a string array
Going off of PixelDough, it would look something like this:
[SerializeField] GameObject[] shirts;
then initialize the shirts in the editor
1 Like
@jackpatters10 @PixelDough thank you both! I’m taking another crack at it and will report back ^___^
@PixelDough @jackpatters10 thank you again for your help so far on this - I have an update!
I have been noodling with the code and resolved the array/initialization issues - the loops, however, are not working in their current form… my suspicion is that it has to do with my way of prompting the ActiveShirt() method:
public class DressUp : MonoBehaviour
{
[Header("Base Character")]
[SerializeField] GameObject baseCharacter;
[Space(5)]
[Header("Shirts")]
[SerializeField] GameObject[] shirt1Colors;
private int shirts1Count = 5;
GameObject shirt1Black;
GameObject shirt1White;
GameObject shirt1Blue;
GameObject shirt1Orange;
GameObject shirt1Purple;
/// cutting out all the other stuff that would be redundant in the middle, here ///
void Start()
{
}
void Update()
{
ActiveShirt();
}
void ActiveShirt()
{
if (shirt1Black.activeSelf)
{
for (int i = 0; i < shirts1Count; i++)
{
shirt1Colors[i].SetActive(false);
shirt2Colors[i].SetActive(false);
shirt3Colors[i].SetActive(false);
shirt1Black.SetActive(true);
}
}
else if (shirt1Colors[1].activeSelf)
{
for (int i = 0; i < shirts1Count; i++)
{
shirt1Colors[i].SetActive(false);
shirt2Colors[i].SetActive(false);
shirt3Colors[i].SetActive(false);
shirt1White.SetActive(true);
}
}
else if (shirt1Colors[2].activeSelf)
{
for (int i = 0; i < shirts1Count; i++)
{
shirt1Colors[i].SetActive(false);
shirt2Colors[i].SetActive(false);
shirt3Colors[i].SetActive(false);
shirt1Blue.SetActive(true);
}
}
else if (shirt1Colors[3].activeSelf)
{
for (int i = 0; i < shirts1Count; i++)
{
shirt1Colors[i].SetActive(false);
shirt2Colors[i].SetActive(false);
shirt3Colors[i].SetActive(false);
shirt1Orange.SetActive(true);
}
}
else if (shirt1Colors[4].activeSelf)
{
for (int i = 0; i < shirts1Count; i++)
{
shirt1Colors[i].SetActive(false);
shirt2Colors[i].SetActive(false);
shirt3Colors[i].SetActive(false);
shirt1Purple.SetActive(true);
}
}
Would I be correct in guessing that I shouldn’t be making conditions about how to simultaneously deactivate/reactivate gameObjects with the condition being that one of them becomes active? My thought is that if I could capture the input trigger from the press of the button gameObject another way, my life would be much, much easier
What do you guys think?
Reasonable attempts and at least you are trying hard but your solution is a) way too verbose and b) limiting in terms of scaling it up.
I would suggest what I term “stepping back” in the thought process and don’t think about this as “shirts” you are simply working with a set of objects. That means adding, removing, reading and changing state, etc. This sounds like a class that wraps your shirt options. Your app leverages the class. Once you have “set behaviors” wrapped you can apply it to a set of hats, pants and what have you.
You do not want an ActiveShirt method with if/else blocks. Just imagine the work involved if you add one additional shirt. Look at the changes you will need to make. That feeling of “yuck” is known as code smell. It just doesn’t feel right.
I’d recommend creating a class and adding functionality to it. Don’t try to actually change the color of an object just have it debug.log the state of things so you know you have it all working. Then you apply what is a working solution to your app.
So add some sort of empty shirt object collection to the class. Create methods for Add, Remove, etc. Have it able to return a count, determine which object is active. Create a method to reset them all on or off and another to set a specific one on.
As a sidenote you don’t need to be calling ActiveShirt from the Update method do you? Something makes the active shirt change. If there is no change nothing will be different and an update shouldn’t need to occur.
3 Likes
@tleylan you’ve given me a lot to think about, and I appreciate it – what you’re saying makes sense, broadly, I’m just too much of a beginner to put it directly into practice without banging my head against the wall a bit!
I’m taking a step back as you suggest, reassessing my methodology, and researching other ways to set this up. In the meantime, I will also not quit my day job
@PixelDough @jackpatters10 thank you so much for your insights as well – I’m so grateful that this community exists, so even old farts like me who are late to the coding party can learn from people who actually know what they’re doing.
1 Like