Extendable Enums with ScriptableObjects
I think that anyone who got interested in the usage of scriptable objects has seen Richard Fine's talk (link in case someone didn't : https://www.youtube.com/watch?v=6vmRwLYWNRo).
It's been really helpful and clear but the extendable enums things has not been explained with an example and i guess that it's so easy that it doesn't need one but for some reason i can't wrap my head around it.
Suppose i have this enum: enum DmgType {Fire, Water, Air}
if i have a field with a type of DmgType i can do the following : dmgType.Fire
.
What interests me a lot with enum is that when I'm writing that i get all the possible types in my enum and If i'm assigning its value in the inspector i get a dropdown with all the possible values. So my question is how do you actually do that with scriptable objects
Answer by Hellium · Jan 23, 2018 at 03:52 PM
You just have to create a simple ScriptableObject as follow:
using UnityEngine;
[CreateAssetMenu( fileName = "DamageType", menuName = "DamageType" )]
public class DamageType : ScriptableObject{}
Then, in your other script, declare a serialized variable of DamageType
type:
using UnityEngine;
public class Weapon : MonoBehaviour
{
[SerializeField]
private DamageType damageType;
}
You will be able to drag & drop a DamageType
asset into the serialized field of your Weapon
class.
Thank you for your quick answer, basically i already knew this part but is it really all that it's about ? just creating multiple DamageType assets then dragging the one you want to assign to your weapon ? I mean as i already mentioned in the question, one of the things that interest me the most is having the ability to get what damage types do i actually have. How will i test if this weapon's damage type is Fire or Water ? can this usage of scriptable objects help with having a drop down in the inspector containing all the DamageTypes i have already created.
In the inspector, once you have the serialized DamageType
field, click on the little circle with a point inside, and the assets explorer will pop-up. You will be able to select the desired scriptableobject from there. It's a little bit like the drop down of the enumerations.
I am a bit late on this post but I am exactly looking for the same thing : having a dropdown by code of all SO enums added in inspector like "damageTypes.Fire || damageTypes.Water" where Fire and Water are the names of the SO serialized in inspector
@Hellium, thank you for trying to help but you didn't answer the question
Answer by OAlexM · Jan 10, 2020 at 08:17 AM
I know this post is 2 years old. But it is on top of the google search. So I try to give an answer to this. The problem with enum as a code construct is, that you have to check what kind of damage the weapon is doing before switch / case to the correct value of damage amount for example, or to which effect you play if the weapon hits. It would look like:
val damageAmount = 0;
switch(damageType)
{
case DmgType.Water:
damageAmount = 2;
break;
case DmgType.Fire:
damageAmount = 4;
break;
// ...
}
The same for all other decisions in code where you need to know what data you need for the current DmgType. Assume you could ask the enum itself for its damageAmount. Like this:
var damageAmount = damageType.amountOfDamage;
It is a one liner. The thing is you could put all these configuration values inside the ScriptableObject class you implemented for your enum type. For every other needed configuration do the same provide a property field in the ScriptableEnum class, that's it. Even conditional questions in code could be solved very easy. For example if you have to decide if the weapon is usable on the enemy. For example there is a fire demon. And your weapon has the DmgType.Fire it is useless against this fire demon. Normally you make an if in the code. But think about the if then elses you need per enemy type to decide if the weapon is usable against them? With the scriptable enum it is easy just implement a:
List<EnemyType> beatable;
bool CanBeat(EnemyType enemytype)
{
return beatable.Contains(enemyType);
}
into the ScriptableEnum class where you can easily put in all types of enemies that are beatable. And the best thing is, if you have this kind of ScriptableEnums all over your code, it is absolutely easy to implement a new weapon without changing one line of code. Just create the new asset object and define all values, conditions and prefabs there. It will work all over your code automatically. The funny thing is you will never have the need again to know if the weapon has the DmgType of fire. :)
This answer helped me see the benefits of using scriptable object "enums" (i find it better not to think of them as enums because enums are just an array of strings really, while these extendable objects are a beast. I used them for creating different game phases, so for example instead of having an enum that looked like this:
public enum GamePhase{
DayPhase.
NightPhase.
HellPhase
}
and comparing values in controllers with values in the enum now I have separate scriptable objects of class GamePhase that have all the info a gamePhase has, like duration, skybox, and whatnot, so in a sense I moved all the data from the controllers to the Scrptable Objects. Awesome stuff