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

Virtual functions?

Discussion in 'Scripting' started by hedgeh0g, Nov 9, 2016.

  1. hedgeh0g

    hedgeh0g

    Joined:
    Jul 18, 2014
    Posts:
    102
    Hello folks,

    I have several characters, each of them has a script which holds their stats (speed, hp, w/e). All of them, have in common a script which basically holds the input.

    This "InputScript" needs to retrieve a particular value (a stat) from the "CharacterAlphaStats" script. Normally in Unity with a gameobject that holds "InputScript" and "CharacterAlphaStats" I would do:
    Code (CSharp):
    1. characteralphascript = gameObject.GetComponent<CharacterAlphaScript>();
    However, if the character is not "Alpha" the code above won't work, because the character "Beta" will have "CharacterBetaStats".

    In C++ the solution is straight forward by using virtual functions, so, how can I retrieve these stats in a more "object-oriented" way?

    Thanks in advance.
     
  2. vothka

    vothka

    Joined:
    Mar 27, 2015
    Posts:
    59
    c# has virtual methods exactly like c++

    Code (CSharp):
    1.  
    2. public abstract class ACharacterStats {
    3.   /*all your stuff that applies to everyCharacter   (e.g.  Health*/
    4.   public abstract int DoStuff();  //abstract equals pure virtual in c++
    5.   public virtual void DoOtherStuff() { } //virtual method
    6. }
    7.  
    8. public class CharacterAlphaStats{
    9.   public CharacterAlphaStats() {}
    10. //must be implemented because it is abstract in its baseclass
    11.   public override int DoStuff() { return 0; }
    12.  
    13.   //CAN be overwritten but does not have to
    14.   public override void DoOtherStuff() {
    15.     base.DoOtherStuff() //Call Method in Baseclass like this in c#
    16.     //Do the additional stuff
    17.    }
    18. }
    19.  
    20.  
    21. //call them now instead of:
    22. characteralphascript = gameObject.GetComponent<CharacterAlphaStats>();
    23.  
    24. like:
    25.  
    26. characterscript = gameObject.GetComponent<ACharacterStats>()
    27. characterscript.DoStuff();
    28.  

    edit:

    to pass Parameters through the Constructor you can use the ": base" keyword aswell.

    eg.

    Code (CSharp):
    1. public class A {
    2. private string Name;
    3. public A(string _name)
    4.     Name = _name;
    5. }
    6.  
    7. public class B : A {
    8.     public B(string _name) : base(_name) {
    9.     //Do some B stuff
    10.     }
    11. }
     
    Last edited: Nov 9, 2016
    NMPT and LiterallyJeff like this.
  3. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,802
    Don't forget to include the base class in the signature:
    Code (CSharp):
    1. public class CharacterAlphaStats : ACharacterStats {
     
    vothka likes this.
  4. vothka

    vothka

    Joined:
    Mar 27, 2015
    Posts:
    59
    Oh, thanks for pointing out - guess that happens if you try to write code directly into a forum lol ;)
     
    LiterallyJeff likes this.
  5. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Also just in case you meant to do this. Does Alpha and Beta have different "Kinds" of stats. say Alpha has 2 ints and a float. but Beta has 2 ints and 2 floats and a string? Or do they both have the same kinds of stats.. say 2 ints and a float and they each have diffeent values in those variables?

    If its the first case , then read all of the above. If its the second case, then both alpha and Beta can have your AlphaStatsScript, they just need to have it attached to different GameObjects. And depending on which gameObject you call with;
    Code (CSharp):
    1. gameObject.GetComponent<CharacterAlphaScript>()
    will get you the right person.
     
  6. hedgeh0g

    hedgeh0g

    Joined:
    Jul 18, 2014
    Posts:
    102
    That's exactly what I was looking for, thanks for answers. :)

    I'm used to code games in C++ with my own game engine, but I'm a little bit noobie with C# and Unity. :)
     
  7. hedgeh0g

    hedgeh0g

    Joined:
    Jul 18, 2014
    Posts:
    102
    Hello again, uhm

    I'm having another issue: I have created a script with the abstract signature, as vothka suggested, and another script CharacterAlphaStats which inherits from the base CharacterStats. However:

    - I cannot attach the abstract CharacterStats script to a gameobject because Unity says "the script class can't be abstract"
    - I cannot attach either CharacterAlphaStats because "classes cannot have multiple classes", as itmust inherit from both CharacterStats and MonoBehaviour

    Here is the code:

    CharacterStats:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public abstract class CharacterStats : MonoBehaviour {
    5.  
    6.     // Pure Virtual in C++
    7.     public abstract float GetSpeed ();
    8.  
    9.     // Use this for initialization
    10.     void Start () {
    11.    
    12.     }
    13.    
    14.     // Update is called once per frame
    15.     void Update () {
    16.    
    17.     }
    18. }
    19.  
    CharacterAlphaStats

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class CharacterAlphaStats : CharacterStats, MonoBehaviour{
    5.  
    6.     private float speed = 2.0f;
    7.  
    8.     public override float GetSpeed ()
    9.     {
    10.         return speed;
    11.     }
    12.  
    13.     // Use this for initialization
    14.     void Start () {
    15.    
    16.     }
    17.    
    18.     // Update is called once per frame
    19.     void Update () {
    20.    
    21.     }
    22. }
    23.  
    What am I doing wrong?
     
  8. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,802
    Abstract classes cannot be instantiated. If you want to make a component using CharacterStats, it shouldn't be abstract. Abstract classes are used only as a base, like the framework or blueprint for a functional class to inherit from.

    If you want CharacterStats to be added as a component, make it a normal or virtual class with virtual functions.

    You don't need CharacterAlphaStats to inherit from MonoBehaviour, because CharacterStats already does. Just inheriting from CharacterStats makes it a MonoBehaviour.

    Also, classes can only inherit from one class in C#.
     
    Last edited: Nov 10, 2016
  9. Kalladystine

    Kalladystine

    Joined:
    Jan 12, 2015
    Posts:
    227
    @hedgeh0g if you're familiar with C++ and (general knowledge) of making games, I'd suggest checking some pure C# tutorials. Normally people say to go to Learn section, and that is also good, but you might find it a little slow (they're aimed mostly at people new to coding, so you won't find actual advanced topics there for the most part).
    A very basic comparison is here on MSDN.
    This is also nice as a reference point - .Net book zero, even if it's a little dated (since Unity isn't up to date with C# that shouldn't matter much).

    Once you get the differences (at least most important ones), then go to Unity. It should be much easier, as you'll be learning one thing at a time.

    Adding to what @jeffreyschoch said about single class inheritance:
    You might want to check how Interfaces in C# work. While they can't provide the implementation, they're the closest to multiple inheritance for a single class. One caveat with them, is that Unity has a magic null check that does not encompass interfaces. Useful to keep in mind.
    With that in mind, composition of individual MonoBehaviour-inheriting classes on a single GameObject is the standard way of working in Unity (quick sample to what it's about).
     
  10. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    The easiest answer in C# is interfaces. Inheritance is for when you need to share functionality. Interfaces are for when you want to share API.