Unity Extension Methods

Do you ever find yourself writing a method that you feel could or should be part of an existing Unity component?  Have you ever wished the Vector3 class had a few more methods?  You should should be using extension methods!

Getting Started

Direction Example

We’ve all needed to get the direction between two points.  Generally we subtract one from the other, then normalize the result.

Sometimes we mix them up, put them in the wrong order, and get the opposite direction.

Because this behaviour is needed across a bunch of classes, it doesn’t make sense to add a GetDirection() method in each class needing to calculate it.

Without Extensions – Helpers

One option that I’ve done plenty of time myself is to create a set of “helper” classes that I can call like this.

While it’s functional, it’s in some mytichical “helper” class that will inevitably turn into a bit of a mess.  When new people join the team, they may not realize this helper existed, and they may even write their own version of it.

With Extensions – Better

Now I use extension methods instead!

Let’s see how the previous example looks as an extension method.


Here, you see that it looks like the Transform class has a DirectionTo method which takes another transform as a parameter and returns the direction as a Vector3.

Extension methods are usually pretty short and simple, though there’s no technical requirement for them to be so.

The biggest difference between a regular method and an extension is how you call them. Extension methods appear to be methods on an existing class (typically something thats sealed or you don’t want to inherit from).

Benefits

  • Discoverability – You can see them with Intellisense. This makes it easy to see what extra functionality you’ve provided for the classes.
  • Cleanliness – You can avoid a bunch of “SomethingHelper.cs” classes.
  • Reusability – Typically your extension methods are simple and can be re-used across all of your projects.

How do I write an extension method?

To create an extension method, you first need a public static class.

For the first example, we’ll create an extension method class to handle Transform extensions.

Next, add a static method named LookAtY like this.

What’s ‘this’ Parameter?

Notice the “this” keyword for our first parameter. The keyword tells our method that the first parameter, named “transform”, is the one that the extension method will be called from.

So when you call the method, you’re not passing in the transform, instead you’re calling it from the transform, but the method recieves it for you to work with.

The LookAtY method will do perform the equivielent of Transform.LookAt, but only on the Y axis. This means it won’t look up or down, only in the flatened direction of the target point. I use this for creatures who walk and turn to face something, to avoid having them tip over and aim at something a bit above or below them.

Another Example – Particle System Emission Rates

Here’s another one of my favorite extension methods.  I use this to adjust a particle system emission rate.  Since I can’t modify the ParticleSystem class and wouldn’t want all particle systems to need to use another class, an extension method is the perfect solution.

How about Vector3 Extension Method?

To wrap things up and show a little more variety, I give you one of my Vector3 extension methods.  You’ve probably used Vector3.Distance before, but if you haven’t, it’s a static method on the Vector3 class to give the distance between two points.

I found myself needing a distance that ignored the Y axis more times than I can remember, and with this simple extension method, it feels like built in functionality.

Conclusion & Resources

If you haven’t used extension methods before, you’re really missing out.  They’re very easy to get started with and will quickly become a habit once you start seeing the benefits.

Unity Tutorial Video

https://unity3d.com/learn/tutorials/topics/scripting/extension-methods

A couple useful extensions on GitHub
https://gist.github.com/omgwtfgames/f917ca28581761b8100f