Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Inheritance Issue

Discussion in 'Scripting' started by squidward572, Feb 16, 2020.

  1. squidward572

    squidward572

    Joined:
    Nov 30, 2019
    Posts:
    4
    Hello everyone, I have an enemy which can shoot, it's shots must have speed = enemy anger. Shots inheritate enemy class, but anger variable always equals zero. Where I did wrong?
    Shot is attached to Enemy Serialize Field.
    Code (CSharp):
    1.  
    2. [System.Serializable]
    3.  
    4. public class Enemy : MonoBehaviour
    5. {
    6. //if I assign value to Anger here, it works only with this value
    7. protected int  Anger;
    8. private void OnTriggerEnter2D(Collider2D collision)
    9.     {
    10.           case "Shot":
    11.                 Anger++;
    12.                break;
    13. }
    14. }
    Code (CSharp):
    1.  
    2. public class Shot : Enemy
    3. {
    4.  
    5. void Update ()
    6. {
    7.  transform.Translate(Vector3.down * Anger * Time.deltaTime);
    8. }
    9. }
    10.  
     
    Last edited: Feb 16, 2020
  2. diXime

    diXime

    Joined:
    Oct 2, 2018
    Posts:
    162
    Hello,
    there is more than inheritance issues here.
    What sort of switch statement is this?
    Code (CSharp):
    1. private void OnTriggerEnter2D(Collider2D collision)
    2.     {
    3.           case "Shot":
    4.                 Anger++;
    5.                break;
    6. }
    Well, I guess you cleaned it up because it wouldn't compile.
    For the transform.Translate I'm guessing this is for testing but this won't speed up shooting.

    I think Enemy would inherit from shot and not the opposite. (ask yourself this : what contains what?). But I'm not sure it wouldn't work that way, it should be fine. It just feels weird to me.

    I think your issue may come from the protected keyword, as you can't modify Anger from within the base class, only derived ones (so Shot in your example):
    Protected Keyword reference
     
  3. squidward572

    squidward572

    Joined:
    Nov 30, 2019
    Posts:
    4
    yes, I cleaned code. I tried public and protected var. enemy contains shot, if I write Anger var in Shot script , it recognizes it, but doesn't adjust value.
     
  4. csofranz

    csofranz

    Joined:
    Apr 29, 2017
    Posts:
    1,556
    I'm not entirely sure (apologies if I'm wrong) but it seems that you may not yet have completely understood how inheritance works. Why does shot inherit from enemy (the assumption here is eneme is an NPC, and shot is something that enemies and allies shoot at each other)?

    It would usually make sense for an enemy to spawn a shot, and if this is true, this is is not what inheritance is about. Spawning an object will not make it inherit from the spawner even if it inherits from it's class.

    So, how do you spawn (i.e. create in-game) a shot? Are shots spawned by enemies, and how do you set Anger in-game? Also, that partial switch statement didn't help, as you should only post code that would at least compile.
     
  5. squidward572

    squidward572

    Joined:
    Nov 30, 2019
    Posts:
    4
    ok, , if u can, please give a tip how shoot can inherit value from enemy?
    simple GetComponent thing doesn't makes it right .

    Anger is just variable inside enemy class and stacks if enemy gets hurt, then it instantiates shot, and shot must inherit some values from enemy, which spawned it.
     
  6. Laperen

    Laperen

    Joined:
    Feb 1, 2016
    Posts:
    1,065
    You'll need to do your due diligence to read up and understand what inheritance is for. We can tell you conceptually, shot should not be inheriting from enemy at all, but if you don't understand inheritance in the first place, we really can't do much else. If reading is too much of a hassle, even youtube videos on the subject will suffice.

    What i don't understand from a design perspective, is why shot needs the anger value from enemy at all.
     
  7. squidward572

    squidward572

    Joined:
    Nov 30, 2019
    Posts:
    4

    Anger is just variable inside enemy class and stacks if enemy gets hurt. Enemy's Anger is speed multiplier of it's shot, shot must use value from parent Enemy, Anger must be individual to every enemy, and shot must take anger only from parent Enemy.

    Shots instantiate by [SerializeField] GameObject Shot; in enemy script;

    how I can get value from individual parent to it's individual child? if i make Anger variable public and access it by Enemy = FindObjectOfType<Enemy>(); in shot script , it becomes overall, and starting a mess.
     
  8. csofranz

    csofranz

    Joined:
    Apr 29, 2017
    Posts:
    1,556
    Maybe that is where the confusion comes from. You don’t inherit values, but you inherit the variable. You still need to set the value, it’s not automatically passed to the child. It makes very little sense to have shot defined as a child of enemy simply because they both need a variable “anger”. You may want to re-read a tutorial on object-oriented programming. That will not only clear things up a bit, but also may give you some good ideas how to design your objects.
     
    diXime likes this.
  9. diXime

    diXime

    Joined:
    Oct 2, 2018
    Posts:
    162
    Your last sentence makes sense. Now imagine what you're asking the program to do (it usually is really bad at guessing games).
    When a I, the shot, hits an enemy, I have to modify Anger.
    I have Anger (I inherit from enemy), so my Anger gets 1 more.

    To add Anger to the ennemy, you have to specify which one. On your collision, you may find the EnemyComponent. So something like, (not tested)
    Code (CSharp):
    1. private void OnTriggerEnter2D(Collider2D collision)
    2.     {
    3.         collision.gameObject.GetComponent<Ennemy>().Anger++;
    4.     }

    To understand your problem, the key sentence from csofranz is "you don't inherit values, you inherit the variable".

    If your shot contains an entire enemy, you'd add a bunch of variables to your shots that you don't need. Hell, it will even get MonoBehaviour and Anger.

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3.  
    4.  
    5. [ExecuteInEditMode]
    6. public class Ennemy : MonoBehaviour
    7. {
    8.     public int Anger;
    9.  
    10.     private void OnEnable()
    11.     {
    12.         // 1 // Your shot inherit from Ennemy, so it will have gameObject and everything else.
    13.         this.gameObject.name = "I'm an ennemy!";
    14.         //  I edit here ennemy name, but Shot won't be able to find it, because you've passed its variables and nothing else,
    15.         // Shot object will have a gameObject but it will remain null, even if I've modified Ennemy gameObject.
    16.  
    17.  
    18.  
    19.         // 2 // Instead, let's create a Shot object into Ennemy
    20.  
    21.         Shot shot = new Shot();
    22.         // creates an ennemy : your "shot" has an Anger variable. Why would a shot have Anger?
    23.         shot.SpawnShot(); // shot returns 0
    24.         shot.Anger++; // This individual shot has values you can work with
    25.         shot.SpawnShot(); // shot returns 1
    26.         // So you can pass on values, but you need to create a Shot Object (so the other way around)
    27.     }
    28.  
    29. }
    30. public class Shot : Ennemy
    31. {
    32.     public string shotName = "shot";
    33.     public void SpawnShot()
    34.     {
    35.         // 1 // Shot has a GameObject thanks to MonoBehaviour from Ennemy
    36.         // But it will remain null even if i've changed the Ennemy's
    37.    
    38.   try
    39.         {
    40.             if (gameObject)
    41.             {
    42.                 Debug.Log(gameObject.name); // exists but will never get here, because it has the variable but not the data
    43.             }
    44.         }
    45.         catch (NullReferenceException)
    46.         {
    47.             Debug.Log(shotName + " returns " + Anger); // Your shot is its own ennemy+shot object, with its own anger and shotname
    48.         }
    49.  
    50.  
    51.     }
    52.  
    53. }
    54.  
    So,
    Inheritance here seems unnecessary. You don't need every Enemy variables into a Shot object. Instead, all you need is making a Shot Object, but it would be the "Shot" Anger inherited from Ennemy. Not necessary at all. That's why I said it could work but it feels weird. You only need a Shot gameObject contained into Ennemy, and not a Shot containing an Ennemy.
    Now if it's the one that shoots that needs to have its Anger grown, your shot does need a reference to the shooting one. But "being" an ennemy is not "I know who launched me".
     
    Last edited: Feb 19, 2020