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

Question Polymorphism in Unity

Discussion in 'Scripting' started by daniduckart, Mar 27, 2023.

  1. daniduckart

    daniduckart

    Joined:
    Feb 11, 2023
    Posts:
    11
    Okay, I'm not sure if I'm really understanding these concepts in order to finish up the Junior Programmer on Unity Learn particularly Polymorphism. I'm looking all over and it's about as clear as mud if I'm following any of it correctly.

    So I have an Enemy script (parent script), and this tells the enemy to go get the player and when the player is destroyed.

    I also have a child script for each different kind of script each with a set of behaviors but no overrides being used. <-- Does this actually show Polymorphism or is it more complex than that? I know I've got inheritance in the first one, but many of the tutorials on this make it seem like I need overrides to be doing it right.

    I've seen tutorials that have animals & cars and put the code in one script but I mostly just see console scripts and don't see how to make it functional. The scripts reference having audio, but not how to make the audio functional. (Even if I don't need to know how to do this right now I would love a link to a complete script so I can see how to make this functional).
     
  2. TzuriTeshuba

    TzuriTeshuba

    Joined:
    Aug 6, 2019
    Posts:
    185
    Not sure i followed. But there are times you could have inheritence without any overriding, although i usually do have overrides. Because Unity is "component oriented", i feel like a parent script with no children overriding anything may be best off as its own component script. but again, not necesarily.

    be aware that technically, if the child classes have different Awake/Update/OnTriggerEnter/etc (any of the unity callbacks) than each other, then there is a hidden "override" in there.
    If you post a snippet of the classes that you feel dont really leverage polymorphism, then post them (please use code tags) and ill take a look :)

    good job on learning the programming concept and questioning it btw, you'll be a great programmer.
     
    Last edited: Mar 28, 2023
  3. daniduckart

    daniduckart

    Joined:
    Feb 11, 2023
    Posts:
    11
    Thanks Tzuri! The main enemy just goes after the player. In this one if another enemy gets in the way the blue enemy will destroy them. I'm hoping this is enough for the class. I'm fine with learning more about polymorphism, but I feel like if I spend too much longer on this one thing I'm going to just burn out.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class BlueEnemy : Enemy
    6. {
    7.     void OnCollisionEnter(Collision other)
    8.     {
    9.         if (other.gameObject.tag == "Enemy")
    10.         {
    11.             Destroy(other.gameObject);
    12.         }
    13.     }
    14. }
    15.  
    16.  
     
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    Want to see an example of Polymorphism? I'll give a few.

    Polymorphism is a fairly simple concept. It's the concept that you can treat 2 similar objects in a similar way. Think like how a VCR/VHS player, a DVD Player, and a Youtube Stream all have play buttons. That play button is a polymorphic interface of a "video player". They all tell the video to play... but how the video plays is unique to each player. You don't care what actually happens inside though... you just care that they all have a play button.

    How does this translate to code?

    OK... here's a VERY SIMPLE example. List<T> and HashSet<T>:
    https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1?view=net-8.0

    https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.hashset-1?view=net-8.0

    They both have methods of:
    Add<T>(T item)
    Remove<T>(T item)
    Contains<T>(T item)
    int Count {get;}
    (as well as others)

    Because they both implement the interface ICollection<T>:
    https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.icollection-1?view=net-8.0

    You can interchangeably use both a List and a HashSet if you only care about these specific methods. Like so:
    Code (csharp):
    1. public void AddValuesLessThan(ICollection<int> coll, int maxvalue)
    2. {
    3.      for (int i = 0; i < maxvalue; i++) coll.Add(i);
    4. }
    You can pass anything that behaves like ICollection<int> to this method.

    This was an example of polymorphism via an interface.

    Another example...

    Collider:
    https://docs.unity3d.com/ScriptReference/Collider.html

    SphereCollider, BoxCollider, MeshCollider, all inherit from Collider. This means the shared members on the type Collider are usable interchangeably. And functions that take a Collider can take any type of Collider. This is why something like OnTriggerEnter can take in Collider and work with it.

    So if we say do:
    Code (csharp):
    1. void OnTriggerEnter(Collider coll)
    2. {
    3.     RaycastHit hit;
    4.     if (coll.Raycast(Camer.main.ScreenPointToRay(Input.mousePosition), out hit, 1000f))
    5.     {
    6.         //we reach here if the mouse is currently hovering over the Collider when it entered this trigger.
    7.     }
    8. }
    Both the acceptance of Collider as a parameter, and the calling of Raycast, are polymorphic. We don't care if it's a Sphere, or a Box, or whatever type of Collider it is. We just care that it entered our trigger, and that Raycast successfully returned true for the mouse position.

    ...

    What you should be doing is demonstrating how polymorphism facilitates be able to accessing objects of varying type through some shared interface (note that interface can refer to the interface like ICollection, or the interface that just is the members inherited from a parent type... both are interfaces in the sense that its the publicly facing members of a type).
     
    Bunny83, Ryiah and Kurt-Dekker like this.
  5. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,849
    As some of the videos in the course note, inheritance denotes an 'is a' relationship. Aka, BlueEnemy is a (or is an) Enemy.

    Though this isn't polymorphism. Polymorphism is treating derived types as through they were one of their base types. Eg, you can assign derived types into fields of their base types, and treat them as said base types.

    That said, important note, the examples in the programming course on inheritance should only be used to understand how these principles work. But they are poor examples on how to actually architect your game. Composition over inheritance, as they say. Make use of Unity's component structure, rather than trying to make deep trees of inheritance
     
    Bunny83 and Kurt-Dekker like this.
  6. Chubzdoomer

    Chubzdoomer

    Joined:
    Sep 27, 2014
    Posts:
    106
    lordofduct beat me to it, but I'll go ahead and post my response as well (which admittedly is not as good, but should hopefully still help):

    Polymorphism is when you manipulate children by using the base class's name. Since all children inherit from the base class, they in turn inherit/override its methods, etc.

    Let's say your base Enemy class has a Die() method, for example. Now let's say you have a BlueEnemy and RedEnemy, and they override that method so that they die in different ways (perhaps Blue merely falls over, whereas Red explodes).

    You could then kill all of them "polymorphically" by doing something like this:
    Code (CSharp):
    1. // Since Blue and Red both inherit from Enemy, this will grab them ALL and store them in an array
    2. Enemy[] allEnemies = FindObjectsOfType<Enemy>();
    3.  
    4. // Kill them all!
    5. foreach (Enemy currentEnemy in allEnemies)
    6.     currentEnemy.Die();
    Notice that nowhere in that code am I ever specifically handling a BlueEnemy or RedEnemy. I'm just grabbing anything that inherits from Enemy, and then calling the Die() method on that specific one (whether it be a Blue or Red enemy). If it's a Blue enemy, then it will perform its "fall over and die" actions, and if it's a Red enemy then it will explode.
     
    Last edited: Mar 28, 2023
    Bunny83 likes this.
  7. TzuriTeshuba

    TzuriTeshuba

    Joined:
    Aug 6, 2019
    Posts:
    185
    So inheritence makes sense here. This is an example of those "hidden overrides" i mentioned. the BlueEnemy has the same behaviour as its Parent (Enemy), it just has different behavior when it detects a collision with another enemy, as you said.

    Notice that most of the scripts that you write actually inherit from 'MonoBehaviour'. So in this case, BlueEnemy is a child of Enemy, which is a child of MonoBehavior. for this point, its probably easiest to think of the MonoBehaviour class as looking like such:

    Code (CSharp):
    1. public class MonoBehaviour{
    2. ...
    3.     protected virtual void OnCollisionEnter(){
    4.         //empty body
    5.     }
    6. ...
    7. }
    and technically your BlueEnemy has
    Code (CSharp):
    1. protected override void OnCollisionEnter(){
    2.     //blue enemy logic
    3. }
    you didnt have to actually write override here, because its a unity MonoBehaviour callback (where no parent of BlueEnemy already implemented the callback - ignore this comment, its not critical). Just the "Destroy other enemy" line doesnt really need to be in the blueEnemy script and doesnt justify the inheritence. however, One does not simply destroy and object. this is probably where the BlueEnemy would perform this.Atack(otherEnemy) and this.AnimatePunches() before the destroy call. hope it helps a little.

    stay motivated, definitely work on a game youre enjoying while learning.
     
    Bunny83 likes this.