Chris McCole

View Original

Unreal C++ Tips

Hey there! I just want to get a quick intro out of the way, and explain a bit of the purpose and inspiration behind this post. So first of all, I am a relatively new game developer, and most of my experience (~6 years) has been working inside of Unity. However, over the last year or so I have been getting more and more acquainted with Unreal and developing in C++. You may recall my Making an FPS in Unreal Engine 4 Devlog which I posted in August of 2020, where I was just starting to dip my toes in. Now, as I work at Gossamer Games as the Lead Programmer, we have been working heavily in Unreal to release our next original title in October of 2021.

This post has been inspired by the lack of resources in Unreal C++, as well as the poor documentation provided by Epic. Most of the time, you learn about something by happenstance. Only by delving deep into the internet or looking at engine source code can you really learn more about it. So far, my experience of programming in Unreal has been amazing when I know what I’m doing. The main drawback has been learning the Unreal jargon and syntax. Almost all of the problems I encountered when learning were on the Unreal side, as opposed to the C++.

I want this post to be a living reference for some tips on getting started in C++ in Unreal. I also will talk about some “features” or techniques that I learned that really helped the game programming or my productivity.

Content :

  1. C++ With Blueprints

  2. Engine Won’t Open

  3. Compilation Time

  4. Working With Other Modules Or Plugins

  5. Gameplay Tags

  6. SubSystems

  7. Widgets in Cpp

  8. Editing Plugin or Engine Code

  9. My Goto Resources

    1. Dynamic FString Printf

    2. Converting Between FString, FText, FName, int and float

    3. Jolly Monster Studio

    4. Tom Looman

    5. Creating Custom Editor Module

See this content in the original post

C++ with Blueprints

I imagine most people will be working with C++ as well as blueprints. I know I am, as nobody else on my team knows how to use the C++, and will try and interact with my code from blueprints. Here is my take on C++ and Blueprints, I pretty much hate it. Here are some of my reasons real quick:

  1. I think that for C++ to work with blueprints it takes much space and time and initial startup learning to get your code to interact properly.

  2. If you create functionality, base classes, structs or enums in the GUI or blueprints, these will not be accessible in C++

    1. IMPORTANT!!! NEVER make a struct or enum in the GUI, if you ever want it inside of C++ code you will not be able, and will need to remake it. However, that means it’s a new type and so all of your blueprint code has to be updated to use the new type. If you had any structs initialized in editor, looks like your going to have to copy and past it all across!

  3. Blueprints make for fast prototype/iteration time, which makes them favorable for first development, but then when you want to tighten it all down, you are going to have to convert it all over to C++ anyway.

  4. Blueprints, if they are anything more than very basic, get unwieldy very fast and look a mess.

  5. Blueprints don’t support things like a dictionary of arrays, or 2D arrays.

  6. Blueprints don’t support operator overloading or method overloading.

  7. Every once in a while I am working in blueprints and am struggling, only to find out that something I needed isn’t supported.

  8. Blueprints are objectively worse in terms of optimization

So I don’t like it, but that doesn’t mean you won’t! But regardless your team will probably still want to use it, and in all actuality, it does make for some nice prototyping or development of small or simple tasks.

So, in order to work best across these two mediums I have some tips here…

  1. As I said above, always define your enums, structs and interfaces in the C++, I know it’s a pain, but you’ll be happy later.

  2. Along with 1, it’s a great idea to define all of your base classes in C++ as well, get as many function definitions and variables in there and use the blueprint to implement them.

    1. The main reason for this, is that when working in C++, if you for instance want a coin to tell the main character to increase their score when they step on it, this will be impossible if the main player is defined in blueprint. So then, to get this functionality, you will need to make a C++ base class for your main character. Change the main character’s parent. Put in the function call or variable that you need to call in the main character inside the C++. Change the main character blueprint to use the new variable/function. Go back to the coin and call the function.

  3. Use your UPROPERTY, UFUNCTION, UCLASS, USTRUCT, UENUM, and UINTERFACE macros well.

    1. UPROPERTY is for attributes, you can say things like “BlueprintReadOnly”, “BlueprintReadWrite”, “EditAnywhere”, “VisibleAnywhere”. These determine runtime read/write privileges from blueprint, as well as if you can edit the values from the details panel. You can also define : Category = “CategoryName” . This will show the variable under a dropdown category with the name that you had given it.

    2. UFUNCTION is for functions, you can specify “BlueprintCallable”, “BlueprintNativeEvent” “BlueprintImplementableEvent” to specify if it is accessible by blueprints, if it is implemented in C++, but the Blueprint can override the functionality, or if it is a blueprint event that will not be implemented in C++, or.

      1. NOTE: When providing an implementation that can be implemented in C++ or Blueprint, you must have two function definitions.

        1. One definition is the normal function

        2. The second is the _Implementation of the actual function.

        3. Here is an example, of an implementable event in C++ or blueprints

          UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Interact")
          int GetInteractionPriority();
          virtual int GetInteractionPriority_Implementation() override;

    3. USTRUCT and UENUM can use BlueprintType to be able to instance these in the Unreal GUI which is quite useful.

      1. Side note, for Structs in particularly, it’s often beneficial to derive your struct from the FTableRowBase class (found in #include <Engine/DataTable.h>). This will let your struct be a base for a data table.

      2. For Enums you must derrive from type uint8

    4. UINTERFACE should have MinimalAPI as well as Blueprintable defined.

      1. Whenever making interface you need two pieces, the UInterface class that derives from UInterface. As well as the IInterface.

Example Interface:

#pragma once

#include "SavableActor.generated.h"

UINTERFACE()

class MYPROJECT_API USavableActor : public UInterface

{

GENERATED_BODY()

};

class MYPROJECT_API ISavableActor {

GENERATED_BODY()

public:

UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Savable")

void SaveActor();

UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = >"Savable")

void ActorLoad();

};

  1. When learning, I often found it useful to make a piece of functionality in Blueprints to see how Unreal called the function. As blueprints has as a fast, context-sensitive menu, you can find functions quickly. Then once you know the name, look that up on the Unreal documentation.

See this content in the original post

Engine Won’t Open

You made some bad code that is running at Engine startup. The way Unreal actually works, is that the Constructors are ran when the engine starts up and never again, copies of this one instance are made off of the original. You will have to edit the code to try and fix your error and then re-open the project.

To get the error information, you will have to find it in the log file. This is going to be in a log file at {Project_Directory}/Saved/Logs/ it is probably going to be the one that was modified last. The name of the file will most likely be {ProjectName}.log

  1. I have learned that this is not where log files are stored on Mac Operating systems. You’ll have to Google around for that one.

This has also happened for me, when I had code that ran fine on my machine, and my co-worker could not launch the engine. It turned out that what I was doing was fine in the Visual Studio 2017 compiler, but 2019 sure didn’t like it and refused to compile. So make sure your whole team is synced up on your compiler version!

See this content in the original post

Compilation Time

One of the first things I noticed when working in Unreal C++ was how long it took to compile my code. I want to say it typically took anywhere between 5 and 30 minutes to change a single line of code in a single file. This killed my flow and made me feel even worse for small errors when I was getting started.

To fix the slow compilation times the real problem is if you have Unreal installed on your hard disk as opposed to an SSD. The project that you’re working on ALSO has to be installed on an SSD. The main reason for this, and the main way I discovered this, was that when I looked at my Task Manager when compiling or building the project, I saw that my CPU utilization was extremely low, when looking at the disk usage, it was using 100% of my hard disk. This was limiting my speeds that I could write, when switching over to SSD, I was able to get my CPU up to 100% utilization.

See this content in the original post

Working With Other Modules Or Plugins

Let’s say that you download a Plugin that has dialogue functionality, and you want to call into it with C++ to ask it what the dialogue is at the current time. This may seem impossible at first, as you can’t figure out what the include path is to the plugin! And without the include file, you aren’t able to access any of the methods that the Plugin supplied you.

Well, this is actually false, you can work with other Plugins or Unreal Modules that are not included by default. The method to interact with these is not well explained, and is quite obtuse. Basically, the code that you write for your game is in a module. You declare what other outside modules you will be working with and using. The place that you declare this is in your {ProjectName}.Build.cs file. This lives inside of the source folder of your project {PROJECT_DIR}/Source/{ProjectName}/{ProjectName}.Build.cs

If you open this file, you will see a listing of “PublicDependencyoduleNames” in here will be things like “Core”, “Engine”, etc. Basically, you need to add on to this array, with the name of the module that you want to interact with. Don’t know the name of the module? Well, finding that isn’t too great either. If it’s a plugin that you’re working with it will be installed in one of two potential locations. It can be installed in the Engine, this makes plugins available to multiple projects while only needing one install location. And the other potential location is in your Projects Plugins folder.

Once you find out which directory the Plugin is installed in, go ahead and click on the {PluginName}.uplugin file, this will list all of the Modules included in the plugin and gives each a Name field. You can use that name inside of your public dependency modules.

If you are looking for the module of something built into Unreal, then it would be best to look at the documentation. The Gameplay Tags documentation here will tell you that it lives in the GameplayTags module.

See this content in the original post

Gameplay Tags

Gameplay tags are a type in Unreal that is built in. Basically it is a glorified string, it really acts much more like an enumerator that you can add to from the inspector. Gameplay tags can be used all over, and currently are in our game. For our game, I developed a dialogue tool, with this you can tag characters in the dialogue, set what animation they should use when saying that dialogue, what quest the dialogue is associated to, what item the character needs in order to trigger that dialogue, etc. All of these are handled with Gameplay tags.

For the associated character, for instance, we have a gameplay tag to represent this such as Character.PBK. Then I can go to the character’s Blueprint, and on their Dialogue Participant component, I can set their character tag to the same thing in order to be able to reference them later.

The interface for creating Gameplay Tags is super easy and straight forward, and they are really convenient to work with.

See this content in the original post

SubSystems

Unreal has these things called SubSystems. Basically you can define a class to be a specific kind of subsystem, and then it is always alive and initialized and accessible throughout the lifetime of that subsystem.

There are 4 kinds of subsystems:

  1. Engine (Engine lifetime)

  2. Editor (Editor lifetime)

  3. GameInstance (Game instance lifetime)

  4. LocalPlayer (share lifetime of local players)

Now to be perfectly honest with you, I have only ever used GameInstance, as you can probably tell, that’s the most useful. GameInstance works great at housing functionality that you want setup, and to be able to access in a sort of Singleton structure, and it lives throughout the whole game’s lifetime. Currently, I have used this for a dialogue manager, as well as for a score manager. I know that many people use this to make save managers as well as it will keep all of the data, regardless of loading between levels.

See this content in the original post

UI with C++

Working with Unreal Blueprint Widgets in C++ can be a HUGE pain. Especially when just trying to simply link into widgets that you want defined and positioned inside of Unreal. Lucky for us there is one magic keyword that Unreal has given us to make this whole process easier. And that’s the “BindWidget” specifier on a UPROPERTY Macro. You can use it as such.

UPROPERTY(meta=(BindWidget))   UTextBlock* dialogueBox;

Then, when creating your widget, simply drop in a TextBlock (or whatever type you defined in cpp), and make sure to name it EXACTLY as it is named in cpp. When compiling the widget, it will be sure to tell you if it was expecting a variable with a specific name and type in the cpp. This makes editing and managing UI in cpp so much more manageable.

There are also specifiers for the following. BindWidgetOptional (for optional bindings, I use for editor only debugging components), BindWidgetAnim (for widget animations), and BindWidgetAnimOptional (an optionally added widget animation).

When these don’t work out for you, and you need some other way to setup references, I typically define a BlueprintImplementableEvent called “SetupCppReferences” or something similar. And then in the Construct function, I make sure to call this function in the blueprints.

See this content in the original post

Editing Plugin or Engine Code

So I have been developing a plugin for Unreal to handle dialogue. I think that this experience has been VERY different from working with regular game code. This is because the plugin code runs within the engine as opposed to on top of the engine with the rest of your game code. This means that you can’t make changes to the game and then see it in editor without doing the following:

  1. Close the editor

  2. Regenerate Visual Studio Project Files

    1. May want to delete the Binary and Intermediate folders within your plugin folder

  3. Rebuild the project and see if it opens

  4. If it doesn’t open, you want to see the errors, these are going to be in a log file at {Project_Directory}/Saved/Logs/ it is probably going to be the one that was modified last. The name of the file will most likely be {ProjectName}.log

    1. I have learned that this is not where log files are stored on Mac Operating systems. You’ll have to Google around for that one.

This process is quite annoying. So I actually setup a build.bat file that I can run to do all of this for me. I highly recommend this approach. I also use the 4Coder IDE when developing my plugin code, and from there I can press Alt + M and it will automatically build the project. Now that’s speedy!

See this content in the original post

My Goto Resources:

See this content in the original post

Ben UI All UPROPERY Specifiers

I often need to lookup the UPROPERTY or UFUNCTION specifiers, and Unreal’s documentation actually doesn’t list everything! And when they do list something, it doesn’t have as good, or as detailed as documentation as Ben UI’s version listed here. For sure check it out, their site has ton’s of great information about Unreal. Checkout their “All UFUNCTION specifiers” page as well!

Ben UI All UPROPERTY Specifiers

See this content in the original post

Dynamic FString printf

I often struggle at remembering how to print a debug message to the screen, with dynamic text replacement from a variable and here is the page I have bookmarked for me to visit all the time.

https://forums.unrealengine.com/t/how-to-print-strings-in-c-console/48777/2

See this content in the original post

Converting Between FString, FText, FName, int and float

Another thing I can never remember is how to convert between all these string types! Another bookmark for you:

https://docs.unrealengine.com/4.26/en-US/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/StringHandling/

See this content in the original post

Jolly Monster Studio

One of the best places to get simple, straight forward unreal tutorials in c++. And they also post to Youtube!

http://jollymonsterstudio.com/category/development/unreal/

https://www.youtube.com/channel/UC9EudUNDcymyYavhT0JYCSA/featured

See this content in the original post

Tom Looman

I somehow never found this creator, however, after recently discovering them, they are one of my new favorite places to get tutorial content!

https://www.tomlooman.com/

See this content in the original post

Creating Custom Editor Module

I was able to create a custom editor module when making my own dialogue system for our game Howloween Hero. However, it was a huge struggle trying to find out how to do this, and I don’t think it would have been possible without the help of this tutorial.

https://www.orfeasel.com/creating-custom-modules/


If you found this tutorial helpful and want to help support me in creating this content that I host and publish for free, please consider contributing to my Patreon or Ko-fi!

See this form in the original post