Lesson 40 - Debugging Unity Projects with Visual Studio

Tutorial Series: Introduction to Unity with C# Series

Previous Article  |  Next Article


Inevitably, you’ll come to the point where you will need to debug your code. As the name suggests, this is often done to get rid of bugs in your code, but it can also be used to elucidate what the code is doing by sort of slowing down the execution, and seeing it step through the code line by line in real time. Sometimes code execution, in other words the order in which execution moves from one line to another, can be ambiguous. Such as when dealing with nested loops, conditionals, and so on. It's not always clear what value a variable holds at what point in that execution flow. And debugging can go a long way to help elucidate these murky areas in your code. So as to not only write code that works, but also code that you understand how it works. Now Visual Studio offers a great set of debugging options, but this lesson will just sort of focus on the most basic and often used features. The first thing you'll need to make sure Unity in Visual Studio is all properly set up for debugging, is to check to see if the Visual Studio Tools for Unity extension is installed. We briefly touched upon this tool in the lesson covering installation. But since that lesson you no longer need to install Visual Studio Tools for basic operation between Unity and Visual Studio.

So it's possible you didn't even install it. So the easiest way to check to see everything's set up correctly for debugging, is to open up a Unity script in Visual Studio and see if the debugging option attached to Unity is available for you. You'll see a write up here with that sort of green arrow play symbol icon right there. You'll see either attached to Unity, attached to Unity and Play, we’ll go over that a minute. If you don't see that option, then you won't be able to properly debug Unity scripts. The first thing is make sure to install this extension, so to install it. You can go to the Tools and then Extensions area from your Visual Studio menu. And then go to online and search for, Unity tools should get you there. There you go. You should see either a green checkmark indicating that the extension is installed, but if not just click to download install it and you'll be good to go. The next thing you want to do after you install it is to check to see if it's all set up correctly with Unity. So open up Unity and go to help, about Unity and you'll see right here… Or you should see right there if it's installed, Visual Studio Tools for Unity.

Now if you don't see that there, if there's no Visual Studio Tools is not enabled in Unity, the best thing to do is projects restart your computer and repeat the previous step and see if that green checkmark is now in Visual Studio for the Visual Studio Tools for Unity extension. If that's the case, and this line is still not visible in the About Unity section, in the Unity menu go to Assets, Import Package, and select Visual Studio 2015 tools, that will import Visual Studio Tools for you. Hopefully everything will be working at that point, and you'll have to remember to do this with each new project you create. Alright, so assuming that's all set up correctly, you should now be able to open up a Unity script and see the debugging option attached to Unity. So let's go to ArraysAndLoops, the script that we worked on previously. And actually just make sure it's enabled in your Test GameObject right there. The first thing you want to do for debugging is to set a breakpoint. I'll just place one anywhere arbitrarily. You can set a breakpoint on any line of code with that little red dot We set this breakpoint so that when you run the application, it runs all of the code prior to this line as it normally would, but as soon as it reaches this breakpoint, the program pauses and then prompts you to control the code execution from this point forward, until you choose to end the debugging.

So this lets you in effect slow down the code. And a good place to illustrate this is in a loop. So go to the loop that we hadn't commented out, and set the breakpoint in the margin like so. Right here where the conditional is within the for loop. So it's kind of self-explanatory but we can either debug by attaching to Unity or choosing Attach to Unity and Play. If you choose Attach to Unity, you have to just manually move over to Unity and hit that play. But otherwise, if you choose Attach to Unity and Play, you just have to start it from here, it’ll automatically start Unity for you. So let's just try this all right now, hit that. So you kind of briefly saw it shift over to Unity and then come right back to code. So what's happening here is the breakpoint was reached rather quickly because code is read very quickly, and it automatically turns your attention back to Visual Studio at the line of code you set at the breakpoint. So you can now go through each line of code, you can sort of step through each line by using the F10 key on your keyboard. You can also access it through the menu here as well, these options here, but we’ll use the. F10 key for now. Now notice how you can use F10 to step through the lines of code, it shows you the execution flow.

In this case, it's going through the conditional. And if it evaluates false, it goes right back to the for loop, right, the next line of code, which you know if it bypasses this because it's false. It's going to go right back. That's going to be the next line of code. Now you can use the Locals window. If you don't see it, then just go to debug windows locals and give you a overview of all the local variables. So here I’ll just keep that there. And so keeping an eye on the i variable, so if we're trying to figure out what's going on with that, we just hit F10 and watch the variable. There you go, it hit 0, so we know it's going to exit this loop right there we go, it exits the loop because, well actually if i is greater than or equal to zero, and now it's -1, so it exits the loop. So if we have 10, it enters the loop again. So this for loop, it starts up all over again when the Update() method it's inside of gets called again. We know that the Update() method gets called roughly every sixtieth of a second, if it's running at sixty frames per second. So that's why it keeps looping through seemingly infinitely if we keep pressing F10.

So you may be wondering why it immediately loops back through this for loop, right? After all, there's a bunch of other code outside of this Update() method should an execution flow first continue on outside of the Update() method. Well yes exactly but by using the F10 key, we step over all of that intervening code and instead focus only on the code flow as it is local to this method. So if you want to actually see how the code flows organically, you can instead use the F11 key to step into each line of intervening code. And to show you here in the Debug menu, as we saw earlier, step over, step into and we're not going to really look at step out, but this will cover pretty much all we need to know. So right now we want to step into it with F11. Now I will run this for loop watch,i, as before we expect it to exit at -1 right now. Now it doesn't loop back to to that for loop, code execution flows the next logical block. In this case, it appears to be the PowerUpManager Update() method, that's what flows right after the Update() method for the ArraysAndLoops test. Alright, so that's a basic look at how to set a breakpoint and go through a loop, but now let's turn to a more complex loop, such as the foreach we used for the SpriteRenderers that animate our Cube’s fade. So let's go there.

So here let's set a breakpoint right about there, where the array of all the different renderers are being set with the GetComponentsInChildren() method, right? Excuse me. You're going to have to remember to turn off the play button here in Unity before you can do debugging again, so yeah. Let's do this again, hit the Attach to Unity and Play. So let's use F10 key to see how code execution flows here. Alright. Makes sense, goes the foreach. Then sets the color. Everything’s working as we expect. However, notice that it will always execute this else clause since we have to actually press the teleport button to engage the initial conditional that actually shows a fade occurring, by first setting the color to 0. Or the color’s Alpha property to 0 and then Lerping from there. Right we actually have to press the button in the CubeController and that’ll get read in the CubeController. So what do we do about this, if we go to Unity and we think that we can or will just initiate it here in Unity with the space button, the space bar been it doesn't work. So I want to stop this, and we’ll see what we can do about this.

So start this again, but this time what we’ll do is set the bool ourselves in code, since we now control line by line execution directly in code. We can temporarily, while it's debugging, set this. The IsDisappear value to true. Actually, in order to do this properly, what we’ll need to do is create a reference that we can then reference by debugging to the to the bool that we're interested in. So, let's just do this, let's say in the CubeController, so let's say let's say GetComponent<CubeController> and Then let’s store that reference to a local CubeController. And this is just for debugging. So we can easily change his value while we're debugging. We’ll reference that controller, that in turn references that that bool that we're interested in. So Attach to Unity and Play. Right, so hitting F10 to get to that point. Alright, so we’ll now set this bool manually to true. Right, so, it’s emulating that button press, and as we run through the loop the first time, we want to keep this bool set to true, as it first goes through each renderer and sets its opacity to 0. So we’re simulating that on this frame, on this frame we’ve engaged teleport. So we’ll want to watch that it goes to this line instead of the else clause. Yep, there we go. And then we set the opacity, for which we can see down here. More on that later. Let's just set each one, each SpriteRenderer. And then we'll flip it to false to observe the Lerping effect as we’re... As we would expect.

Alright, we know it's now set each SpriteRenderer’s opacity to zero, because now it's exiting that foreach loop, and well we don't have to manually set that to false because the default is false. And so this time as we enter the foreach loop, yep it's false. So now with each renderer, opacity is set to zero, we’ll start Lerping in the next frame. This is the next frame, although we're slowing it way down with debugging, this will actually be the next frame after we set the opacity in the previous frame. So we should do actually is, let’s pin the renderer, so that we know which renderer’s currently being Lerped. Remember, this local renderer variable represents the current item in the index, the array that the loop is working with. So here we can actually observe it as the index and commence with each loop. So let's just pin that. Just hover over it, and then select the pin or here, it can be a little finicky, and it pins it right there. So we see this, now is the Cube’s SpriteRenderer we’re working with at this moment. And, so keeping an eye on that, we’ll also keep an eye on the opacity change, as we expect it to increment, as it starts to Lerp, it's going to increment each SpriteRenderer in this loop by a certain value. So we’ll watch that at the same time, as I keep pressing F10 here. There it goes: .029, that's what increments each frame. And we expect that to be the case for each renderer as it sets it.

So this now we're on the left eye, and it's going to set its opacities just like it did the previous one, right? As I stop in there, you see the game runs from the point at which it paused, and we took control execution flow over, and it kept running. I could've chosen to continue, and it would have just continued to play out the game in this area right here while we were debugging, but I just decided to stop it. Because really, I just wanted to show you this practical example of how you can go about debugging. Inspecting those values in real time and using the Locals window, pinning them changing those values and so on. So when you stop debugging, you'll notice that those pins and the breakpoint, they hang around, right? This is for future reference if you want to come back and keep debugging. So you can simply delete these, we don't them any longer need to continue debugging. So just click on the red dot there to get rid of it, and right-click on the pin if you want to remove it. Otherwise you'll retain that pinned variable that you're interested in the previous time you debugged.

Right, so what you saw here is debugging through Visual Studio. Through the Visual Studio debugger. But you can also debug with things we've seen before, such as you know simple things like the Debug.Log() method to output values and sort of inspect them as the game runs. You can also debug by changing exposed, or in other words public fields, in your unit inspector and directly accessing them, changing them there, and seeing how that affects your game. We kind of showed that in a previous lesson. Another debugging option you have available to you, is that you can watch the game move along frame by frame. So we’ll press the play button here to start the game, I'm going to hit pause, right? And now I can move it ahead of one frame in time. Simply by hitting this little next arrow, you see how we can see the Sphere here is moving ever closer to our character. See we can inspect the transform.position as it changes, or as we were interested in before with debugging, we were interested in how the SpriteRenderer’s being Lerped, the opacity is being Lerped when we engage teleport. So that would be, we'd be keeping our eye on this Alpha property. So here what I’m going to do is quickly hit spacebar on the pause again, right, there you go. It's already incremented a bit, so looking at this represents the opacity, right here in the inspector, you can see the Cube fading back in and we can get a sense of how much it increments on each frame. Sort of the same thing as we just saw in the in the Visual Studio debugger, but in a different way.

So this is useful as well for debugging. OK that's debugging in a nutshell, kind of technical stuff. Maybe not the most fun stuff, but it’s there to help you figure things out, so then you can spend more time hopefully on the fun stuff. So on that note, a lot more fun stuff ahead. I'll see you there.

Related Articles in this Tutorial:

Lesson 1 - Who This Course is For

Lesson 2 - What to Expect from this Course

Lesson 3 - Installation and Getting Started

Lesson 4 - Starting the First Project

Lesson 5 - Prototype Workflow

Lesson 6 - Basic Code Review

Lesson 7 - Game Loop Primer

Lesson 8 - Prototyping Continued

Lesson 9 - C# Fundamentals and Hello World

Lesson 10 - Variables and Operations

Lesson 11 - Variables and Operations Continued

Lesson 12 - Floats, Bools and Casting

Lesson 13 - If Statement Conditionals

Lesson 14 - If Statements Continued

Lesson 15 - Complex Evaluations and States

Lesson 16 - Code Syntax vs. Style

Lesson 17 - Variable Scope

Lesson 18 - Object-Oriented Programming Intro

Lesson 19 - OOP, Access Modifiers, Instantiation

Lesson 20 - Object Containment and Method Returns

Lesson 21 - "Has-A" Object Containment

Lesson 22 - "Is-A" Inheritance Containment

Lesson 23 - Static Fields and Methods

Lesson 24 - Method Inputs and Returns

Lesson 25 - Reference vs. Value Types

Lesson 26 - Introduction to Polymorphism

Lesson 27 - Navigating the Unity API

Lesson 28 - Applying What You've Learned and Refactoring

Lesson 29 - Constructors, Local Variables in the Update Method

Lesson 30 - Collecting Collectibles, Items and Powerups

Lesson 31 - Spawning and Managing Prefab Powerups

Lesson 32 - Implementing Powerup State Logic

Lesson 33 - Displaying Text, OnGUI, Method Overloading

Lesson 34 - Referencing Instantiated GameObjects, Parenting

Lesson 35 - Understanding the Lerp Method

Lesson 36 - Creating Pseudo Animations in Code

Lesson 37 - Understanding Generic Classes and Methods

Lesson 38 - Animations Using SpriteSheets and Animator

Lesson 39 - Working with Arrays and Loops

Lesson 40 - Debugging Unity Projects with Visual Studio

Lesson 41 - Camera Movement and LateUpdate

Lesson 42 - Playing Audio Clips

Lesson 43 - Routing Audio, Mixers and Effects

Lesson 44 - Adding Scoring Mechanics and Enhancements

Lesson 45 - Scene Loading and Game Over Manager

Lesson 46 - Understanding Properties

Lesson 47 - Controller Mapping and Input Manager

Lesson 48 - Understanding Enums

Lesson 49 - Dealing with Null References

Lesson 50 - Handling Variable Framerates with time.DeltaTime

Lesson 51 - Preparing the Project for Final Build

Lesson 52 - Final Build and Project Settings

Lesson 53 - Introduction to the Unity Physics Engine

Lesson 54 - Understanding FixedUpdate vs. Update

Lesson 55 - Movement Using Physics

Lesson 56 - Attack Script and Collision Events with OnCollisionEnter2D

Lesson 57 - Projectiles and Stomping Attack

Lesson 58 - Parallax Background and Scrolling Camera

Lesson 59 - Infinitely Tiling Background Sprites

Lesson 60 - OOP Enemy Classes

Lesson 61 - OOP Enemy Classes Continued

Lesson 62 - Trigger Colliders and Causing Damage

Lesson 63 - Multi-Dimensional Arrays and Procedural Platforms

Lesson 64 - Finishing Touches

Lesson 65 - Series Wrap


Please login or register to add a comment