typical rule of thumb I go by is that other game objects shouldn’t know that a UI even exists (unless its also a UI and only if there’s no better way). This rule of thumb is there to help prevent deadlocks in logic behavior, or some nasty hard to trace bugs.
For example, I wouldn’t have my AudioController ask if the UI mute button is turned on or off, I do it the other way around… my AudioController tracks the mute state and the button checks what state the mute is. If muted show the unmute icon, otherwise show the mute icon. when the button is pressed it triggers a call to the AudioController to change its state via a public function in the AudioController. The AudioController has no knowledge whatsoever that a mute button even exists, nor does it need to.
so to answer your question, I would instead have whatever you have checking to state of the button check the source of what ever is affecting that button’s state. if the logic you have that determines the state of the button self contained in the script connected to the button, I would push it out to an external controller class.
And in this external class set the state change to an event so what ever needs to work of it can just subscribe themselves to the event. This will further decouple your code (classes know less about other classes and thus are less prone to break from code changes) and keeps it fast (instead of having to ask that class every frame what it’s state is, the class will simply tell all that cares to listen when it’s state has changed).
I don’t know exactly what you need to track the button state, but this is how I would code it, going back to my previous example…
public class AudioController : Monobehavior
{
public delegate void MuteEvent();
public static event MuteEvent OnMute;
public static AudioController instance;
private bool _isMuted = false;
public bool IsMuted
{
get { return _isMuted;}
set
{
_isMuted = value;
// only call if someone is listening,
// otherwise you'll get a crash
if(OnMute!=null)
{
OnMute();
}
}
}
void Awake()
{
// set the static reference so that other
// scripts don't have to do any complex searching
instance = this;
}
}
public class MuteButtonScript : Monobehavior
{
public Button btn;
public Sprite muteSprite;
public Sprite unmuteSprite;
void Awake()
{
Button btn = GetComponent<Button>();
}
void OnEnable()
{
//subscribe to the AudioController's On Mute event
AudioController.OnMute += OnMute;
}
void OnDisable()
{
//unsubscribe from the AudioController's On Mute event
AudioController.OnMute -= OnMute;
}
// this function will always run whenever the class is subscribed
// to the AudioController and the AudioController runs "OnMute()"
void OnMute()
{
//update the button sprite depending on the AudioController's Mute State
btn.image.sprite = AudioController.instance.IsMuted ? muteSprite : unmuteSprite;
}
}
here the button’s image is changing state depending on when the AudioController issues the OnMute event. So instead of having whatever you’re planning to listen to this button, have it listen to the event from the audio controller. Neither the AudioController nor the MuteButtonScript needs to know what this script is, which makes it very easy and lightweight to extend functionality.
by using events you can have other classes (subscribers) attach themselves to an event that is issued by a single source (provider) and the subscribers don’t have to constantly check every update loop, the provider simply tells the subscribers when the event happens.
so whatver event that is causing your button to become non-interactible have your other UI stuff also listen to that same event and have then change their color based on the same decision making