Best way to declare class properties in Unity3D - c#

I am new to Unity 3D development and I wanted to know what is the best way to declare attributes of a class to be assigned later from the editor.
I have seen mainly two:
public class MyObject : MonoBehavour {
public GameObject relatedObect;
}
and
public class MyObject : MonoBehavour {
[SerializeField]
private GameObject relatedObect;
}
I understand that it is of the second form because the encapsulation is maintained, but I am not sure.

Please consider that in the example you declared class fields, and not properties.
They are both members of a class, but they are quite different.
For the sake of this answer I'll focus on your example, so I'll talk about fields.
Both public and [SerializeField] private let you inject a value in the Unity Inspector, but they act differently in the scripts.
1 - public field
You declare a public field when you want it to be used or set from another class. This choice goes against encapsulation, because other script may access it. It still might be an intended behaviour if you require the field to be accessible.
2 - [SerializeField] private field
You use this when you want to set the item in the inspector, but you do not want the other classes to see it. This option is better for encapsulation, because in this way no other script may access or change this field.

Second is the way to go if you want to do things "properly". But unfortunately there is a "bug" that throws warning on every private you set via the editor. I saw on github that it is finally getting fixed, but in the meantime if you want to remove the warning you can put your variables between pragma warning disable 0649 and pragma warning restore 0649

In addition to Jack Mariani's answer, I want to mention RangeAttribute and HideInInspectorAttribute.
[Range (min, max)]
If there's one, the inspector will show a slider instead of just a number. You move a slider and the value changes in specified range.
[SerializeField] [Range (0, 5)] private float _speed;
Documentation
[HideInInspector]
You should use it when you do not want a public variable to show up in the inspector (they are shown by default):
[HideInInspector] public float X;
Documentation

Related

How to pass value to constructor from unity inspector

I have a base abstract Character class I created (it extends MonoBehaviour) which contains some data, one of which is maxHealth. I don't want the maxHealth to be changed and so I made it readonly and use a property to change it (public float MaxHealth { get; }).
I want different characters to have different max hp values so I tried to use a constructor and pass in the max health there but I can't pass a value to the constructor from the unity inspector.
Does anyone have any idea how to pass a value to a constructor from the Unity inspector or any other way to achieve what I'm trying to do (make readonly hp values for different characters and to be able to edit them from just the unity inspector).
MonoBehaviour instances are created using AddComponent, not by using new(). Because you are not creating the instance using the new keyword, there is no constructor to access.
If you want a variable that can be set from the inspector, but not public, use [SerializeField] on a private/protected field.
[SerializeField]
private float maxHealth;
public float MaxHealth => maxHealth; // Allow others to use this value, but not change it

Unity Custom Editor NullReferenceException When SerializedProperty Has Any Accessor

I am trying to make a custom editor in Unity for a ScriptableObject class which has private fields like such:
But has soon as one of my fields has an accessor (I also tried properties with get;), I get the following error when I try to see my ScriptableObject in the inspector.
I made some tests and it works perfectly without accessors. For instance, I can see the field "test".
Here is the code for my custom editor:
Any idea? I would not believe a custom editor for a class that has accessors would not be supported.
Thank you!
This has nothing to do with an "accessor". And note that properties are not serialized by Unity at all.
The mistake is pretty simple: Your field's name is not ingredients but rather _ingredients!
Therefore FindProperty("ingredients") returns null since it doesn't find any field called ingredients.
(This is assuming of course that Item is a [Serializable] type at all.)
To avoid exactly this type of issues I usually prefer to embed the editor into the type itself and use e.g.
public class YourType : MonoBehaviour /*or ScriptableObject*/
{
[SerializeField] private int _someField;
#if UNITY_EDITOR
[CustomEditor(typeof(YourType))]
private class YourTypeEditor : Editor
{
private SerializedProperty _someFieldProperty;
private void OnEnable()
{
_someFieldProperty = serializedObject.FindProperty(nameof(_someField));
}
...
}
#endif
}
so whenever you rename the fields it will be fixed in the Inspector automatically

How to hide the private variable with [SerializeField] inherit from the base class in the Inspector in Unity3d

When I have a private variable id, I write [SerializeField]before i define it:
class A{
[SerializeField]
private int id;
}
And, I have another class
Class B : A{
}
When I add the component B on one object, I can see variable id in the inspector, How can I hide it?
Writing a custom inspector is fine, but often tedious if the only thing you need to change is a visibility of a serialized field.
Try [HideInInspector] attribute before a serialized fields. It will be serialized but not shown in the inspector.
EDIT
Here's a couple of reference to understand serialization: ref1, ref2.
I'll try to explain in brief:
The process of setting the fields of your objects, and getting them,
is called deserialization and serialization respectively. Unity's
serializer is able to serialize many different kinds of fields, but
not all of them.
In a few words:
Serialization
Is the term used to indicate every data flow from the runtime memory to outside (such inspectors, files on the disk, ...)
Serialization
Is the term used to indicate every data flow towards the runtime memory to outside (es. change a value in the inspector and the serializer thread will deserialize it into the runtime memory).
The main point is that there are situations where you want a given field to be serialized (es. saved into a prefab on disk) but don't want to show it in the inspector.
If this is the case, rewriting a whole inspector is an overkill. Use instead [HideInInspector] attribute.
If you want it not to be serialized nor shown in the inspector, just let it private without [SerializedField] or public and mark it as[NonSerialized].
I believe that the only way is to build a custom inspector:
http://unity3d.com/learn/tutorials/modules/intermediate/editor/building-custom-inspector

Why does C# use [System.Serializable] for keeping instance? (Unity3D)

I wanted to make a programme if it take a TextAsset from inspector(it is placed in 'ExampleEditor'), it make a custom data instance for use blendshape animation.
At first I made my custom data class not using [System.Serializable].
public class Matrix {
public int row;
public int col;
public double[,] mat;
}
My strategy was taking a TextAsset, parsing string from TextAsset and finally making a Matrix instance to a field variable in 'Example.cs'. I thought when it was initialized and assigned first, I was able to use that variable in Example instance. However, It did not work, It threw 'NullReferenceException'.
So I found solution using '[System.Serializable]'. It did work. (and I knew that Unity3D does not provide multi-dimensional array for their serialization method.)
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
[System.Serializable]
public class Matrix {
[System.Serializable]
public class mRow {
public List<float> aRow = new List<float>();
}
[HideInInspector]
[SerializeField]
public int row;
[HideInInspector]
[SerializeField]
public int col;
//[HideInInspector]
[SerializeField]
public List<mRow> mat = new List<mRow>();
}
Finally, I know the solution, But I don't know why this problem was happened. It is related to GC?
Your question isn't very clear, but I think to know what you are not understanding.
My strategy was taking a TextAsset, parsing string from TextAsset and
finally making a Matrix instance to a field variable in 'Example.cs'.
You didn't explain how you did that (perhaps call the parsing function from a custom inspector?).
However, despite on how you managed to initialize a field from the editor, if the field isn't serializable, it will be null when switching from editor to play mode.
That happens because when entering play mode, Unity3D serializes all C# classes populating the relative C++ classes of the engine. If a field isn't a public field of a type that Unity can serialize (or even a private field marked with a SerializeFieldAttribute, always of a type that Unity can serialize ), Unity3D won't serialize it.
So when you switch to play mode the reference will be null.
In other word, all fields that you want to initialize from the editor MUST be serializable in order to be used in play mode.
[SerializeField]
public List<mRow> mat = new List<mRow>();
The code above doesn't make much sense. If you plan to intialize a serializable field from the inspector don't initialize it by code, otherwise you could eventually lose the reference.
An example of such an error:
[SerializeField]
private List<int> aList;
public void Start()
{
aList = new List<int>();
}
The code above will cause troubles. If you had initialized aList from inspector, it will be correctly serialized but when you switch in play mode e the Start callback is called, aList will be reinitialized and you'll end up with a reference to an empty list.
Here's a nice blog post explaining details on how Unity3D handle serialization of objects. Read it!

Unity Serializable Class Custom Inspector

I have a very simple class in unity, UnitRange (which has a minimum and a maximum range).
[System.Serializable]
public class UnitRange {
public int Minimum;
public int Maximum;
}
And this shows up in the inspector (if I make a public variable of this type.) Though the default way it is shown isn't very good:
Now, I was wondering how I can change this? I found how to change the inspector of monobehaviours, though couldn't find how to change it of other classes. I would like it to just be two numbers next to each other, something like this:
It's just a small thing, and not that big a problem if it's not possible, though knowing how to could prove more useful later too.
Oh yes, as you might have noticed, I'm using c#, so it would be nice if any example code is in c#.
Thanks.
This is no longer true in later versions of Unity.
Just found out this is not possible.
The only way to do this is, whenever you use it in a monobehaviour, to give that monobehaviour a custom inspector and in there give the class your custom layout. To make this easier you can make a method which does the layouting and then use that in each monobehaviour.
From Unity4 you can make this with PropertyDrawer
One solution that would require writing less custom inspectors would be to make UnitRange a component. Anything that needs a UnitRange you can annotate with [RequireComponent (typeof (UnitRange))] so you don't have to go through the hassle of adding it yourself. Make UnitRange check it's the only one attached (and error/remove itself etc if it's not).
Then make your various units cache the attached unit range component on Start() using GetComponent<UnitRange>(), ready for later use (as you currently do, if you just change the visibility to private and reuse).
Finally - write the inspector for UnitRange that looks nice.

Categories