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

Need help with custom editor

Discussion in 'Scripting' started by MajorSmurf, Jan 1, 2021.

  1. MajorSmurf

    MajorSmurf

    Joined:
    Feb 1, 2018
    Posts:
    16
    Hi there I need some help and to get a basic understanding of how to make custom editors. I know the super basics and can do basic things with it but I can't find any useful tutorials on what to do I'm trying to achieve or if its even possible. Let me explain what I'm trying to do:

    upload_2021-1-1_1-0-18.png

    The above screenshot shows a scriptable object for an ability which holds an array of ability attributes which is a custom class. I want to show/hide variables depending on the ability type or if any variable is true and make the editor display/hide variables depending on its type. (e.g. if its a buff type maybe a bool appears etc.) My basic understanding lead me to this simple code (Show below) which just displays an int field on the editor if even one in the array is marked as a damage type when what I want it is for it to only display for the one in the array marked that type. (Btw the damage number is appearing as its currently just a public variable and has nothing to do with script).

    SUPER BASIC EDITOR SCRIPT
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEditor;
    5.  
    6. [CustomEditor(typeof(Ability))]
    7. public class CustomAbilityEditorScript : Editor
    8. {
    9.     public override void OnInspectorGUI ()
    10.     {
    11.         base.OnInspectorGUI ();
    12.  
    13.         Ability a = (Ability)target;
    14.  
    15.         for (int i = 0; i <= a.abilityAttributes.Length - 1; i++)
    16.         {
    17.             if (a.abilityAttributes[i].abilityType == AbilityAttributes.AbilityTypes.Damage)
    18.             {
    19.                 a.abilityAttributes[i].damageNumber = EditorGUILayout.IntField ("Damage Number", a.abilityAttributes[i].damageNumber);
    20.             }
    21.         }
    22.     }
    23.  
    24. }
    I shall also show the Ability code which also holds the ability attribute class to give a full picture.

    Ability and ability attribute class
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [CreateAssetMenu(fileName = "New Ability", menuName = "Ability System/Default")]
    6. public class Ability : ScriptableObject
    7. {
    8.     public string abilityName;
    9.     [TextArea(15, 20)]
    10.     public string abilityDescription;
    11.     public int abilityCooldown;
    12.     public int abilityEnergyCost;
    13.     public AbilityAttributes[] abilityAttributes;
    14.  
    15.     public void OnEnable()
    16.     {
    17.         for (int i = 0; i <= abilityAttributes.Length - 1; i++)
    18.         {
    19.             abilityAttributes [i].abilityObject = this;
    20.         }
    21.     }
    22. }
    23.  
    24. [System.Serializable]
    25. public class AbilityAttributes
    26. {
    27.     [System.Serializable]
    28.     public enum DecidingTarget
    29.     {
    30.         Selected,
    31.         Random
    32.     }
    33.  
    34.     [System.Serializable]
    35.     public enum TargetTypes
    36.     {
    37.         SingleAllyTarget,
    38.         MultiAllyTarget,
    39.         SingleEnemyTarget,
    40.         MultiEnemyTarget,
    41.         SelfTarget
    42.     }
    43.  
    44.     [System.Serializable]
    45.     public enum AbilityTypes
    46.     {
    47.         Damage,
    48.         Buff,
    49.         Debuff,
    50.         Heal
    51.     }
    52.  
    53.     public DecidingTarget decisionForTarget;
    54.     public TargetTypes targetType;
    55.     public AbilityTypes abilityType;
    56.     [Range(1, 99)]
    57.     public int numberOfTargets = 1;
    58.  
    59.     private ShipData abilityUserShipData;
    60.     private ShipData targetShipData;
    61.  
    62.     //Make it so this only appears if the ability type is damage via custom editor
    63.     public int damageNumber;
    64.  
    65.     [System.NonSerialized]
    66.     public Ability abilityObject;
    67.  
    68.     public void UseAbility(GameObject target, GameObject abilityUser)
    69.     {
    70.         targetShipData = target.GetComponent<ShipData> ();
    71.         abilityUserShipData = abilityUser.GetComponent<ShipData> ();
    72.  
    73.         switch (abilityType)
    74.         {
    75.         case AbilityTypes.Buff:
    76.             Debug.Log ("Buff has been done " + target.gameObject.name);
    77.             break;
    78.         case AbilityTypes.Damage:
    79.             Damage (targetShipData, abilityUserShipData);
    80.             break;
    81.             case AbilityTypes.Debuff:
    82.             Debug.Log ("Debuff");
    83.             break;
    84.             case AbilityTypes.Heal:
    85.             Debug.Log ("Heal");
    86.             break;
    87.         }
    88.     }
    89.  
    90.     private void Buff(ShipData target, ShipData abilityUser)
    91.     {
    92.        
    93.     }
    94.  
    95.     private void Damage(ShipData target, ShipData abilityUser)
    96.     {
    97.         target.TakeDamage (DamageCalculator (target, abilityUser));
    98.     }
    99.  
    100.     private void Debuff(ShipData target, ShipData abilityUser)
    101.     {
    102.  
    103.     }
    104.  
    105.     private void Heal(ShipData target, ShipData abilityUser)
    106.     {
    107.  
    108.     }
    109.  
    110.     private int DamageCalculator(ShipData t, ShipData au)
    111.     {
    112.         float critChance = Random.Range (0, 101);
    113.         float critDamageRange = Random.Range (1.5f, 2f);
    114.         float currentDmg = au.attackDmg;
    115.  
    116.         //Add in extra things such as crit etc at a later date;
    117.  
    118.         Debug.Log (currentDmg);
    119.         return Mathf.RoundToInt(currentDmg);
    120.     }
    121. }
    Any guidance will be super helpful even if it's just a tutorial and If I haven't explained myself clearly please just ask as I rewrote this several times and I'll be honest I might have confused myself.
     
  2. Ardenian

    Ardenian

    Joined:
    Dec 7, 2016
    Posts:
    313
    Your line 11
    base.OnInspectorGUI ();
    in your editor script strikes me as odd because it probably does the same thing as Editor.DrawDefaultInspector(). In my own words, you are basically drawing the default inspector and then add elements on top of it.

    The thing about custom editors is, you have to write the inspector for everything, every little element. In your particular case, a custom PropertyDrawer for the type
    AbilityAttributes
    is probably a lot easier to achieve with the same outcome.
     
    Bunny83 likes this.
  3. MajorSmurf

    MajorSmurf

    Joined:
    Feb 1, 2018
    Posts:
    16
    Aha I see. I did try with doing custom editor for
    AbilityAttributes
    but unity screamed at me and I'll be honest the main struggle was putting into words what I wanted into google. Hopefully this is what I was looking for and I guess I'll have to watch unity scream at me as I attempt to butcher this into working. Also the thing at line 11 is just cause it came with it by default when it generated so I just kept it.
     
  4. Ardenian

    Ardenian

    Joined:
    Dec 7, 2016
    Posts:
    313
    The difference between
    Editor
    and
    PropertyDrawer
    is crucial. A custom Editor defines your own logic on how the inspector displays a whole component, instead of using the default one, whereas a PropertyDrawer defines how an instance of a particular type is displayed in the inspector, as part of any object. Therefore, since you want to hide/show something of an instance of type
    AbilityAttributes
    in the inspector, a property drawer allows you to write this once.

    Think about if you used
    AbilityAttributes
    anywhere else, in another component type. You would then have to write a custom editor for that as well, to enable that hide/show for the instance(s) of type
    AbilityAttributes
    .

    If your integrated development environment generated that, such as Visual Studio, it is trying to help you by doing that, but that doesn't mean that in the Unity development environment, that's something you would want to have. It can be tricky at times, but you will learn it over time getting experience what is helpful and what isn't. I believe that in this case, your IDE generates that because your override is for a virtual method, not an abstract method, so deleting that is easier than to having to type it out or something like that.