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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Convert Parent class to Child class from a method

Discussion in 'Scripting' started by unity_8I_suMy7c9iU0g, Sep 25, 2022.

  1. unity_8I_suMy7c9iU0g

    unity_8I_suMy7c9iU0g

    Joined:
    May 29, 2020
    Posts:
    22
    I have a class named Skills
    Code (CSharp):
    1. public class Skills : ScriptableObject
    2. {
    3.     public string type;
    4. }
    and it has a child AttackSkill with some new variables (like damage and etc.)

    So i want to get to those variables in a script

    Code (CSharp):
    1. public void SkillExec(Skills skill)
    2.     {
    3.         if (skill.type == "Attack")
    4.         {
    5.             //Error here!
    6.             SkillAttack(skill);
    7.         }
    8.     }
    9.  
    10.     public void SkillAttack(AttackSkill skill)
    11.     {
    12.         //code here
    13.     }
    But it gives an error, because SkillExec() uses parent Skills class (this is so method can get different types of skills)

    At first i also wanted to just use parent Skills type, but as i understood you can't get children's variables with a parent type

    How can i make this code work? Am i thinking the wrong way?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,780
    I think all you need is a cast to the child type, which will fail if it isn't that type.

    The above is not a good way to do things however. For one, strings allow you to make typos. For two, you need custom code in SkillExec() to handle each different skill... that's gonna get totally out of control.

    Instead you may wish to consider interfaces.

    Using Interfaces in Unity3D:

    https://forum.unity.com/threads/how...rereceiver-error-message.920801/#post-6028457

    https://forum.unity.com/threads/manager-classes.965609/#post-6286820

    Check Youtube for other tutorials about interfaces and working in Unity3D. It's a pretty powerful combination.
     
  3. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,123
    It would be a better idea to move SkillExec to the base class as an abstract method. This would force all derived classes to add their own implementation.

    Code (CSharp):
    1. public abstract class Skill : ScriptableObject
    2. {
    3.     public abstract void Execute();
    4. }
    5.  
    6. public sealed class AttackSkill : Skill
    7. {
    8.     public override void Exexcute()
    9.     {
    10.         // attack skill specific code here
    11.     }
    12. }
     
    Bunny83 and Kurt-Dekker like this.
  4. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,123
    To answer your original question: you can usually use your IDE to fix errors like these automatically!

    When you mouseover code in your IDE that has a red underline, you can see it say "Show potential fixes".

    mouseover.png

    If you press the keyboard shortcut or select Quick Actions from the context menu you will see some suggested fixes.

    quick_actions.png

    In this case the "Add explicit cast" suggestion will resolve the issue.

    Add explicit cast.png

    In addition to the explicit cast - which throws an error if the object can not be cast to AttackSkill - there are various other ways to perform casting:

    As cast:
    Code (CSharp):
    1. public void SkillExec(Skills skill)
    2. {
    3.     AttackSkill attackSkill = skill as AttackSkill; // if casting fails then null is assigned to attackSkill
    4.     if(attackSkill != null)
    5.     {
    6.         SkillAttack(attackSkill);
    7.     }
    Is cast:
    Code (CSharp):
    1. public void SkillExec(Skills skill)
    2. {
    3.     if(skill is AttackSkill attackSkill) // if casting fails then 'skill is AttackSkill' returns false and nothing is assigned to attackSkill
    4.     {
    5.         SkillAttack(attackSkill);
    6.     }
     

    Attached Files:

    Bunny83 likes this.
  5. unity_8I_suMy7c9iU0g

    unity_8I_suMy7c9iU0g

    Joined:
    May 29, 2020
    Posts:
    22
    Thanks for the reply, are you suggesting to make an Interface instead of a parent Skill class and then modify SkillExec as needed?

    Also, how can i replace the string variables to not make typos? Do i use enums?
     
  6. unity_8I_suMy7c9iU0g

    unity_8I_suMy7c9iU0g

    Joined:
    May 29, 2020
    Posts:
    22
    This looks great for what i want, thanks.

    By the way, why did you seal the AttackSkill class?
     
  7. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,123
    Sealing classes from which you don't need to derive can improve performance for free, so I think it's a good idea to seal everything by default in your own code.

    You can always always just unseal them later if the need does arise to introduce additional derived classes.
     
    Last edited: Sep 28, 2022
    unity_8I_suMy7c9iU0g likes this.
  8. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,198
    I'd just remove the skill string. If you want a method external to Skill that takes different skill types and does things with them, you could:

    Code (csharp):
    1.  
    2. public void SkillExec(Skills skill)
    3.     {
    4.         if (skill is AttackSkill attackSkill)
    5.         {
    6.             SkillAttack(attackSkill);
    7.         }
    8.         // etc. for other types
    9.     }
    10.  
    11.     public void SkillAttack(AttackSkill skill)
    12.     {
    13.         //code here
    14.     }
    15.  
    But that's probably not the best design, the inheritance things suggested above might be better. Or not, depends very much on what you're doing.