I haven’t used Scriptable Objects before so maybe this is possible, and hopefully it is.
A normal object can have the following (it will look familiar if you have used the standard controller assets):
public class Controller: MonoBehaviour
{
[Serializable]
public class MovementSettings
{
public float ForwardSpeed = 8.0f; // Speed when walking forward
public float BackwardSpeed = 4.0f; // Speed when walking backwards
}
What’s great about this is it makes the properties of this class really clear as to what they are without needing to name each one with long names, but also the inspector kindly collapses each sub class.
Unfortunately doing this in a Scriptable Object doesn’t seem to be possible because the properties don’t show in the inspector. For the following you can only set the name:
using System;
using UnityEngine;
using System.Collections;
public class Name : ScriptableObject
{
public string Name;
public class Sounds
{
public AudioClip[] Ambient;
public AudioClip[] OneShots;
}
}
ScriptableObject is for storing data only and not something that you can attach to a GameObject. That means you will get no variable throughput in the inspector.
So, unfortunately I’m going to have to say it isn’t possible. If you want to attach this script to a GameObject it has to inherit from MonoBehaviour
Can you give me more details on exactly what you are trying to achieve. I have a lot of experience with custom editors and may be able to point you in the right direction.
So I don’t want to attach it to an object. Basically I want to create an Environment class or something similar which holds properties such as which objects, textures, sounds etc to use. Then in my environment generator I will have an array of possible environments to choose from. I create instances of the scriptable object for each biome. It works great other than it looks messy.
using System;
using UnityEngine;
using System.Collections;
public class Name : ScriptableObject
{
public string Name;
public SoundEffects Sounds;
}
[Serializable]
public class SoundEffects
{
public AudioClip[] Ambient;
public AudioClip[] OneShots;
}
By creating the classes outside the scriptable object
Perfect. Glad you figured it out! If you need any help in the future feel free to get at me via my website or my Twitter account: Links in my signature. Best of luck in all your future endeavours!
And to make it Serializable. You could have kept SoundEffects inside the ScriptableObject definition:
using System;
using UnityEngine;
using System.Collections;
public class Name : ScriptableObject
{
public string Name;
//[Serializable] //<-- Need this line to make it show in the inspector.
// ^ edit: sorry, wasn't paying attention. This is a ScriptableObject. Don't need this.
public class SoundEffects
{
public AudioClip[] Ambient;
public AudioClip[] OneShots;
}
public SoundEffects Sounds; //<-- And this line to declare the variable.
}
I think his goal was to get it outside of the script so he can keep the main class tidy and just reference the other classes when he needs them.
I use this idea myself… it makes access to the variables a little bit longer but it works fine. If you have lots of data this is much better than stuffing it all in the main class.
Sorry but this is wrong. The way I am doing it feels like a trick because I have to create the class outside and declare a variable of that type inside.
I posted the first block of code for a reason: This shows you can create a subclass MovementSettings so that if you have an object of type Controller and want to access the forward movement speed you do “ControllerObject.MovementSettings.ForwardSpeed”
See above.
With a ScriptableObject it serializes anyway so didn’t think it would be necessary to specify it but I did try with and without marking it serializable anyway.
You wrote “this did the trick” and stated that you just put the class outside of its enclosing class. But this actually doesn’t do anything to your ScriptableObject subclass. What actually “did the trick” was to put a member “public SoundEffects Sounds” into your ScriptableObject subclass - at all. I was just pointing that out, and I don’t think I am wrong here
[quote=“blizzy, post:16, topic: 577702, username:blizzy”]
You wrote “this did the trick” and stated that you just put the class outside of its enclosing class. But this actually doesn’t do anything to your ScriptableObject subclass. What actually “did the trick” was to put a member “public SoundEffects Sounds” into your ScriptableObject subclass - at all. I was just pointing that out, and I don’t think I am wrong here
[/quote]My point is that you don’t need a member “public SoundEffects Sounds” when NOT using a ScriptableObject, you just declare it at serializible and then you immediately can start setting those values in the inspector. In the first block of code I posted that works perfectly (it’s from the FPSController script) WITHOUT declaring a member. I wanted to be able to set the values in the inspector in a tidy way, and that’s ‘the trick’ that can be achieved with this alternative method when using a ScriptableObject.
Is there a way to achieve this in the same way that it can be achieved when not using a ScriptableObject?
If you don’t declare a public member variable, there’s nothing to be serialized; you can’t just define a type without declaring a variable. Is the member variable of type MovementSettings declared somewhere else in Controller perhaps?
This is what I thought and realise now to be true. Yes it was an oversight on my behalf that further down the script it is declared. No magic trick here then, my bad!