Using GetComponent<>() Advanced Discussion

In Reference to this lesson in this course I would like to point out that yes, this is in fact a beginner course where we are trying to understand the basics of coding. But at the same time, we also have to be careful of the performance of our code. We are in fact after all writing games. With that in mind, we want our code to be as fast as possible so that it won’t have an impact on the overall performance of our game.

In the OnCollisionEnter callback function we have the line

GetComponent<MeshRenderer>.material.Color = Color.Red; 

Now what this is doing is asking Unity to find us a component, in this case the MeshRenderer and that takes some time for Unity to do, because Unity starts at the top of a game object and works it’s way down until it find what we’re looking for. And if we remember that even a simple Cube has multiple components by default attached to it, So Each time you hit your player up against an object, and the OnTriggerEnter callback is happening, it is searching for the MeshRenderer every single time. and like was previously mentioned this takes some time, it takes some overall game performance to do.

So How can we go about fixing this issue

One common way to fix this issue is called component caching. And what this is, is getting the component beforehand and storing it in a variable so that we can use it later. In this way, we only ever have to call GetComponent<> once.

So how would we go about doing this. Well it is in fact quite simple. We can create a variable to hold a reference or the location of where the MeshRenderer that is associated with our game object. Then in the Start callback function we can use GetComponent<> and assign the result of the search that GetComponent<> can do to our variable. Then finally in OnCollisionEnter() we can make the change to our variable as if we used the original line of code from this lesson, and that would look something like this

public class ObjectHit : MonoBehavior 
{
   // This is a variable to hold the location of the MeshRenderer Component
   MeshRenderer meshRenderer;

   void Start() 
   {
      meshRenderer = GetComponent<MeshRenderer>(); 
   }

   private void OnCollisionEnter(Collision collision)
   {
      Debug.Log("You hit the wall");
      meshRenderer.material.color = Color.red;
   }
}

And this code here will do the same thing that was shown in the lesson, but will save some time because unity isn’t looking through all the components every single time your player hits an object. I know that this is more of an advanced topic to cover at this point. But I do think that it is something worth mentioning and it is also something that you will pick up more along the way as you work more with Unity and you learn about optimizing your code.

3 Likes

It would be great that whenever Rick uses certain “unefficient” code for the sake of simplicity, that there is a thread like this in the “Resources” section of the video showing a more advanced explanation/variant that would be how it is actually done or should be done for those students who want to take the further step.

1 Like

While I like that idea, over time, you learn significantly better methods to approach these kinds of problems… and then to do a full circle and do near close to the way Rick did it the first time since it’s so much easier to read, but you add an event or use some other trick that is suitable to the circumstance… I’ve even gone full hog abstract and make it near impossible to track down what you did.

In all honesty, I see a lot of people incessantly worrying about these efficiences (I used to do it) and and hamper their learning to make their code efficient. In the end, you realise that computers are so powerful and you learn techniques so that a lot of these calls use so little resources, in the whole scheme of things, it doesn’t really matter (unless it’s a resource heavy core part of code that runs every frame when performance matters - then disregard what I said and do it!).

1 Like

It should actually be noted that a few lessons later on, this exact technique is covered. It is good that the more correct and efficient way shown and somewhat explained. But at the same time I think the best practices way should have been used in first place. Sure it might have made the lesson a little longer, and there might have been some more dryer technical stuff as to why, but at the same time, as Unity developer these things should be known about from the get go.

One of the things people will learn when it comes to programming is that, sure, there is an easy way, which works which can show how something is done or show a concept. And then there is the more right or proper way to do something that pretty much everyone else would be doing in the real world.

Before Unity was as popular as it is now, there was actually a lot of gamers that hated games made with unity, because one of the main reasons was you could see micro stuttering as the game played. people with high refresh rate monitors would see frame rates go from 120fps for like 6 for a second then back up to 120. A lot of this was due to C#'s garbage collection that runs in the background, but also a lot of it was due to developers still learning best practices for working with the engine. Over the years and as Unity has released new versions of the engine things have gotten a lot better, but there is still things that we need to be mindful as developers working with the engine.

Now what I think should have happened during this lesson, is yes it should have been shown that you can use GetComponent<> in the way that it was shown, but then actually shown the right way, and did a little bit of discussion about as to why it should be done one way vs the other.

it is always better to cache a component then to search for it each time in a section of code that could be run multiple times a second.

And as @MichaelP had mentioned there are times when it doesn’t matter. But in this case Just seeing the example in this specific case where GetComponent<> was used, and how it was used is very cringe worthy if you understand anything about the engine. And I am the type of person that would much rather have people understand as to why doing such a thing should be avoided where possible in the first place as sort of a best practices type of thing.

If you want to push for efficiency, perhaps you should be pushing the inbuilt dependency injection so you can avoid most of the GetComponent<> calls that should be cached in the first place. That’s pretty much best practices on this topic and this is something that is hammered in, time and time again through the courses.

That all being said, I do somewhat agree with you that some things should be cached. You need to remember these courses are pretty much beginner courses and their primary purpose is to teach game design and game programming. Learning best practices, techniques that are more efficient, even defensive programming, while is important, it is more suited to later in a programmers journey where you’re in a better position to make decisions on the pros and cons of each decision.

You don’t teach a beginning driver everything at once. You overwhealm them. You start with one or two of the basics, do that and then slowly teach extra stuff.

I would definitely agree with you, removing lookups with GetCompoent<> all together in the first place would be the best thing to do, but then that also opens up a whole new can of worms. i.e. Null Reference Exceptions because you forgot to set something in the inspector. Sure, it’s an easy enough fix you just add in the missing component to where it supposed to be hooked up. But I think that would be harder on someone who is just learning to program then say knowing where and when to cache a component.

1 Like

You can still get null ref errors even if you cache a component… or for the matter, just make the simple GetComponent<> calls. You also need to teach a beginner defensive programming techniques… but all that in good time.

There are plenty of things that can be taught. For example ternary operator. It’s super efficient, but teaching it over an if/else statement to a beginner programmer is a recipe for disaster.

Privacy & Terms