How to make public variable read-only during run-time?

I have a simple variable:

public enum something { one, two }
public something variable = something.one;

And I want to don’t let user to change that variable in the inspector during run-time. I need to somehow make it read-only. Any ideas?

We use [this plugin][1] to make public variable read-only in the inspector. It provides a [NotEditableInInspector] attribute. [1]: https://www.assetstore.unity3d.com/#!/content/66996

3 Answers

3

I adapted the scripts from this article to achieve this.

ReadOnlyWhenPlayingAttribute.cs:

using UnityEngine;
public class ReadOnlyWhenPlayingAttribute : PropertyAttribute { }

Editor/ReadOnlyWhenPlayingAttributeDrawer.cs

using UnityEngine;
using UnityEditor;

[CustomPropertyDrawer(typeof(ReadOnlyWhenPlayingAttribute))]
public class ReadOnlyWhenPlayingAttributeDrawer : PropertyDrawer
{
	// Necessary since some properties tend to collapse smaller than their content
	public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
	{
		return EditorGUI.GetPropertyHeight(property, label, true);
	}

	// Draw a disabled property field
	public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
	{
		GUI.enabled = !Application.isPlaying;
		EditorGUI.PropertyField(position, property, label, true);
		GUI.enabled = true;
	}
}

Usage:

[ReadOnlyWhenPlaying]
public something variable = something.one;

Brilliant! This simplifies a lot of my scripts.

You need to make the field private and add [SerializeField] then expose it as a read only property:

  [SerializeField]
  private something _variable;

  public something variable { get { return _variable; } }

Tried it right now, variable still can be changed during run-time, so it doesn't work.

Oh I've got what you want now - that is not possible - I'm struggling to think of why you are worrying about changing it in the inspector at run time? Why would you want to do that??

The code I gave you stops the variable being changed in code from another script.

I need it because if user changes character movement type during run-time, the whole movement system doesn't work anymore. So there isn't better solution than creating another variable, changing it's value when script starts and then in Update() setting the original variable to the new? Would look like [this][1] [1]: http://pastebin.com/1HFSWVPS

But why would the user be messing around in the inspector? At runtime? Well fair enough - yes - you have to have a private variable initialized from a public variable during Start or Awake.

For anyone still interested on how to achieve this behavior do as follow:

[SerializeField]
private <Type> InternalVariable = default;

//To be accessed from this class or other scripts.
public <Type> Variable { get {return InternalVariable;}; }

void Update()
{
    UpdateInternals();
}

void UpdateInternals()
{
    if (InternalVariable != Variable)
    {
        Debug.Log("InternalVariable can only be set at compile time. Your change will not be applied.");
        InternalVariable = Variable;
    }
    //Process any other internals
}

What actually happens is that whatever is set at startup in InternalVariable is then used while Unity runs. You can even make it such as just in certain circumstances this will be disabled.

I like to use that variable as private and use “Internal” in its name so its purpose is clear. If I want to handle it from scripting I use its property instead (create a setter for it, of course).

Not the best pattern but the nice thing is you can use C# partial classes to remove the Inspector behavior from the actual class. Having a classInspector.cs will clearly indicate what you will find there.

nice, but would be cool to have a simpler way to do that.