Mastering Game Development with Unreal Engine 4 - Second Edition

5 (1 reviews total)
By Matt Edmonds
  • Instant online access to over 8,000+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Making a C++ Project for a First-person Shooter

About this book

To make a basic combat game from scratch, you will quickly override existing UE4 classes, and add and implement simple C++ functions while running and building them. These are all discussed as a short summary for new developers and as a quick refresher for experienced developers. Next, you will build a combat player character with expanded controls, create logic for a character, swap weapons, attack and move, bridge over scene changes and transitions, retain data between scenes, and manage the scene-change process.

You will then build an intelligent enemy AI and add physics based particles for weapon impacts. You will also get acquainted with cutting-edge features such as Volumetric Lightmaps for precomputed lighting, and Atmospheric and Volumetric Fog, to build advanced visuals in our ongoing GitHub project.

Moving on, you will explore the tools required to build an in-game cut-scene for a more professional gameplay experience and story direction.

Along the way, you will implement a solid game UI, including writing a full in-game load and save system that will enable players to resume their game from any point. You will also prepare, build, and work on VR and AR taking them from editor to real-world, building two new projects one in each of these brand new areas of UE4 and integrate classes from the main project into AR!

By the end of the book, you will have mastered all major UE features and will be able to bring self-imagined games to life through Unreal Engine 4.18+.

Publication date:
September 2018


Chapter 1. Making a C++ Project for a First-person Shooter



Welcome to Mastering Unreal Engine 4! The goal of this book is to take individuals who are familiar with UE4 and C++ development to the next level in a holistic way. While some chapters will focus on specific system implementations and best practices in depth, others may give a more broad view of the large UE4 systems that are often used by content creation team members. By the end, you should have a solid foundation on which to make the best decisions concerning the use of UE4's technology with any scope or platform of project, and you will be able to guide a whole team towards seeing the project through to the end. There will be many areas in which you can directly implement these systems into game projects, but the overall goal of this book is to be able to address any needs from a technical direction side, giving you a base of knowledge that's a step above that of those who simply write code.

In this chapter, we will start a project for a basic combat game so that we have a basis for adding and working on more advanced features when we go forward. While some of this is automatically managed from UE4's game templates, we will go through all the necessary steps to make sure that the core setup referenced through the rest of the book is added, built, and tested, and that some new gameplay systems are implemented and demonstrated.

The major topics to be covered through the rest of this chapter are as follows:

  • Setting up and creating a new first-person shooter project
  • Overriding existing UE4 classes
  • Adding and implementing simple C++ functions for them
  • Quick review of build and running options

Technical requirements

For this chapter, you will need the following components:

  • Visual Studio 2015 or 2017 (any edition)
  • Unreal Engine 4.18.3 or higher built from source code

Some quick notes on platforms and installations: the aforementioned components assume that you will be using a Windows 10 PC, but there is no reason that a Mac running a current version of Xcode cannot benefit from and perform all the same work explored in this book. As the work presented will be from VS and reference some of its features, this is the recommended working environment as we progress through the chapters, but it is not specifically required. Samples will be tested from time to time and built on Mac mainly for iOS purposes in later chapters, but this book will not focus on IDE specifics other than giving steps (typically in Visual Studio terms) and tips. Code samples may reflect formatting that comes from's Visual Assist tool, which I highly recommend for Visual Studio users, but their tool does not affect building or results.

You can find all the sources referenced in all of this book's chapters at, with revision history for the work presented in each chapter.

For this chapter and its work, be sure to select the branch named Chapter1, the branch's dropdown on the top left of GitHub's web interface, or use the direct link for this chapter's branch at 

Two notes on using the project directly from GitHub: You still need to have the engine installed from source locally so you can right-click the project (Mastering/Mastering.uproject) and click Select Unreal Engine Version, and you will need to choose your installation file, which will also build the proper project files. Upon launching the Mastering.sln file in VS, please go through the following steps:

  1. Right-click the Mastering game project in the solution explorer and select Set as Startup Project so when running from VS, you launch directly into the editor for this project.
  2. Set the configuration to Development Editor, with the platform set as Win64.
  3. It may be necessary to right-click directly on the UE4 Project in the solution explorer and click Build. Sometimes, when building a game project, it will not pick up the full dependencies needed for building the engine, if this was not already done separately.

The engine version that we will be using is 4.19.0.



Building the FPS C++ project

In this section, we will go through the steps of creating a new project from scratch using the Unreal Project Browser. For those familiar with these steps already, the process should be relatively quick and straightforward. For anyone new to this setup, which can be typical of team members joining projects that are already in full development, there are some necessary steps to getting started. Since we will be working in C++ and using Visual Studio, I will make a quick aside here for users of the engine without the source code: Since this book will endeavor not to modify the engine source directly, it is still necessary for you to build C++ projects, as this is what this book will focus on. A blueprint-only project can be made without building source, and some pros and cons of this are explored inChapter 3, Blueprint Review and When to Use BP Scripting, but again, this is not the way this book's information is presented in most implementation cases. It is also worth noting that Epic Games are quite receptive to users of their technology finding issues or improvements that they can help resolve, and if given proper debugging information, they typically respond to these raised issues much more readily on their answer hub forums, such as Additionally, if your project needs a fix or change to engine code immediately before Epic Games can help, you will need to be comfortable debugging and building the engine. Lastly, if you would like to make pull requests of the types of changes or fixes that are to be integrated by Epic Games, you will also want to bind it to their GitHub project in Git. So, going forward, we will proceed as if we are installing the engine and project on a fresh computer with the full ability to rebuild from source code.

In the following section, we will do some modifications to the game mode and player, recompile these, and see the results in-game. For those wishing to skip ahead, all of the work that will be presented is available on the GitHub repository in the Chapter1 branch, as notedpreviously.

There are three major steps to getting a brand new project up and running:

  1. Download and install the UE4 source and compile it.
  2. Run the editor to the project browser for the first time and pick a template.
  3. Build and run that project.

Installing and building UE4

Our first step is to download the UE4 source code and build it. This can be done in a number of ways. If this is your first time doing this, the simplest way is to go to their GitHub site to acquire the engine, at


For the link above to work, you must be signed in to GitHub, and have applied as an Unreal Developer.  See: for details.

Click the Clone or download button to see your options. From here, the simplest solution is simply to select the option to download the project as a ZIP file and unzip it wherever you like on your hard drive, as shown in the following screenshot:


Using the website is always a viable option with Git. While I am not personally a fan of the GitHub Desktop app, it is also a possibility that you can explore at this point in the process. And while I would say there are some user-experience issues with SourceTree, it is a free app that I do recommend for managing GitHub projects. For those comfortable with command-line work, there are a number of options, as well as a terminal that you can open in order to use these commands in SourceTree. The important part, for now, is to get the UE4 tree installed so that we can get to building!

The first thing to do when downloading a new version of the engine, be it an update or fresh install, is to always run Setup.bat (or the setup command on Mac) in the main installation folder before doing any other steps. Make sure that the pop-up window is getting all the platforms you use, ensuring that it pulls the required files for the platform that are described in the file in the same folder.

Once the Setup.bat/setup command has completed, run the GenerateProjectFiles.bat file, and a UE4.sln file will appear in the same folder. A quick note on the state of UE4-generated solutions and VS 2015 and VS 2017: UE4 generates VS 2015 project files by default. It is possible to specify -2017 as a batch file argument. It is currently not necessary to build for 2017, and the 2015 project files open, build, and run perfectly well in both VS 2015 and VS 2017. However, if you have both versions of VS installed, then by default it will try to open them in VS 2015, which can be very annoying. As of writing this book, using either version of Visual Studio should grant the same results, and this was tested here, but going forward, what is in GitHub will force you to use VS 2017 for building in the editor. There is a discussion about why and how this is set later in this chapter in the Overriding the Character Class portion of the Modifying Our Game with C++ section.

The steps that we need to go through to have the engine built are now very straightforward:

  1. Double click the .sln and open it in VS.
  2. For now, right-click the UE4 project in the solution explorer and select Set as Startup Project.
  3. Select Development Editor as the Configuration (or DebugGame; more on this later), and Win64 as the Platform.
  4. Build the project. This can take an hour, depending on your hardware setup. Some build recommendations are listed at the end of this section.


Running the editor and picking a template

Our next step is running the editor. Launch the engine in VS by pressingF5. Without a game or app project in the solution, this will take you directly to the Unreal project browser. You can also easily do this any time later by right-clicking the UE4 project in the solution explorer and debugging or running it directly. I also recommend simply creating a shortcut to your UE4 install folder's /Engine/Binaries/Win64/UE4Editor.exe file, as sometimes it can be beneficial to quickly launch this outside of your programming IDE. From the Project Browser, go through the following steps:


  1. Click the New Project tab, and under it, the C++ tab.
  2. Pick the First Person icon as our type to make our first-person shooter (FPS) base.
  3. Pick a destination folder and a project name, and click Create Project.
  4. If you choose a project name other than Mastering, please read the following information box.

The choices for Desktop/Console, Quality, and Starter Content can be left as their defaults, but feel free to hover over them and click their drop-down arrows to see the options for each, as well as the brief descriptions of what they do. Starter Content is actually an Unreal content pack, and we will be adding it manually in a later chapter.


As the project presented here is set on GitHub as Mastering, that will be the name used throughout this book to refer to the project name. Unreal's templates use this for making several of the basic files added to the project, too. So, for example, when referring to MasteringCharacter.h, if you chose another name, please reference (Your Project's Name)Character.h from what the template built. For simplicity, it is recommended that you simply name it the same.

At this point, UE4 will close the project browser, generate the game's project files, and attempt to open it in VS. Naturally, at this point, it is a good idea to simply close the engine-only IDE session, as the engine project is also opened in the project solution. As you can see, the project you named should now be the startup project, and should contain several source files for the C++ template.


Building and running the game project

Now, we can finally build and run our game. Building the FPS sample project should go very quickly, and unless you change to another configuration or platform, it will not require the building of any of the engine code again. As a general rule, it is a good idea to build DebugGame versions for testing. Using this, you will get some extra runtime information and safety checks for your project's code, but typically without a significant change to performance when testing. So in our case, I recommend using DebugGame Editor, even though we built the engine in development. DebugGame Editor, as a standalone configuration (DebugGame) running on you PC, will build only the game project's code in debug, but will continue using the engine in its faster-running development configuration. Changing the configuration to Debug Editor, for example, would force the engine to fully build in debug as well. The engine also runs rather slowly in areas in debug builds, and maintaining both debug and development builds of the engine is time-consuming and usually unnecessary, unless it is actually debugging engine code directly. Once the project finishes building, simply run it using F5, like we did with the engine-only solution session. This will launch the editor with your game as the game project. The editor in UE4 is where all developers, including programmers, will do a huge amount of work and testing while building a game or app. Play In Editor (PIE) is one of Unreal's greatest strengths, as is the hot-reload of the game library while working in the editor. As projects grow in complexity, and the game flow may change from the simple starting of a level, hot-reloads and PIE itself may not always be a viable option for testing, but for our work in this section, it is perfect for showing off some of its advantages. Generally, when working on gameplay systems or debugging new code, PIE will be your best friend.

So, "sounds great!", you say. Feel free to give it a shot with the Play button near the right side of the top bar of the editor's default layout. Immediately, you'll notice that you can move around with the traditional WASD FPS keyboard controls, fire a weapon (with some physics impact on its projectile when it hits the cubes in the level), and even jump with the spacebar.


At this early stage, it is always a good idea to consider your controls. It is always recommended that you maintain viable PC controls for any game type for any team to use while working in the editor and PIE. Even if a game or app will not use a PC as its native platform, such as those using a mobile or VR, the speed and ease of testing in PIE makes maintaining parallel PC controls very valuable. In fact, if you go to the game project and open the MasteringCharacter.cpp file and browse through some of the input code, you will notice that it specifically supports two methods of turning in order to correspond to a control stick or virtual control stick on mobile, as well as direct axis input, such as a mouse. There is also commented-out code to support one-touch movement and turning on a touch-screen device, such as a phone or tablet. In the next section, we will add a new input. You are welcome to browse the existing inputs to see what was already set up and bound across the various platforms. Just keep in mind that at a time like this, it is typically much easier to begin maintaining controls across multiple platforms earlier than it is to add controls for a whole platform later.


Modifying our game with C++

In this section, we will look at some quick ways to add new features and gameplay to a project by adding a new mechanic to this FPS game: stealth. We will do this by overriding some of the existing supplied classes in the template, and adding a new input and some new code. At the end of this section, we will run the game, test that our code is definitely doing what we want, and see those results in game as the character crouches when the input is down. We will go through the following steps:

  1. Add a new C++ class from the editor.
  2. Modify this class and let it hot-reload back into the running editor.
  3. Add a new input and gameplay mechanic and see it in action.

Overriding the character class

To facilitate our future work and start some good practices, we will add a bit of specialized game code here by subclassing the existing MasteringCharacter native (implemented in C++) class that supplied. This can be done directly in Visual Studio by hand, but Epic Games have once again supplied us with some shortcuts in Unreal that we will use from the editor. So, let's begin with the editor opened to our project, as we left it in the previous section.

We will begin in the content browser window, which is typically docked to the bottom section of the editor by default. If it is not already open for you, or was closed for some reason, just reopen it by clicking on the Window at the top and scroll to Content Browser, then Content Browser 1, and it will reopen as a free-standing window. I would dock this wherever you are comfortable in the editor, or, of course, it can be a free-standing window. What is important, however, is on the left-hand side. Just under the Add New dropdown is a small icon with three lines and a little arrow. Click this to open the Sources panel, which I find extremely helpful for navigating content in the editor. In there, under Content, is a folder called FirstPersonCPP, and in that is a Blueprints folder. Click on that folder and you should see a FirstPersonCharacter item on the right panel. This is the blueprint representation of the character we currently play when the game is started, and it is required to have an instance in the map for the game to function properly, given the way this C++ FPS template is made. This is one of the only blueprints used in the C++ FPS template, but let's open it and take a look at what is available from our native class in C++ code in the MasteringCharacter.h/.cpp file, which shows up here in a blueprint representation in the editor. Right now, it just looks like a collection of variables, with a line at the top starting withNOTE: and ending with a blue link toOpen Full Blueprint Editor. A much more in-depth discussion of blueprints and their classes and interaction with C++ will be made in Chapter 3, Blueprint Review and When to Use BP Scripting. For now, just click the blue link so that we can see a bit of how these variables define our character in the game. The strict C++ style of the template makes very little use of this blueprint; it really is just a collection of some variables for the use of the template. But if you now click the Viewport tab at the top, you can see just what some of these variables do. For example, on the right in the Details tab, there should be an open flyout labeledCamera. Under this, the first variable is Base Turn Rate with a greyed-out value of 45.0. In code, this is used to determine how fast our character can turn, but it can't be edited. Let's go see why.

Switch back a moment and look in Visual Studio at MasteringCharacter.h. Down in one of the class' public sections, you should see the following lines:

/** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category=Camera)floatBaseTurnRate;

The UPROPERTY macro is the method in which a C++ variable is bound into a blueprint class, where it can be seen and/or edited. In this case, the flags specified in the VisibleAnywhereBlueprintReadOnly macro are why we can view it in the blueprint, but not edit it, and theCategory=Camerais why it is under the Camera flyout. Variables are automatically displayed in blueprints based on their camel case from C++, so each capital letter makes a word in the blueprint representation, such as BaseTurnRate, in our case. In the MasteringCharacter.cpp file, you can see in the constructor thatBaseTurnRate = 45.fis specified, hence its value is shown in the editor. Again, this will all be used more and more, but a quick overview is needed for the changes that we will make shortly.

Our next steps are going to create a build of our game in the editor, so we will mention again the issues that will arise from having both VS 2015 and VS 2017. If you do not have VS 2015 installed and only use VS 2017, feel free to skip to the steps past this paragraph.

To force everything to open in Visual Studio 2017, follow two steps. First, in the project's file from GitHub, you will see instructions on how to make a batch file, or use the same line by copy-pasting in a command prompt, to generate your project files in VS 2017 from Explorer. In addition, when the editor generates these files, as noted, it will also default to VS 2015, which can be very annoying if you have both IDEs installed, as you may be working in VS 2017 and then the editor will make a build and try to open your project in VS 2015! You will want to go to the Settings tab at the top of the editor, open Project Settings, then scroll down under Platforms to the Windows flyout, as shown in the following screenshot:

Select Visual Studio 2017 as the compiler, as shown in the preceding screenshot. This should fix the problem of unwanted VS 2015 project files once and for all. This is what is checked in to GitHub, and if you are using only VS 2015 or don't want this behavior, just go to that same Compiler Version line and set it to Default or explicitly back to 2015.


So, back in the main editor window, we will add our new class, derived from MasteringCharacter, by going through the following steps:

  1. From the top menu bar, click File and select New C++ Class.
  2. In the Choose Parent Class window, click the Show All Classes box on the top right.
  3. In the Search field, start typing MasteringCh until it shows only MasteringCharacter, and then click on this option.
  4. Make sure that the Selected Class field reads Mastering Character and click Next.
  5. Change its name from MyMasteringCharacter to StealthCharacter and click Create Class.


In step 1, note that you can also access the New C++ Class option from the popup by simply right-clicking in a normal content browser window. Also, in step 2, over time it will just become a habit for you to always immediately click the Show All Classes box. It is nice that Epic Games filters it to some useful classes by default for new users, but as projects grow, you are typically using your own custom classes far more than these.

The editor should then tell you that it is compiling the new C++ code, and notify you when it has finished successfully on the bottom right. One very important note to bear in mind with this hot-reload concept is that if you now return to Visual Studio, it will want to reload the game project solution. This will prompt you to stop debugging, and if you say yes, it will close the editor! A technique I frequently use is just to attach and detach the debugger to the editor as needed. In VS, under the Debug menu is the Detach All command (I like this bound to Ctrl + D). This allows the editor to continue, and you can reload the solution safely as many times as needed. Once you want to debug some code, just reattach it to the running editor. To do this, go back to Debug and Attach it to Process (I like this bound to Alt + D). Click in the big field of Processes, and just tap the U key, and look for UE4Editor.exe. Double click this, and you are right back to debugging.


Editing our class in VS and hot-reloading the editor

So, now that our class is added with the MasteringCharacter as its parent, let's edit it in C++ and see our changes over in the editor. I suggest detaching the debugger as described in the last paragraph, but stopping debugging and restarting the editor is not a problem if you decide to do that. If you do detach, note that you need to right-click on the Mastering project in the solution explorer, select Unload Project, and then right-click it again and click on Reload Project to make sure that everything matches the current state (this is much faster than closing and reopening VS). In the solution explorer, you can now find the StealthCharacter.h and .cpp files under Source/Mastering. Open these. There's not much to them yet, but let's quickly add a new variable so that we can go look at it in the editor later. Add the following lines in the StealthCharacter.h file after theGENERATED_BODY()line:

public:/** Modifier to our turn and pitch rate when in stealth mode */UPROPERTY(EditAnywhere,BlueprintReadWrite,Category=Gameplay)floatStealthPitchYawScale=0.5f;

Back in Visual Studio, we will add the following to StealthCharacter.h after the StealthPitchYawScale variable that we added earlier:




Here, we are following the patterns from MasteringCharacter, which you can study further, but the short version is that we will bind a new input to two functions (Stealth and UnStealth), then override a base class's functions for using yaw and pitch input to slow these down by our scale. We will do this by adding the following code to StealthCharacter.cpp:

voidAStealthCharacter::SetupPlayerInputComponent(UInputComponent*PlayerInputComponent){// Bind jump eventsPlayerInputComponent->BindAction("Stealth",IE_Pressed,this,&AStealthCharacter::Stealth);PlayerInputComponent->BindAction("Stealth",IE_Released,this,&AStealthCharacter::UnStealth);Super::SetupPlayerInputComponent(PlayerInputComponent);}voidAStealthCharacter::AddControllerPitchInput(floatVal){constfloatfScale=bIsStealthed?StealthPitchYawScale:1.0f;Super::AddControllerPitchInput(Val*fScale);}voidAStealthCharacter::AddControllerYawInput(floatVal){constfloatfScale=bIsStealthed?StealthPitchYawScale:1.0f;Super::AddControllerYawInput(Val*fScale);}voidAStealthCharacter::Stealth(){bIsStealthed=true;Super::Crouch();}voidAStealthCharacter::UnStealth(){bIsStealthed=false;Super::UnCrouch();}


Most of this should be clear to experienced UE4 C++ programmers, but do note that our overridden functions for Stealth and UnStealth call existing functions in the ACharacter class that we distantly derive from. This uses existing mechanics to crouch and uncrouch our character, saving us the trouble of making these ourselves. You can build the project now, or after adding the following input, which causes an editor restart anyway, so make sure you did indeed save the editor changes that we made!

There are two ways to add our new input binding. The best way is to once again open Project Settings in the Settings tab in the main editor window. From here, scroll to Engine and Input in the flyouts, and you will see a section for Bindings on the right, and under it,Action Mappings. Click the small plus symbol to the right ofAction Mappingsand it will display a new line under it. We will rename theNewActionMapping that it added to Stealth, and then we will click the small plus symbol to the right of our newStealthline. Click theNonedrop-down menu and scroll down toLeft Shift, as shown in the following screenshot:


We have now bound the action named Stealth to the left Shift key of the keyboard. This will add a line to the game's /Config/DefaultInput.ini file and update the running editor version at the same time. If you were to instead manually add this line right at the top after [/Script/Engine.InputSettings] (that is, +ActionMappings=(ActionName="Stealth", Key= Left Shift)) and then save that file, the engine will not automatically reload the .ini files, which requires the relaunching of the editor to pick up the changes, if you were to modify it this way! So, always remember to try to edit settings from the Settings window, and if you do modify things in a .ini file, always remember to restart any running editor or standalone versions of the game on your PC to pick those up.

We need one last change in our FirstPersonCharacter blueprint to bring things all together, so open it in the full blueprint editor window again. At the bottom left, under its Components tab, is CharacterMovement (Inherited). Click on this. There are now many properties on the right, but scroll down until you see the Nav Movement flyout and open it. At the top, there is the Movement Capabilities flyout, and in that we need to check the Can Crouch checkbox so that it is true. Note that the Compile button near the top left went from having a green checkmark to having an orange question mark. Click the Compile button to update the blueprint with this change and press Ctrl + S again to save.

Now, when running the game, note that when you press and hold Shift, the player's perspective moves down a small distance, which is set by a couple of other existing blueprint parent class variables, and our turn and pitch speed is slow down by our StealthPitchYawScale. Success! Now, feel free to modify the pitch and yaw scale value, even as the game is running, and see how much we speed up and slowed down while stealthed. This is also a great time to set some breakpoints in our functions and just step through how things are working on the C++ side, but at this stage, our mechanic is in and proven.



In this chapter, we have gone from having potentially no engine, zero source code, and no projects to having a local build of the UE4 engine and an FPS project of our own, and added code and overriding functions to add new gameplay to it. This is a great start, and gets us past many of the hurdles in making games and gives us a great foundation to build upon in subsequent chapters.



Next, we'll be looking much more in-depth at controls and improvements we can make on the basics that we mentioned in this chapter. We will also learn how to add some more game features, including inventory and weapon pickups. After that, there will be a much more in-depth discussion of blueprints and what they do for us, why they are so valuable, and when they can be a problem. Rounding out our initial efforts in this section, we will look at the UI, loading and saving, and adding an AI creature, before we quickly accelerate into several more advanced and varied topics in the following chapters!



Work through the following questions to test what you have learned:

  1. What are some advantages to building the engine from source code?
  2. Where is the source code for UE4 found?
  3. What step always needs to be done after getting any updated version of UE4 before building anything?
  4. How are variables exposed in the blueprint declared in C++?
  5. How do we quickly add and test our functionality without needing to create a new blueprint in the editor?
  6. Why is DebugGame a good choice to use as your configuration during development?
  7. Why is requiring changes to .ini files in order to add new features a poor choice?
  8. When changing a blueprint property, what step do you have to perform before saving it?

About the Author

  • Matt Edmonds

    Matt Edmonds has been a lover of games for as long as he can remember, and a professional maker of PC, console, and mobile games since summer 2000. Having graduated with a degree in physics and mathematics, and while doing graduate studies in computer engineering, it became clear all of Matt's free time was going toward learning the technical and creative skills to build amazing 3D games. After making games on his own for around a year, he finally got a break after showing his work making a real-time strategy game in an open source 3D engine with Surreal Software and has never looked back: he now leads teams in creating amazing titles across generations of hardware. With a love of Unreal and 7 years of professional experience with it now, this book is a testament to that passion.

    Browse publications by this author

Latest Reviews

(1 reviews total)
top material in up to date tutorials. love your books and courses ! thank you!

Recommended For You

Book Title
Access this book, plus 8,000 other titles for FREE
Access now