Let's say I have the following class attached to a game object:
public class SomeClass : MonoBehaviour
{
[SerializeField]
private bool aBool;
public bool ABool
{
get
{
return aBool;
}
set
{
Debug.Log("we are setting the bool!");
// triggered when changing from false to true
if (aBool == false && value == true)
{
// do stuff
}
// triggered when changing from true to false
if (aBool == true && value == false)
{
// do stuff
}
aBool = value;
}
}
// Other fantastic methods and etc here.
}
When I play my game and check the aBool checkbox on the game object in the inspector, the set method is not being triggered. My debug log statement is not triggering, so it looks like it is not entering the set method.
How do I trigger the set method when I set the boolean in the inspector window, when playing the game? Have I done something wrong when creating the property?
CodePudding user response:
Posting for anyone else in the same situation.
In unity, when you have a bool exposed in the inspector, which also has a property overriding the set method, it does not call the set method when the bool is set in the inspector. Instead, it is modifying the bool directly.
If you want to be able to change a bool in the inspector and detect when it is changed in a script, you will need to poll for changes in the update function.
This makes my particular use case a bit more verbose, but oh well.
CodePudding user response:
The Inspector itself is not aware of any properties in your class. It will always only expose the serialized fields. See also Unity Script Serialization.
A Field and a Property are very different things. You do not simply add setter and getter to a Field, but rather convert your Field into a Property.
What you see and edit in the Inspector is not the Property ABool
but rather the Field aBool
which itself is in no way aware of that a property ABool
with setter and getter exists at all.
The confusion might be caused by the Inspector automatically formats th names of all exposed fields for a "human readable" display
- Always starting with a capital letter
- inserting spaces when switching from a lower case to a capital letter
(basically treats every capital letter or number and all lower case letters behind it as one word) - ignoring leading
_
- some special cases like ignoring leading
m_
So basically no matter if you call a field one of
public bool aBool;
public bool ABool;
public bool _aBool;
public bool _ABool;
public bool m_aBool;
public bool m_ABool;
the Inspector will for all them display A Bool
.
One way that was mentioned is using OnValidate
which s automatically called when a value of this component was changed via the Inspector and do e.g.
private void OnValidate()
{
// Only call properties during PlayMode since they might depend on runtime stuff
if(!Application.isPlaying) return;
ABool = aBool;
}
In your case though the issue will of course be that value != aBool
will never be true
since aBool
already was set to the value.
In order to avoid this you would need to introduce yet another control flag
[SerializeField] bool aBool;
private bool _oldABool;
public bool ABool
{
get => aBool;
set
{
aBool = value;
if(aBool != _oldABool)
{
if(aBool)
{
// do stuff
}
else
{
// do stuff
}
}
_oldABool = aBool;
}
}
private void OnValidate()
{
// Only call properties during PlayMode since they might depend on runtime stuff
if(!Application.isPlaying) return;
ABool = aBool;
}
Another way would be to implement your own field attribute like e.g. mentioned in OnValueChanged for fields in a Scriptable Object
CodePudding user response:
I think anyone did not notice that OP is setting abool variable and has getter and setter on Abool variable .Obviously setter and getter will get triggered when read write happens on Abool not abool. But OP is setting abool instead of Abool. Also properties (variables with get/set methods) can not be exposed in inspector to be set by inspector by yourself. They can only be altered through code.