Can't assign ScriptableObject in inspector - unity3d

I'm having trouble with assigning ScriptableObjects in inspector.
For example, I have this class:
using UnityEngine;
public class Buff : ScriptableObject {
public string buffName;
}
In one of the monobehavior-derived classes, I have a member like this:
public Buff testBuff;
In inspector I see the following, but I can't drag+drop script 'Buff' to this member
It works to drag+drop Buff as a new script, but I can't add it to 'Test Buff'.
What I tried instead of dragging+dropping is to simply create an instance of Buff like so:
public Buff testBuff = new Buff();
This worked:
However I believe drag+drop should work as well, plus the above gives warning:
Buff must be instantiated using the ScriptableObject.CreateInstance method instead of new Buff.
UnityEngine.ScriptableObject:.ctor()
Buff:.ctor()
...
I'm using Unity "5.0.2f1 Personal", which is the latest version.

You need to create an asset file that uses your Scriptable Object as it's type. This can only be done with an editor script. There is a generic one on the wiki.
Essentially you just create a menu item for each Scriptable Object type you have, use the menu item to create assets of those types, and then modify the assets with the values you want them to have. It's important to remember that SCOs are to be used as templates, if you modify a SCO either in the editor or with code those changes will instantly take effect on all GameObjects and Components that reference the SCO.

create asset with specific file extension inside custom inspector using EditorGUILayout.ObjectField; DefaultAsset; Open/Save dialog
detail video how do it

That's because you did not add[System.Serializable] at the Buff:ScriptableObject class, so all your "buff" is not serializable, and Unity Editor can't read c# directly, it can only read c# that are serialized.

Related

Creating an array/list of scripts for a Scriptable Object

So, I have an ItemObject which is a ScriptedObject
In an ItemObject I want to create an array/list that stores the scripts in it
The scripts that will be stored in this array/list will be used to extend the functionality of the GameObject (Imagine as unique skills for player, not attributes)
To do this, I'm going to add the script as a component with Player.AddComponent(SCRIPT.GetType())
So, it is assumed that after I create an item asset in the project directory, I can select the number of script skills and add them through the inspector
Also, as a sad alternative, I was considering using GameObject, which would store scripts as components. And that, to me, is terribly unhandy, given that there could be hundreds of the scripts. And unfortunately, I'm still not experienced enough, so it's the best I've come up with so far.
I solved my problem in the following way:
By adding the script as an Object and displaying its type in the console, I found out that it is a MonoScript
So just by adding using UnityEditor I was able to create a list consisting of MonoScript
using UnityEditor;
class Script : MonoBehaviour
{
List<MonoScript> scripts
}
And then, using [GameObject].AddComponent([MonoScript].GetClass()) I was able to add this script as a component to the GameObject
class AddScriptAsComponent : MonoBehaviour
{
GameObject object;
MonoScript script;
void Add()
{
object.AddComponent(script.GetClass())
}
}
You could do something like
using UnityEngine;
public class ItemObject : ScriptableObject{
[SerializeField] List<MonoBehaviour> scripts;
}
Although, if I'm understanding the objective correctly, maybe it would be a good idea to have a look at the concept of prefabs instead.

Is there a way to have a script reference an object as a field?

I've had trouble searching around and may be critically misunderstanding how Unity wants you to structure your project, but here is my situation:
I have characters in my game and would like to configure them in the editor. I have made classes that represent different behavior types and actions that can be performed. Is there a way for me to make a field on a script typed for these classes so that I can drag and drop using the inspector to configure different prefabs?
Here is some code demonstrating the situation:
Unit.cs
// A unit on the board.
public class Unit : MonoBehaviour
{
public UnitAction action;
}
UnitAction.cs
// A unit on the board.
public class UnitAction : MonoBehaviour
{
// Does things
}
These fields show up in the inspector once this script is applied to a prefab, but there are no options to populate the default field value. If I make the field type UnityEngine.Object, I can put the scripts there, but that seems like something I do not want.
It sounds like you are trying to serialize references to scripts themselves instead of instances of those scripts. There are a couple of ways that you may want to do this:
You could attach your UnitAction scripts as components of a GameObject that is in a context accessible to your "Unit" object (in the same scene, a child of the "Unit" object, or - probably the most common case - the "Unit" object itself). Then you will be able to serialize those instantiated components into the fields in your Unit class. This is the most common use case.
You could create a prefab for each of your UnitAction components and then serialize those prefabs into your Unit class fields. You would then instantiate a UnitAction at runtime. This doesn't really seem appropriate for your case based on what you described because a UnitAction probably isn't something that needs to be dynamically instantiated, but it is important to be aware of. This article has an example of using this method for giving a unit a list of spells (and also provides some good context on how to think about using unity components that would probably be valuable to you):
Unity: Now You're Thinking With Components
I would guess and say you do not want these scripts exposed except in editor, so you can use an attribute called SerializeField. It will expose the field to the editor so you are able to drag in references, but other scripts will not be able to access the fields you drop in.
If you want a specific script to appear in the editor, simply write
[SerializeField] private YourScriptName scriptReference = null;
As lists are generic structures, if you want, you can also make a list of scripts in a similar way
[SerializeField] private List<YourScriptName> scriptListReference = new List<YourScriptName>();
As I do not think you will be assigning these references again, if you want to grab the reference at any point, you can make a getter method.
public YourScriptName GetYourScript(){ return scriptReference;}
There are very few fields that Unity can not serialize, so generally, if you want to drag in a reference to a component, script, object, etc. all you need to do is make it either SerializeField or public followed by the type of whatever you want to drag in.
From the docs, the serialization system
CANNOT serialize static fields.
CANNOT serialize properties.
CAN serialize public non-static fields (of serializable types)
CAN serialize nonpublic non-static fields marked with the SerializeField attribute.
The fields that it can serialize are as follows
All classes inheriting from UnityEngine.Object, for example
GameObject, Component, MonoBehaviour, Texture2D, AnimationClip.
All basic data types, such as int, string, float, bool.
Some built-in types, such as Vector2, Vector3, Vector4, Quaternion, Matrix4x4, Color, Rect, LayerMask.
Arrays of a serializable type Lists of a
serializable type
Enums
Structs

Options to storing data in a prefab

After realizing that you can't really use UnityEvents in Scriptable Objects (they don't read global variable values correctly). I had to move to another solution for where to store my Dialogs.
The best solution I could find was to just store them in the corresponding NPC-prefab. This is really convenient. However this leaves a bad taste in my mouth, it just feels wrong to store data in a prefab like this. Is it a bad practice?
For example if I were to refactor something in the DialogObject, everything would be lost.
Since I can't seem to successfully store UnityEvents anywhere (can't serialize them as Json and as mentioned Scriptable Objects don't seem to handle them well) I feel like this is the only solution if I want to be able to use the Editor to create Dialogs.
Just checking here first, is this stupid? is there another way?
I am trying to save a List of this:
[System.Serializable]
public class DialogObject {
public List<PageData> conversations = new List<PageData>();
public UnityEvent postEvent; //Invoked on last page of Dialog
}
I would say yes, prefabs are meant to be a template to create new items of a type. You are trying to save data states.
Even though you cannot serialize the UnityEvent, you could serialize its content.
If you assign via inspector, you can use https://docs.unity3d.com/ScriptReference/Events.UnityEventBase.GetPersistentMethodName.html
But then you would not have problem of storage if you know from the start where it goes.
Second solution is when you assign the method to the UnityEvent, store it.
void AddListener (UnityAction ev)
{
MethodInfo mi = ev.Method;
// Use mi
postEvent.AddListener(ev);
}
With the mi reference, you have the name of the method, its type, the object it belongs to and anything you need.

AnyLogic - create objects dynamically on simulation time

Is it possible to dynamically create objects or modify them on run-time ?for example,on button click,another button created or change number of lines of a road?
When I write this code for a button Action,in run-time
road123.setBackwardLanesCount(3);
I get error below:
root:
road123: Markup element is already initiated and cannot be modified.Please use constructor without arguments,perform setup and finally call initialize() .function
You'll get that error with any object you attempt to create at runtime using a parameterized constructor. If you create the object with a simple constructor (just "()") and then set all of the parameters individually, you won't run into that issue. Check the Anylogic API for specific information about the object you are using, because some require you to call .initiliaze() on that object after setting all of it's parameters if you created it using a simple constructor. Furthermore, if you want to add the object to the screen at runtime you'll need to add this code to the function that creates it:
#Override
public void onDraw( Panel panel, Graphics2D graphics) {
obj.drawModel(panel, graphics, true);
}
where obj is replaced with the name of the object you created dynamically.

Saving MethodInfo variable in Unity EditorWindow to Component, var resets on compile

I'm trying to save a MethodInfo to a script through an editor window. When I create the script that should remember the method info it works well but whenever unity recompiles, (Run-Time, script has changed or unity restarts) the MethodInfo variable has been reset to null. I've tried serializing the class that saves it and making the MethodInfo a SerializedField,
What happens precisely: I select a Component belonging to a GameObject and a MethodInfo belonging to that component. Then create a new GameObject containing a script that has variables for GameObject, Component & MethodInfo. I then set those variables to the selected vars. Untill now it works. When unity compiles again the GameObject and Component are still saved but the MethodInfo has turned to null.
Any help would be greatly appreciated.
I don't think Unity will be able to serialize an object of MethodInfo class. And even if it was: as Unity is a cross platform engine, there is no guarantee that an object of MethodInfo, as it was saved in the Editor, will be compatible with an object of MethodInfo as it would exist in the platform specific build.
You will have to store the name of the target method and use that together with Reflection to find the correct method at runtime. If the method is overloaded by signature you'll also have to decide which overload to take at runtime.