Search Unity

How do I access a Scriptable Object as an Enum in code?

Discussion in 'Scripting' started by quyrean, Apr 22, 2018.

  1. quyrean

    quyrean

    Joined:
    Nov 29, 2016
    Posts:
    16
    I have watched the videos,
    and
    https://www.youtube.com/watch?v=raQ3iHhE_Kk

    and done every tutorial I can find on the subject, but I still don't get how to use a scriptable object as an enum. I don't understand how to access the values from code and I cannot find an example. I feel like I must be missing something obvious, so any help is appreciated. Thanks.

    The example is that there are different races, Human and Martian, and the code wants to do something different for each race. We want to add other races later, so I am trying to make it easy to add races without having to edit an enum, something the designer can do from the inspector. Then later I can add any specific code for each race. How do I say

    if(race == martian)

    with a scriptable object?

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. [CreateAssetMenu]
    4. public class RaceSO : ScriptableObject {
    5.     public string Name;
    6.     public string Description;
    7. }
    8.  
    Code (CSharp):
    1. using UnityEngine;
    2. public class RaceTest : MonoBehaviour {
    3.    //I want to get rid of this enum and use a SO
    4.     public enum RaceEnum { Human, Martian };
    5.     //example of what I need to do
    6.     public void checkRaceEnum(RaceEnum race) {
    7.         if (race == RaceEnum.Human) {
    8.             //do human stuff
    9.         } else if (race == RaceEnum.Martian) {
    10.             //kill humans
    11.         }
    12.     }
    13.    
    14.    //I don't understand how to do this with a scriptableobject
    15.     public void checkRaceSO(RaceSO raceSO) {
    16.         if(raceSO == /* what goes here?? */ ) {
    17.             //do human stuff
    18.         } else if (raceSO == /* martian */ ) {
    19.             //kill humans
    20.         }
    21.     }
    22.    
    23. }
    24.  
     
  2. Ian094

    Ian094

    Joined:
    Jun 20, 2013
    Posts:
    1,548
    You could add the enum to the RaceSO class:
    Code (CSharp):
    1. public class RaceSO : ScriptableObject
    2. {
    3.     public RaceTest.RaceEnum race;
    4.     public string Name;
    5.     public string Description;
    6. }
    Now, check the enum in the checkRaceSO function:
    Code (CSharp):
    1. public void checkRaceSO(RaceSO raceSO)
    2. {
    3.     if(raceSO.race == RaceEnum.Human)
    4.     {
    5.         //Do human stuff
    6.     }
    7.  
    8.      //etc...
    9. }
     
  3. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    I remember that video..
    Instead of comparing an enum value, you could compare to the referenced Scriptable object.

    So, comparing human and martian, you'd create 2 RaceSO instances. In code that needs to do a comparison, you'd like one or both of them as a reference to compare.

    Your example...
    Code (csharp):
    1. public RaceSO human;
    2. public RaceSO martian;
    3.  
    4. public void checkRaceSO(RaceSO raceSO) {
    5.    if(raceSO == human) // code here
    6.    else if(raceSO == martian) // etc..
    7.  }
    Is that what you were after?
     
    Grave188 likes this.
  4. quyrean

    quyrean

    Joined:
    Nov 29, 2016
    Posts:
    16
    Yes, that should do it! Thank you very much.
     
  5. xjjon

    xjjon

    Joined:
    Apr 15, 2016
    Posts:
    612
    The better approach may be to have a single variable for `race` and then put the SO you want there.

    Something like

    Code (CSharp):
    1. public class RaceTest {
    2.  
    3. public RaceSO Race;
    4.  
    5. }
    There are ways to get the 'dropdown' of all the ScriptableObjects of `Race` type, similar to what an enum dropdown would look like if you create a custom editor.

    The asset `Odin Inspector` supports this behavior out of the box if you're interested in making life easier for the designer.
     
    NeatWolf likes this.
  6. quyrean

    quyrean

    Joined:
    Nov 29, 2016
    Posts:
    16
    Thanks for the input, however setting the variable in the inspector is not the problem. The problem that is never answered in the videos is how to check the variable in CODE, with an if or switch statement, how do I tell what the variable is set to? I don't understand how your approach solves that problem.
     
    DSivtsov, Baydogan and AmbroseFurback like this.
  7. xjjon

    xjjon

    Joined:
    Apr 15, 2016
    Posts:
    612
    So I'm guessing you need to do some stuff if it's a human SO, some stuff if it's alienSO right?

    The proper way to design this would be to compose your logic into different components, which is sort of what you are doing - but you could take it one step further and have the 'logic' you want to execute in SOs, which avoids the if/else stuff completely.

    Code (CSharp):
    1.    
    2. public class RaceTest {
    3.    
    4.     public RaceSO Race;
    5.  
    6.     public void CheckRace() {
    7.         race.DoSomething();
    8.     }
    9.    
    10. }
    11.  
    You could then create an interface that both SOs implement, to get that `DoSomething()` behavior.

    Code (CSharp):
    1. public interface IRace {
    2.     void DoSomething();
    3. }
    Then when your RaceTest needs that behavior, it doesn't have to care or check which type of SO you have, it just delegates the responsibility to the actual SO.
     
  8. eestradaRAS

    eestradaRAS

    Joined:
    Apr 2, 2018
    Posts:
    4
    Just check the Repo:
    https://github.com/roboryantron/Unite2017/blob/master/Assets/Code/Elements/Elemental.cs
    and
    https://github.com/roboryantron/Unite2017/blob/master/Assets/Code/Elements/AttackElement.cs

    are what you are looking for:

    He defines a list of the elements an object can defeat (Which are SO References) in the "Element SO":
    Code (CSharp):
    1. public List<AttackElement> DefeatedElements = new List<AttackElement>();
    And then, in the elemental monobehaviour he does the check:

    Code (CSharp):
    1. //References what element this is, so, this is THE ENUM
    2. [Tooltip("Element represented by this elemental.")]
    3.         public AttackElement Element;
    4.  
    5. //.... Bla bla
    6.  
    7. private void OnTriggerEnter(Collider other)
    8.         {
    9.         //Gets the other object element type
    10.             Elemental e = other.gameObject.GetComponent<Elemental>();
    11.             if (e != null)
    12.             {
    13.             //And if it is on the DefeatedList, deletes
    14.                 if (e.Element.DefeatedElements.Contains(Element))
    15.                     Destroy(gameObject);
    16.             }
    17.         }
    Of course, this is just for demo, but you get the gist. Hope it helps.
     
    Rallix, conNen, Simiridium and 3 others like this.
  9. UnseenBeyond

    UnseenBeyond

    Joined:
    Jul 2, 2015
    Posts:
    2
    Best answer