Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

How can I expose variables of an asset in the inspector?

Discussion in 'Scripting' started by fgbg, Jun 21, 2020.

  1. fgbg

    fgbg

    Joined:
    Dec 22, 2012
    Posts:
    53
    I have an Abilities class who's sole job is to hold the abilities my player can use, which I attach to my player:

    Code (CSharp):
    1. public class Abilities : MonoBehaviour
    2. {
    3.     [SerializeField] Ability ability1;
    4.     [SerializeField] Ability ability2;
    5.     [SerializeField] Ability ability3;
    6.  
    7.     public void Start()
    8.     {
    9.         ability1 = new TeleportAbility();
    10.     }
    11. }
    I have an abstract Ability class that all abilities inherit from:
    Code (CSharp):
    1. public abstract class Ability : ScriptableObject
    2. {
    3.     public int cooldown;
    4.     //more stuff later like icon and sounds
    5.  
    6.     public Ability()
    7.     {
    8.  
    9.     }
    10. }
    Finally, I have an actual ability like TeleportAbility:
    Code (CSharp):
    1. [CreateAssetMenu]
    2. public class TeleportAbility : Ability
    3. {
    4.     public TeleportAbility()
    5.     {
    6.         cooldown = 10;
    7.     }
    8.  
    9.     public void DoAbility()
    10.     {
    11.         //Ability logic here
    12.     }
    13. }
    During runtime it looks like this:
    upload_2020-6-21_15-45-1.png
    Later, the controls will access Abilities.ability1.DoAbility(). That's fine and should work.

    However, what I also want to see is ability1's cooldown, icon and sound assets from this inspector view too. Is there a way to get these to show up with my current architecture and in a clean way code-wise? If not, how can I re-architect it to make this work?

    Now, I know that I can make an asset from the TeleportAbility scriptable object, but that showS its variables on the asset's inspector view, not in the Abilities' inspector view on my player prefab:
    upload_2020-6-21_15-55-30.png

    upload_2020-6-21_15-55-22.png

    Ideally, I don't do something like this...
    Code (CSharp):
    1. public class Abilities : MonoBehaviour
    2. {
    3.     [SerializeField] Ability ability1;
    4.     [SerializeField] int cooldown1;
    5.     [SerializeField] Ability ability2;
    6.     [SerializeField] int cooldown2;
    7.     [SerializeField] Ability ability3;
    8.     [SerializeField] int cooldown3;
    9.  
    10.     public void Start()
    11.     {
    12.         ability1 = new TeleportAbility();
    13.         cooldown1 = ability1.cooldown;
    14.         ability2 = new FireBallAbility();
    15.         cooldown2 = ability2.cooldown;
    16.         ability3 = new ShieldSlamAbility();
    17.         cooldown3 = ability3.cooldown;
    18.     }
    19. }
    ... which doesn't even work anyways because if I apply the TeleportAbility asset, the cooldown isn't updated in the inspector until runtime.
     
    Last edited: Jun 21, 2020
  2. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    9,916
    You just need to write a custom inspector. Something like this:


    And check the manual about custom inspectors.
     
  3. fgbg

    fgbg

    Joined:
    Dec 22, 2012
    Posts:
    53
    Awesome thanks! Taking a look now.
     
  4. fgbg

    fgbg

    Joined:
    Dec 22, 2012
    Posts:
    53
    Hmm ok after looking at it... but what if I want to show properties that are unique to say, the LeapAbility() which has a new variable called jumpHeight or something? Is there anyway to build these dynamically instead of setting the properties statically in the editor code?
     
  5. fgbg

    fgbg

    Joined:
    Dec 22, 2012
    Posts:
    53
    Or am I asking for too much? If so... is there a better way to architect this little ability system?
     
  6. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    You could create a wrapper class that contains an Ability ScriptableObject and a cooldown variable separately:
    Code (CSharp):
    1. [Serializable]
    2. public class AbilityWrapper
    3. {
    4.    [SerializeField] Ability ability;
    5.    [SerializeField] int cooldown;
    6.  
    7.    public AbilityWrapper(Ability ability, int cooldown)
    8.    {
    9.       this.ability = ability;
    10.       this.cooldown = cooldown;
    11.    }
    12. }
    Then in your Abilities class, replace all Ability declarations with AbilityWrappers:
    Code (CSharp):
    1. public class Abilities : MonoBehaviour
    2. {
    3.    [SerializeField] AbilityWrapper ability1;
    4.    [SerializeField] AbilityWrapper ability2;
    5.    [SerializeField] AbilityWrapper ability3;
    6.  
    7.    public void Start()
    8.    {
    9.        ability1 = new AbilityWrapper(new TeleportAbility(), 10);
    10.    }
    11. }
    This should make the inspector show:
    • Ability 1
      • (Ability)
      • (Cooldown)
    • Ability 2
      • (Ability)
      • (Cooldown)
    • Ability 3
      • (Ability)
      • (Cooldown)
    From there, you could remove the "cooldown" variable from the Ability class.

    Personally, I don't particularly like how this looks myself. It would look nice in the Unity inspector, but feels a bit messy in code.
     
    Last edited: Jun 23, 2020
    fgbg likes this.