I just started using Unity (which came with VSC), but I had better experience using JetBarin products such as IntelliJ IDEA, so I went and switched to Rider. However, I am now unable to connect public variables (int, float, GameObject) to my Unity projects.
I tried updating Rider and changing some setting, but came none the wiser.
UPDATE: There have been (obvious) request for my code to see the exact issue, so I hope this helps clear up the issue a little bit:
Code written in VSC
The resulting public variables showing up in Unity
Similar code written using Rider
No interactive variables showing up in Unity
Unity serializes only fields (not properties with get or set) of MonoBehaviours. All public fields are serialized unless have [System.NonSerialized] attribute.
DO NOT get confused with the [HideInInspector] attribute, it won't be visible in the inspector (if you don't have a custom inspector) but WILL BE serialized.
class Foo
{
// Bar won't be shown in the inspector or serialized.
[System.NonSerialized]
public int Bar = 5;
}
To serialize a non-public field use [SerializeField] attribute for primitive types (such as int, float, bool).
public class SomePerson : MonoBehaviour
{
// This field gets serialized because it is public.
public string name = "John";
// This field does not get serialized because it is private.
private int age = 40;
// This field gets serialized even though it is private
// because it has the SerializeField attribute applied.
[SerializeField]
private bool isMale = true;
}
If you wanna serialize own class or struct, use [System.Serializable] attribute.
[System.Serializable]
public struct PlayerStats
{
public int level;
public int health;
}
Related
I want to see the Dictionary used by Unity on the Inspector. But I don't know if it's possible or not, and I don't know how.
Please tell me how to see the Dictionary on the inspector. Or you can tell me about other data structures similar to Dictionary in Unity.
Short answer is no, you can't serialize them.
But you have some options, I'll provide you with one.
Suppose you want to create a Dictionary<string, int>. You can create a class/struct that holds this information:
using System;
[Serializable]
public class StringIntPair {
public string key;
public int value;
}
And then, in your code, you can create a List<StringIntPair>, that will be visible on your inspector. This way you can set the values you want in the inspector.
Lastly, you can create a Dictionary<string, int> and populate it in Awake / Start method as you wish:
using System;
[Serializable]
public class YourClass : MonoBehaviour {
public List<StringIntPair> exposedDictionary;
Dictionary<string, int> hiddenDictionary;
void Awake(){
foreach(StringIntPair pair in exposedDictionary)
hiddenDictionary[pair.key] = pair.value;
}
}
And then you can use hiddenDictionary in the code as you wish.
Yesterday I've found out about Scriptable Objects in Unity.The first thing that came to my mind is : hey , this is really simillar to inheritance.Let's say I have this:
[CreateAssetMenu(menuName = "Scriptableobjects/enemy_data")]
public class enemydata : ScriptableObject
{
public float HP;
public float mana;
public float damage;
}
If I have three enemies A , B , C i will just create 3 instances of enemy_data in my project assets , and complete HP , mana,damage individually.On each of my enemy monobehaviour i'll say :
public enemydata data;
And I'll drag the instances from project assets in their inspector.This is what I understood about scriptable objects from the tutorials I have seen.But , what if i did this:
public class enemydata
{
public float HP;
public float mana;
public float damage;
}
And just inherit this class?Wouldn't this be the same thing?
public class enemy1:MonoBehaviour , enemydata
{
void print()
{
Debug.Log(this.HP + " " this.mana + " " + this.damage);
}
I know I am missing something so please correct me.Thanks!
It is exactly the same thing, yes.
BUT ScriptableObjects are Assets and therefore you can
reference it at multiple places (re-use it)
you can have multiple instances but with different values => easily exchange e.g. settings without having to recompile your code
you can have a base class and inherit different types of ScriptableObjects and still reference them via the Inspector
This last point can be used to e.g. implement exchangeable behaviour. A bit like an interface but you can exchange the actual method implementation without having to recompile so it can even happen on runtime.
This is a huge advantage against the basic [Serializable] public class EnemyData { ... } for which you would already in code have to define which type to use exactly.
This makes ScriptableObjects quite powerful and they have a lot of usecases. (See e.g. How to pass data between scenes in Unity)
Most Unity configurations are based on ScriptableObject e.g. the AnimatorController.
Your last example
public class enemy1:MonoBehaviour , enemydata
{
void print()
{
Debug.Log(this.HP + " " this.mana + " " + this.damage);
}
}
makes no sense. You can only derive from one class so either MonoBehaviour or enemyData!
If something it would need to be a field like
public class enemy1:MonoBehaviour
{
[SerializeField] private enemydata data;
void print()
{
Debug.Log(data.HP + " " data.mana + " " + data.damage);
}
}
You can not inherit from 2 classes and only ScriptableObject assets are draggable in the inspector.
The main use for SO is to easily share the same values/data across different components through simple drag and drop. For example your player have a component that adds/removed hit points from PlayerHealth SO. Then you can have on some completely unrelated place LevelReseter component, you just drag PlayerHealth asset and monitor when it reaches zero to reset the level. It should be noted that ScriptableObjects does not serialize their modified values when closing the game, i.e. they can not be directly used to save data across different app runs.
BTW another use for ScriptableObjects is to achieve Strategy Pattern through inspector drag and drop, i.e. swapping algorithms by swapping ScriptableObject assets implementing the same interface (or even better inheriting from the same base class).
In Unity am creating an item system using the base class:
[CreateAssetMenu]
class ItemBase : ScriptableObject(){
public string ItemName;
public Sprite ItemSprite;
void Spawn() {
//Spawn Item Using The Sprite
}
}
and then I am using the CreateAssetMenu to right click in my project folder for each item I want to add to the game and then assign their values in the editor.
When i drag my object from the editor onto a game object, everything works fine.
The issue im having is that I cannot figure out how to actually instantiate these at runtime from a script.
When I try to reference it like a class, the class is not found, when I add a script that mirrors the created item, the properties set by the editor are null upon instantiation.
Ideally what id like to do is something like:
Right click and create new ItemBase called FishingRod from editor
Assign name and sprite in editor
\\Instantiate From Script
FishingRod rod = ScriptableObject.CreateInstance(typeof(FishingRod)); // Properties should be the properties set by editor
FishingRod.Spawn(); // Inserts Item Into Game
But when I instantiate the class, its properties are null;
rod.ItemSprite //is null
rod.ItemName //is null
From your use case description it sounds like you shouldn't need to create instances of the ScriptableObject on runtime. You rather want to reference and use the ones you already created.
So what you should do is
(As you already did) create a new ItemBase instance via the Inspector's Asset create menu (Create -> ItemBase)
(As you already did) fill this "container" with your data (name and sprite)
Now in the file that want's to use this asset reference it via a field in the Inspector:
// In the Inspector go to according GameObject
// and drag the ScriptableObject you created into this slot
[SerilaizeField] private ItemBase fishingRod;
And then you simply use the values and methods of this instance via
fishingRod.Spawn();
So if you want to switch between different items you would e.g. have a kind of controller script like
[SerilaizeField] private ItemBase fishingRod;
[SerilaizeField] private ItemBase hammer;
[SerilaizeField] private ItemBase umbrella;
Then you could switch between them like e.g.
private ItemBase _activeItem;
public void SelectFishingRod()
{
_activeItem = fishingRod;
}
public void SelectHammer()
{
_activeItem = hammer;
}
public void SelectUmbrella()
{
_activeItem = umbrella;
}
and then e.g. do
public void UseActiveTool()
{
_activeItem.Spawn();
}
What is the use of constructor here ?
This is script A :
[SerializeField]
private LobbyFunction _lobbyFunction;
public LobbyFunction LobbyFunction
{
get { return _lobbyFunction; }
}
This is script B:
private void Start()
{
GameObject lobbyCanvasGO = CanvasManager.Instance.LobbyFunction.gameObject;
if (lobbyCanvasGO == null) return;
}
what if I choose not to use the encapsulation ? no error , I guess .Any help would be greatly appreciated ,thanks!
edit: I guess using encapsulation here make the var read- only , only get... and therefore increase the security , people from outside can't change the value ,is it the ans?
This is no constructor but a Property
A property is a member that provides a flexible mechanism to read, write, or compute the value of a private field. Properties can be used as if they are public data members, but they are actually special methods called accessors. This enables data to be accessed easily and still helps promote the safety and flexibility of methods.
In your case it is for granting Read-Only access to the private backing field _lobbyFunction so no other class can change its value since only the class "A" containing _lobbyFunction itself is allowed to assign it.
Btw the way you have it it is equivalent to simply write
public LobbyFunction LobbyFunction { get; private set; }
without the need for a backing field. Then still only the containing class "A" itself is allowed to assign a value while everyone else can read it.
While trying to make a script for building assets, I ran into an issue with unity's serialization. I have a class in which I store some arbitrary information, which is then stored in an array in a MonoBehaviour on a prefab. I cannot for the life of me get the array to save however, as when I make the object into a prefab it loses the list's values. I have tried using [System.Serializable] and ScriptableObject, but both seem to pose their own new issues.
For instance, using ScriptableObject would mean having to save the data objects as assets, which would become way too much since these objects can get to hundreds in number.
Am I making a mistake in my understanding of unity's serialization? Is there a way to get this working without the ScriptableObject approach of saving every ArbitraryInfo object in an asset?
Data object:
[System.Serializable]
public class ArbitraryInfo{
public int intValue;
public Vector3 vectorValue;
}
OR
public class ArbitraryInfo : ScriptableObject {
public int intValue;
public Vector3 vectorValue;
void OnEnable() {
hideflags = HideFlags.HideAndDontSave;
}
}
Behaviour:
public class MyBuilder : MonoBehaviour {
public ArbitraryInfo[] infoArray;
}
Editor:
[CustomEditor(typeof(MyBuilder))]
public class MyBuilderEditor : Editor {
private SerializedProperty infoArrayProperty;
void OnLoad() {
infoArrayProperty = serializedObject.FindProperty("infoArray");
}
void OnInspectorGUI() {
serializedObject.Update();
for (var i = 0; i < infoArrayProperty.arraySize; i++) {
if (i > 0) EditorGUILayout.Space();
var info = infoArrayProperty.GetArrayElementAtIndex(i).objectReferenceValue as ArbitraryInfo;
EditorGUILayout.LabelField("Info " + i, EditorStyles.boldLabel);
info.intValue = EditorGUILayout.IntField(info.intValue);
info.vectorValue = EditorGUILayout.Vector3Field(info.vectorValue);
}
serializedObject.ApplyModifiedProperties();
}
}
EDIT 1, Thank you derHugo
I changed my code to incorporate the changes. Now there are errors for ArbitraryInfo not being a supported pptr value.
Secondly, ArbitraryInfo no longer being a ScriptableObject poses the question of how to initialize it. An empty object can be added to infoArrayProperty through infoArrayProperty.arraySize++, but this new empty object seems to be null in my case. This might be due to the pptr issue mentioned above.
EDIT 2
The issue I was having was caused by another piece of code where I tried to check if infoArrayProperty.objectReferenceValue == null. I changed this to another check that did the same thing and everything worked!
No, no ScriptableObject needed.
But note that GetArrayElementAtIndex(i) returns a SerializedProperty. You can not simply parse it to your target class.
so instead of
var info = infoArrayProperty.GetArrayElementAtIndex(i).objectReferenceValue as ArbitraryInfo;
and
info.intValue = EditorGUILayout.IntField(info.intValue);
info.vectorValue = EditorGUILayout.Vector3Field(info.vectorValue);
you have to get the info's SerializedPropertys by using FindPropertyRelative:
var info = infoArrayProperty.GetArrayElementAtIndex(i);
var intValue = info.FindPropertyRelative("intValue");
var vectorValue = info.FindPropertyRelative("vectorValue");
than you can/should use PropertyFields
EditorGUILayout.PropertyField(intValue);
EditorGUILayout.PropertyField(vectorValue);
allways try to avoid using direct setters and use those SerializedProperties instead! This provides you with Undo/Redo functionality and marking the changed Behaviour/Scene as unsaved automatically. Otherwise you would have to tak care of that manually (... don't ^^).