Interface Polymorphism

Ben Mercier
4 min readJul 19, 2021

Objective: When an object’s OnTriggerEnter() event is raised, reduce it’s health based on the specific object it came in contact with.

One of the primary pillars of OOP, polymorphism, allows an object to implement a particular behavior while allowing the performance of that behavior to vary between objects. For example, dogs and cats are both animals which can speak, but when speaking, dogs will bark while cats meow. Interfaces are a great way to accomplish these behaviors across objects and create cleaner, more manageable code.

In my scene I currently have three objects which each interact with one another. An enemy, a harpoon, and a player to fire the harpoon towards the approaching enemy. When hit by the harpoon, the enemy needs to be able to reduce it’s health by the appropriate damage amount of that specific harpoon object.

Enemy, Harpoon, & Player

To check for collisions on my enemy, I’m using OnTriggerEnter() and have the necessary collider and rigidbody components on each enemy and harpoon object. Without the use of interfaces, a simple, yet limited, way to verify when the enemy is hit would be through the use of tags. By tagging the harpoon, an if() statement comparing the tag can be quickly used within the enemy’s OnTriggerEnter() method to check for a collision:

Enemy OnTriggerEnter() method checking for the “Harpoon” tag

The harpoon object contains a Harpoon script with a public DamageAmount property which returns the amount of damage it causes. That damage amount can then be passed into the enemy’s DamageReceived() method to reduce its health.

DamageAmount property on the harpoon object

This implementation works well enough for a single object, but once more objects and features are added, then any classes needing to check for collisions can quickly become bloated, inefficient, and unmanageable:

Like the Energizer bunny, it will just keep going and going

This is where interfaces can really shine.

First, some key features of interfaces to acknowledge:

  • interfaces may only contain methods and properties
  • methods and properties cannot be implemented within the interface
  • any class inheriting an interface MUST implement each of its methods and/or properties
  • classes can inherit more than one interface

To start, I created a new script named IDamager to signify it’s an interface, and like with the original Harpoon script, the only interface member is a float property named DamageAmount.

Note: all methods and properties in an interface are public

Back in the Harpoon script, the IDamager interface is then inherited by the class. Once inherited, an error will appear until each member of the interface is implemented (i.e. the DamageAmount property).

To quickly implement the interface, right click the error, go to “Quick Actions and Refactorings…”, and then select “Implement interface”. The necessary methods and/or properties will then be automatically added to the class and ready to use.

With the public DamageAmount property, any class implementing the IDamager interface will have that variable available to access. Now instead of the enemy’s OnTriggerEnter() method having to compare multiple tags, it only cares whether the object it collided with implements the IDamager interface. If so, then that object’s respective DamageAmount can be passed into the enemy’s DamageReceived() method.

Much cleaner!

Just like dogs and cats having a base speak behavior that they individually perform, these harpoons and any other necessary objects can have their own DamageAmount without relying on an endless stream of if()…else if()… statements.

Cheers!

--

--

Ben Mercier

I’m an emergent software developer with a longtime love of games and a growing understanding of how to actually build them.