>> My name is Charles, and in this video,
I'm going to show you how to use the debugger in
Visual Studio to get a better understanding of
what your code is doing at runtime so you can fix bugs faster.
If you'd like to follow along,
the example project used in this video is free for download.
Unity comes with a rich set of features that you can use to
implement game mechanics and create stunning visual effects.
Its physics system can simulate almost any physical interaction,
and its visual tools like
Shader Graph and the Universal Render Pipeline can be
used to generate an extremely
realistic or stylized look for your game.
When coupled with its scripting engine,
there's no limit to the variety of things that Unity can achieve.
However, as great as these features are,
they tend to slow down the process of debugging your code.
Let's take this project, for example.
As you can see, it's a relatively small game
with a few simple mechanics.
We have a third-person view of the player and we can
perform various attacks against
the enemies that are spawning around us,
my favorite which is this really cool shooting mechanic where
the camera moves in over the player character's shoulder
when her gun is drawn.
Very cool, except it has one problem.
While everything seems to be working fine,
the console is filled with errors.
Let's pause the game and take a closer look.
At first glance, we can see that this error
is being caused by a Null Reference Exception.
More specifically, if we click on the error in the console,
we can see that this exception is occurring somewhere in
this SendDamageMessage method
in the ParticleCollisionListener class.
Let's go ahead and open that up in Visual Studio.
Somehow, a variable in
this method is inadvertently being set to null.
In programming, null values are very bad.
They represent a void or black hole in your code,
so we'll need to account for that in this logic.
But we can't do that if we don't know
which variable is being set to null,
so we'll need to do some debugging.
A common approach to debugging in Unity is to use
log statements to reveal
exactly where your code is doing in the console.
Let's add a few calls to Debug.Log to our broken method now.
We will place one at the top that lets
us know when the method is being invoked,
then another to display the value of
this variable here called Damageable,
as well as one to display the value of Message.
Finally, one at the end of the message to let us
know when it's completed its execution.
Now, we can play the game until the error appears
again and analyze the logs to figure out what's going on.
It looks like there's some edge case that's
causing Damageable to be set to null,
which results in our Null Reference Exception
when the applied damage method is invoked.
It's a good place to start,
but we still need more information,
which means we'll need to add
more log statements and run our game again,
and even that might not be enough.
We might have to complete two or three more iterations of
this slow trial and error approach
before we fully understand how to fix this bug,
and that just takes too much time.
Luckily for us, Visual Studio has a tool
that offers the perfect solution to this problem.
The debugger in Visual Studio is
a tool that allows us to step through
our code line by line and inspect
the values of our variables at runtime,
or in other words,
as the code is actively running.
To do that, we'll need to make sure that
Visual Studio is attached to the instance of Unity
that's currently running our project by either
clicking the play button that's labeled Attach to Unity,
or by locating the Unity instance manually,
which we can do by expanding
the Debug menu and clicking "Attach Unity Debugger."
Doing so will open a small window that
contains a list of all the available Unity instances,
including remote instances that are running on your network.
Let's go ahead and click on "Attach to Unity",
which is a much quicker option.
Now Visual Studio's attached to the correct instances of Unity,
and we can start debugging our project by
switching back to Unity and pressing "Play".
Now we're officially debugging our project.
But if we want to find out what's
causing our null reference exception,
we'll need to set what's called a breakpoint in our code,
so let's stop running
our game and switch back over to Visual Studio.
Breakpoints are a feature of the debugger that allow you to
pause the execution of your game on a single line of code.
Once paused, you can examine variables,
step through the code,
and perform other similar debugging tasks.
Let's set up a breakpoint at the top
of the SendDamageMessage function.
We can do that by clicking the gray bar to the left of our code.
Alternatively, we can expand
the Debug menu and click the "Toggle Breakpoint" button,
which has the keyboard shortcut F9.
Now we're ready to start debugging.
We can do this by switching back to
Unity again and pressing "Play",
or by expanding the play menu
and selecting "Attach to Unity and Play",
which will play the open scene and switch
the focus back to Unity for us automatically.
Now, the key to diagnosing any problem is to recreate the bug.
But first, it's important to
understand what the code actually does.
We'll start with the happy path and shoot an enemy so we can
step through the code and see the expected behavior play out.
Now that we've shot an enemy,
we can see that the running scene is paused,
which means that our breakpoint has been reached.
Over in Visual Studio,
we can see that the first line is now highlighted,
signifying that the execution is currently paused there,
and down at the bottom of the screen,
we can also see that the debug window is
populated with all the variables that are currently in scope,
including the offending Damageable variable.
Let's move the execution of this code one step forward by
pressing the Step Over button in the toolbar.
Now the execution has progressed to the next line.
If we look back at the debug menu,
we can see that the Damageable variable has
now been populated and is no longer null.
If we set forward again,
this time I'll just use the shortcut F10,
and one more time, it's clear that
the code is working because the exception was not thrown.
Now we can go ahead and recreate the error
by shooting a non-enemy in the scene.
First, let's let the code go back to executing as
normal by pressing the "Continue" button in the Toolbar.
Then let's switch back to Unity and shoot this box in our scene.
Now the scene is paused,
and the Visual Studio debugger has
stopped the execution of the first line,
so let's step through it again, and look at that.
In this scenario, the damageable variable is null because
the game object that was passed into this function, the box,
did not have the component called Damageable attached to it,
and when we set to the next line,
we can see that the exception is thrown,
which, of course, we'll need to handle.
Thanks to the debugger, we were able to recreate
the bug and determine what was causing it.
All we have to do now is add
a simple null-checking guard clause to
the top of the SendDamageMessage function.
Then step through the code one
last time and confirm that it works.
Let's go ahead and add our new logic.
The guard clause right after Damageable is initialized.
If Damageable equals null, return.
Now, with our breakpoint still in place, let's test it out.
We'll take aim at our box,
and now we can set to the code again.
But this time, our guard clause will recognize that
Damageable is null and break out of the function early.
We can quickly confirm this by hovering over Damageable with
our mouse to reveal the inline inspection tool tip.
Sure enough, Damageable is null,
so our logic will now break out of this function
prematurely to avoid
the null reference exception from being thrown.
Log statements are a quick way to expose what your code is doing,
but they only offer so much.
The Visual Studio debugger, on the other hand,
gives you access to all the information you need to
understand how your logic is operating,
and the setup and process is similar
across all Visual Studio products.
So whether you're using Visual Studio,
Visual Studio for Mac,
or Visual Studio Code,
make sure you take advantage of this powerful tool so you
can debug issues more effectively and fix bugs faster.
[MUSIC]