Transcript for:
Using Rider for Unreal Engine Development

Hi, if you're not using Rider, no problem. You can follow this tutorial series with other ADEs as well. Visual Studio is a great general purpose IDE, and I always have at least one version of it installed on my system. But Rider offers a really great Unreal integration, so that's why I prefer using Rider. In the beginning, I will show you how you can speed up your workflow through Rider. We will create C++ templates for Unreal classes, and we'll also provide you with a batch file that will help you to perform clean builds. In the second part, we are going through different debugging approaches. The Blueprint Debugger in Unreal Engine, the Rider Debugger, Console and On-Screen Logging, and finally, we are going to utilize macros to draw debug geometry in our 3D world. Let's start Rider. In the File Settings, and then under Appearance Behavior, New UI, Check Enable New UI, and Show Menu in a separate toolbar. I think it looks cleaner, and I just like to not be distracted by too much information. One of the first things I usually do is, I change the build CS, and I add the root folder to the public include path. This will make the include statements in subfolders just look cleaner. For this project, I prefer to not have a public and private folder, as you see in many other projects. I mean, encapsulation is very important, but since it's not a module, I am not going to expose the game to other software. So for the sake of simplicity, I keep my header and implementation files together. All right, let's add a new class, which is going to be the base class for all characters in the game. First of all, you see this copyright notice that we set last time in the settings. And you also might notice that the file looks a bit cleaner than usually. This is because I changed the templates that are used to generate the Unreal classes. I show you what I mean. I use an application called everything to search for files. You don't need it. You can just go to the location and open the templates and writer and change it to a liking. Just keep in mind that with every Unreal update, you need to replace the templates with your own files. Let's create two more character classes. One is the enemy character. Like all our characters, it's going to be a child of the FAB character base. Writer automatically includes required headers if it can. The second class is the player character, which is also going to be derived from the FAB character base, of course. What I would like to show you now are some basic but useful writer tips. If you double-press shift, you can search for many different things. Like, for example, on component overlap, which is going to find those two functions. And if I go here, press control and click, I can navigate to the type definition. I close the tab with middle mouse and here, I toggle between a header and implementation file by pressing Alt-O. Suppose I don't have this implementation of the BeginPlay function. I can go to the declaration of our BeginPlay function in the header file and with Alt-Enter, I open the context menu to generate the function definition, which already contains a call to the parent function. Very handy. When I select some lines of code and press Alt-Enter again and go to reformat and clean up and then detect code style settings, Rider is going to learn my code formatting style based on that selection. So whenever you let Rider generate code for you, like we did before with the BeginPlay function, it's going to apply your coding style. I'd say let's build the solution. You can also press shift-B to build it. Okay, the build has succeeded. I'm going to close all those notifications and go to the project directory. I have prepared this batch file that deletes all intermediate files. If you double click on it. If you run into some issues and you don't know the cause of it, you can just run the batch file, make a clean build and that might solve your problems. If you now click on that file, you see that the intermediate files are locked by some process. If you run into this, just open the task manager and the resource monitor. Sorry for being it in German. Search for your project name and then you see all the process that might block the files. You can right click and restart it. But if you terminate the process, I first have to close the CMD. And you lost the Explorer entirely, you can just start the Explorer in the task manager. And if we now run the cleanup bet, you can see that the intermediate files are deleted. I start the engine, but we first have to rebuild the project. All right, let's talk about debugging. I open the player character blueprint. This event begin play is called right after you hit play. Then the controller is getting casted. Check if it's valid. And after that, we go to the add mapping context. Let's add a breakpoint here. You can also press F9. And now if you hit play, it's going to enter at the begin play event and stop here at the breakpoint. We can go inside the function with F11, with F10, advance and advance, and it's going to jump out of the function. Now, if you go to node, for example, this one and hover over the return value, we can inspect this controller variable. There are also other options like the blueprint debugger tool, where we can inspect the core set and we can click through the execution trace to inspect the data flow. Here in this menu, you can select which blueprint instance you actually want to debug. Before I show you how we can debug our C++ code in Rider, I go to class settings and I reparent this blueprint to our player controller class that we created before. Now in Rider, we can see that there's one blueprint derived from the player character C++ class. Pretty cool. If we hit Alt O to go to the implementation file, we can put a breakpoint here and attach Rider to the Unreal editor process, which is going to take a little moment. Now, this little check mark indicates that we are good to go. Now back in Unreal, we click play the game. We actually could have done this in Rider too. And it's going to stop here at this breakpoint. And if we hover over variables like we did in the blueprint, we can inspect their values. This unsigned char is actually interpreted as true. Then we have this debug window with the typical controls. We can stop the process, resume, step over, step into or out of a function. We can also open the breakpoint menu. Here in this menu, we can change all breakpoints at one place. We can disable and enable breakpoint. We can always mute all breakpoints. When we click on a breakpoint, we can add a condition and turn it into a conditional breakpoint. So for example, like that, which doesn't make too much sense because it's always true, but we can also take this variable and evaluate it here as a condition. Whenever the variable is true, it's going to hit the breakpoint. If not, it's going to skip the breakpoint. In the debug window, you can also inspect the call stack. Here we see that super begin play roots ultimately to the actor class, which calls another function that calls another function and so on and so forth. We can also inspect variables. Here are no local variables, only a lot of members of this object. It's very insightful if you ask me. We can also watch a specific variable like this bool bCanAvertick. I stop the debugger now and I remove the breakpoint. I also stop the play an editor session and I close this. Next to breakpoints in blueprints and code, logging functions are very helpful to debug your code. With logging, you are not interfering or stopping the game execution, which is often a better approach to understand and debug the game, especially when timing is important. For example, this infamous Ulog function with log temp being the category, the verbosity level warning and the text macro that contains this %s placeholder and there we can have a variable number of arguments. If you don't always want to type this by hand, you can also press double shift and make use of live templates. In the settings, you see those live templates and you can go here to C++ where you can write your own templates. I have this Ulog template and it's going to print the logging function with the name of the function where the logging is taking place. I use it very often. This Ulog bool down below logs boolean variables. Let me quickly demonstrate what I mean. First, I use the template for logging the function name and then I use the boolean template together with our boolean member variable. If you don't only want to print to console, you can also print to the viewport with G engine at onscreen debug message. We don't need a key, then the time in seconds and the color. I say purple and yeah, then of course the text itself. To try out the logging, we first need to close Unreal Engine and then with control shift B, we can build the project as always. Okay, build was successful. I'm going to clean this up and open the engine again. If we now hit play an editor, we can see the onscreen message. Okay, it was only two seconds, but I think you saw it. And in the output log, we can see the two logging statements. The first one is logging the function and the other one is printing our boolean variable name and value. I'm going to close the editor because we're going to add a bit more. Back in Rider, I add more of those logging messages. However, I don't want to type them out all the time. Instead, I want to employ macros. I add a file in our project that I call fabmacros.h. I type pragma once so that it is only included once. Then I define a macro with capital letters, print, and debug message is the first parameter. Then we have a variable number of additional parameters. Then I paste the body of our G engine function here. And instead of this text, I'm going to type f string printf. Text, debug message, and then var args for variable number of arguments. Okay. Now I go back to the player character. I delete this and I write print and it says declared in header fabmacros. So the header was included automatically. The only thing I write here is hello, and then I can add as many placeholders as I want. And then I'm going to type f string function. Don't forget the asterisk to dereference the returned pointer. And now let's check if this worked. Okay, the build succeeded. However, before we test this out, I'd like to point out that we were able to include this header directly because we added the fab folder to the include path. Okay, let's go back to our fabmacros because I wish to add some more macros. First, I close this and I include the draw debug helpers. You'll see why in a second. I define a theorem macro with a position of its center as the only parameter. If I can obtain a world object to provide a world context, I'm going to call the draw debug theorem function. You don't have to remember the function's parameters and you don't have to check the API. I recommend to get used to look into the source code directly to understand the Henry engine. Let's jump into the draw debug helpers header file. Okay, we need a world object, a center position, a center position, and a radius. So, get world. The center parameter, say 20 centimeter, could be a good value for the radius. It follows the number of segments, the color, and the question if the lines should be persistent or not. And then we have a couple of default parameters like lifetime and so on. So, the numbers of segments, say 16 is a good value. Then we have a color, say blue, and we want it to be persistent. All right. I also want to have a version that's not persistent because if you want to draw a sphere in the tick function, it should only stay for one frame. Therefore, we can just duplicate this line and rename the macro to sphere tick. And the only difference is that persistent lines is false. For this case, the lifetime defaults to a single frame, and I change the color to green to visually differentiate between the two functions. I also want to be able to draw a line. A line or mathematically correct, a line segment has a start and an end point. And again, we need to check if we can retrieve world object in this context. Let's go to the draw debug helpers again. Here we have the world object, the line start and the line end. Then we need a color, be persistent lines, and there's a lifetime. So, pretty similar actually, only with line start and line end in this case. Okay. Get world, line start, line end, then F color again, blue for the persistent one, and true. And of course, with control D, we duplicate the function, and write tick for the non-persistent function. And here we only change this to green and that to false. Now, let's use those functions in the player character. So, we have this print function here. Then I define a vector for the target location. I checked this position out before if you ask yourself why I choose those numbers. And now we draw the sphere with the target location for its center position. We also want to draw a line, of course, with get ectolocation starting at the location of this player character and ending at the same target location. At this point, what's missing in the player character is a tick function. So, let's go to the header file to override this function and to generate a definition. In the tick function, I call the tick, this time with get ectolocation, and line tick with get ectolocation for the line start, and I copy the values for the line end. I build everything with control shift B. The build was successful, so we can open the project again. And now when we hit play in editor, we just saw the on-screen message called in begin play, the two UELOG calls still appear at the output log. We see the persistent blue sphere and line, and we also see the green non-persistent versions. This is going to be really useful when we implement and debug combat, NPC behavior, and in general, interaction with the world. Now you should be able to start working with Rider, and you also have a handful of tools to develop and debug your game. So, I hope you enjoyed watching this video. Don't forget the GitHub link in the description. Thanks for watching and see you next time.