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

GameManager inheritance

Discussion in 'Scripting' started by whitedrow, Apr 18, 2021.

  1. whitedrow

    whitedrow

    Joined:
    Mar 31, 2008
    Posts:
    15
    Hi,

    i've created a scene with a GameManager object attached with a GameManager.cs with some methods like GameStart(), GamePause(), GameResume, GameEnd() and so on.

    Everything is working fine and now I want to use this as a template for other levels.


    To do this I duplicated the complete scene which is called "Level1" and renamed it to "Level2".
    I also created a new script, called "Level2.cs" which inherits all from "GameManager.cs" and in "Level2.cs" i did the adjustments for level 2.

    BUT:
    Since I use in other scripts this way of communication with the "Master" GameManager.cs:

    Code (CSharp):
    1. private void Awake()
    2.     {
    3.         GameManager = GameObject.Find("GameManager");
    4.    GameManager.GetComponent<GameManager>().GameStart();
    5.     }
    My game is not working anymore because the component is now called "Level2.cs".

    So I need a way of doing a call like
    Code (CSharp):
    1. GameManager.GetComponent<"Level2">().GameStart();

    But i cant figure out how to do this.
    Is there any way to solve this problem?
    Do I missunderstand the inheritance concept?
    Do I have to take another approach?

    Any help is welcome.
     
  2. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    Your first method should still be working. You can even shorten it to this:
    Code (CSharp):
    1. private void Awake() {
    2.   GameManager gm = FindObjectOfType<GameManager>();
    3.   gm.GameStart();
    4. }
    As long as your
    Level2
    script inherits from
    GameManager
    , you can find it by searching for
    GameManager
    .
     
  3. MDADigital

    MDADigital

    Joined:
    Apr 18, 2020
    Posts:
    2,198
    You probably want a more data driven and component driven approach to this
     
    Meltdown likes this.
  4. whitedrow

    whitedrow

    Joined:
    Mar 31, 2008
    Posts:
    15
    @Vryken
    I've wrote
    Code (CSharp):
    1. public class Level2 : GameManager
    2. {
    3. }
    and then attached this script as a component. The IDE complains that no strings are allowed

    (in screenshot there is the old name "GameManagerLevel001" - sorry about that)
     

    Attached Files:

  5. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    Can you please post the entire error message about "no strings allowed"? That doesn't make much sense to me given the context here.

    In your screenshot, it looks like you're using both
    GameManager
    -type components at the same time? That would cause issues when you try to
    Find
    it, since Unity can't know if you mean to find the
    GameManager
    or
    Level2
    component.

    A different approach might also be needed here, because a "GameManager" is usually a singleton responsible for handling general events & data shared across the entire game, If you need more than one "GameManager" script, then chances are that script shouldn't be a "GameManager".

    With inheritance, always remember the "is a" rule before extending objects:
    Does it make sense to say "this object is a type of that object"?
    • A Car is a Vehicle.
    • A Sedan is a Car.
    • A Flower is a Plant.
    • A Rose is a Flower.
    "A Level2 is a GameManager" doesn't sound too right, so perhaps "Level2" shouldn't be concerned with "game management" logic.
    You might want to try splitting your "game management" logic from your "level" logic.
     
  6. Magnesium

    Magnesium

    Joined:
    Sep 14, 2014
    Posts:
    178
    Hello,

    Inheritance is rarely a good idea in development. It happens but this doesn't look like a good case for it. You could put you game manager on a object that isn't destroyed on scene change then have scene scripts that reference it.
     
  7. whitedrow

    whitedrow

    Joined:
    Mar 31, 2008
    Posts:
    15
    @Vryken Maybe my idea of having a big class with the game logic and some minor classes with adapted Methods is wrong - so thank you four your thoughts with the is a-rule.

    But my main question is still left: How to use variables or string in GetComponent
     

    Attached Files:

  8. Magnesium

    Magnesium

    Joined:
    Sep 14, 2014
    Posts:
    178
    With parenthesis GetComponent("type").

    Which you shouldn't do, because it will make your code prone to bugs.
     
    MDADigital and Vryken like this.
  9. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    What @Magnesium said. You technically can use string names to get components like this:
    Code (CSharp):
    1. GameManager gm = GetComponent("GameManager") as GameManager;
    But this is really prone to bugs. If you change the name of your script for instance, you need to remember to change the name in every single
    GetComponent
    call as well.

    You can still use an abstract class or an interface that all of your "level" scripts can inherit, and then use the abstract-type with the
    GetComponent
    call to accomplish what you want to do instead.

    Abstract class example:
    Code (CSharp):
    1. public abstract class Level : MonoBehaviour {
    2.   public abstract void DoSomthing();
    3. }
    4.  
    5. public class Level1 : Level {
    6.   public override void DoSomething() {
    7.     Debug.Log("I am Level1");
    8.   }
    9. }
    10.  
    11. public class Level2 : Level {
    12.   public override void DoSomething() {
    13.     Debug.Log("I am Level2");
    14.   }
    15. }
    16.  
    17. public class Level3 : Level {
    18.   public override void DoSomething() {
    19.     Debug.Log("I am Level3");
    20.   }
    21. }
    22.  
    23. public class AnotherClass : MonoBehaviour {
    24.   private void Awake() {
    25.     //Level1, Level2, Level3, and anything else inheriting the Level class can all be assigned into this Level variable.
    26.     //This logic doesn't need to care about which specific Level-type component exists in the scene.
    27.     Level level = FindObjectOfType<Level>();
    28.     level.DoSomething();
    29.   }
    30. }
    Interface example:
    Code (CSharp):
    1. public interface ILevel {
    2.   void DoSomthing();
    3. }
    4.  
    5. public class Level1 : MonoBehaviour, ILevel {
    6.   public override void DoSomething() {
    7.     Debug.Log("I am Level1");
    8.   }
    9. }
    10.  
    11. public class Level2 : MonoBehaviour, ILevel {
    12.   public override void DoSomething() {
    13.     Debug.Log("I am Level2");
    14.   }
    15. }
    16.  
    17. public class Level3 : MonoBehaviour, ILevel {
    18.   public override void DoSomething() {
    19.     Debug.Log("I am Level3");
    20.   }
    21. }
    22.  
    23. public class AnotherClass : MonoBehaviour {
    24.   private void Awake() {
    25.     //Level1, Level2, Level3, and anything else implementing the ILevel interface can all be assigned into this ILevel variable.
    26.     //This logic doesn't need to care about which specific ILevel-type component exists in the scene.
    27.     ILevel level = FindObjectOfType<ILevel>();
    28.     level.DoSomething();
    29.   }
    30. }
     
  10. Magnesium

    Magnesium

    Joined:
    Sep 14, 2014
    Posts:
    178
    I don't think you misunderstood, i think the basic programming tutorials explain the concept poorly. They explain that a class is like representing something from the real world, like you have a class animal, then you have a class cat that extends animal.

    In reality, classes are more ways to organize functionalities. While there are uses to inheritance, most of the time you want to compartmentalize your classes with as little functionalities as possible.

    So here, you have a game manager class that... well, manages the game. Then you have levels. Those are separate things. Instead of making levels that extend the game manager, make your levels use your game manager. This will come with several advantages. The first most obvious ones is that you will be able to keep the same game manager object through levels with the Don't destroy on load function, so you will be able to keep the game state between scenes.

    Then, you probably wont need a specific component for each of your scenes, chances are most of them are going to have exactly the same code since Unity relies on individual object behaviors.

    But your biggest problem is going to be when you realize that you have to do a major change in your main class and have to adapt tens of classes that derive from it.
     
    Ian094 and MDADigital like this.
  11. whitedrow

    whitedrow

    Joined:
    Mar 31, 2008
    Posts:
    15
    Thank you all for your answers.
    I have not yet found THE ONE SOLUTION, but I know now in any case that I have to think again fundamentally about the structure of my game.

    I will probably try to get on with only one GameManager and without much inheritance.

    So again, thanks for all your input - I really appreciate it.