Sponsored By

Oversharing About Overriding

The why and how of using the overriding directive in game programming

Zulu OneZero, Blogger

November 14, 2018

5 Min Read

The idea of a class and how objects, scripts or behaviors are implemented in Unity is pretty straightforward. Each object or type is a class and each script is a sub class of the MonoBehaviour class. So we are using classes all the time. Even if a script isn't a behavior, like a controller script or similar, the common pattern in a Unity project is to make an empty object and attach the script to it.

Classes are useful for separating code that is re-usable or for segregating data structures. Good Class usage is supposed to make your code easier to read if you have a sensible naming convention and self explanatory methods. I don't know if it really does help personally I find it hard to keep flipping between scripts and classes in different locations when writing and debugging. Sometimes I find it easier to have all behaviors in one big class and split up code into functions where possible.

I've published two games and written many more but I have never used a class that wasn't derived from standard MonoBehavoir. But lately I've changed things up a bit. I started working with the concept of Overriding. I'm not sure if it's any easier or better at this stage but I'll describe the general concept and you can try it for yourself (of course you've probably been doing this for years!).

But first let's go back to Classes.

Classes

A useful metaphor for a class that's been used many times is the Vehicle. The basic behavior for a vehicle is that it moves. Be it a bike, a car, a motorcycle, a truck, or a tank they can all be categorized as a type of “Vehicle”. Our basic variables for all Vehicles could be maxSpeed, acceleration, and direction. Our base class could also have a function called Move().

If we want to make a new Vehicle we can go:
Vehicle someVehicle = new Vehicle(); // and it get's all those parameters (maxSpeed, acceleration, direction) and can access the Move() function.

If we want to make a constructor to handle those default parameters on instantiation we can do something like this:


class Vehicle {
       	float maxSpeed, acceleration;
       	Vector3 direction;
	string makeNmodel;  // Added this one to so we could have a name in there

	//The constructor
	Vehicle(float _maxSpeed, float _acceleration, Vector2 _direction, string _makeNmodel)	
       	{
		maxSpeed = _maxSpeed; 
		acceleration = _acceleration; 
		direction = _direction; 
		makeNmodel = _makeNmodel;       
	}

	// Basic move function
	public virtual void Move()   // is this the fun bit?
	{	        
        	transform.Translate(direction * acceleration * Time.deltaTime);
	}
} 

Using the constructor I can make a new sportsCar instance of a Vehicle object and initialize the base values immediately:
Vehicle sportsCar = new Vehicle(210, 21, Vector2.right, "MazdaRX7");

Then if I upgrade my RX7 with a new fuel injector I can access those values like this:
sportsCar.MaxSpeed = 240;

And of course I can drive it round now too:
SportsCar.Move();

Now I can keep going building automobiles with different variables that represent their base characteristics - fill a whole garage if I want.
But what if I made an assumption about my Vehicle() class that they all had wheels and I wanted to add a plane?
I could write the plane a new class to handle flying or I could keep the sanctity of the Vehicle concept intact and just override the Move() function to include a bit of up and down action.

Overriding

What we can do is override the Move() function in the Vehicle class with an Airplane Move() function.
What we are doing here is also called up Upcasting. We are effectively overriding a Parent method in a Child Class.
The Vehicle class and the new Airplane class form part of an Inheritance Hierarchy.

Vehicle -> Airplane (Parent -> Child)

This is how to do it.
To make a Parent method able to be overridden use the 'virtual' keyword on it's method and the 'override' keyword in the child method.

The parent Vehicle class has:
public virtual void Move()
// The direction variable is a Vector2 as it moves around on a flat surface using wheels

The child Airplane class has:
public override void Move()
// The direction variable is a Vector3 which adds the up and down movement using wings

For example the Airplane Class


using UnityEngine;
using System.Collections;

public class Airplane : Vehicle  // the Airplane class inherits from the Vehicle class
{
    public Airplane ()
    {
        Vector3 flightDirection;
    }
    
    //This method overrides the virtual method in the parent
    public override void Move()
    {
        transform.Translate(flightDirection * acceleration * Time.deltaTime);   
    }

}

You can also add the Parent method into the new Class by using the base keyword but unfortunately this is where my example above falls down. You would never need to keep the 2D movement and add the 3D movement on a vehicle. Unless maybe you were giving the RX7 a jetpack and wings - it could be that kind of game.

If you have to do this the syntax is to declare the function in the new Child class using "base" to indicate that the parent(base) method is being used:
base.Move();

I've put links at the bottom of the post for more info here if you want it.

But why use a custom class and the override feature? One good reason is when you don't need the stuff that you inherit from MonoBehaviour.
You could define your own class when you don't need functions like Update(), Awake() and similar things like FixedUpdate(), OnCollision(), or UI behaviors.

You could define classes when they are not game objects like in-game information, a score multiplier, number of bullets left, etc. or you could use them when you have a common data structure that is shared by several objects like in our Vehicle example but you certainly don't have to. One of my favorite things about old programming and scripting philosophy is the concept 'that there is more than one way of doing it'. You don't have to write perfect code that follows a pattern or schema. It just has to work (mostly) and be understandable (at least to you) next time you have to look at it.

https://unity3d.com/learn/tutorials/topics/scripting/overriding
https://answers.unity.com/questions/15448/when-do-we-need-to-use-class.html
https://unity3d.com/learn/tutorials/topics/scripting/classes
https://www.studica.com/blog/unity-tutorial-classes
https://stackoverflow.com/questions/36539708/c-sharp-in-unity-3d-2d-am-i-required-to-use-classes-for-every-script
https://www.reddit.com/r/Unity3D/comments/32c9nj/how_to_create_custom_classesobjects_in_unity/

Read more about:

Blogs

About the Author(s)

Daily news, dev blogs, and stories from Game Developer straight to your inbox

You May Also Like