Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Game Development Patterns with Unreal Engine 5

You're reading from   Game Development Patterns with Unreal Engine 5 Build maintainable and scalable systems with C++ and Blueprint

Arrow left icon
Product type Paperback
Published in Jan 2024
Publisher Packt
ISBN-13 9781803243252
Length 254 pages
Edition 1st Edition
Languages
Arrow right icon
Authors (2):
Arrow left icon
Stuart Butler Stuart Butler
Author Profile Icon Stuart Butler
Stuart Butler
Tom Oliver Tom Oliver
Author Profile Icon Tom Oliver
Tom Oliver
Arrow right icon
View More author details
Toc

Table of Contents (16) Chapters Close

Preface 1. Part 1:Learning from Unreal Engine 5
2. Chapter 1: Understanding Unreal Engine 5 and its Layers FREE CHAPTER 3. Chapter 2: “Hello Patterns” 4. Chapter 3: UE5 Patterns in Action – Double Buffer, Flyweight, and Spatial Partitioning 5. Chapter 4: Premade Patterns in UE5 – Component, Update Method, and Behavior Tree 6. Part 2: Anonymous Modular Design
7. Chapter 5: Forgetting Tick 8. Chapter 6: Clean Communication – Interface and Event Observer Patterns 9. Chapter 7: A Perfectly Decoupled System 10. Part 3: Building on Top of Unreal
11. Chapter 8: Building Design Patterns – Singleton, Command, and State 12. Chapter 9: Structuring Code with Behavioral Patterns – Template, Subclass Sandbox, and Type Object 13. Chapter 10: Optimization through Patterns 14. Index 15. Other Books You May Enjoy

Translating back from Blueprint to C++

Equipping yourself with tools to translate back from Blueprint to C++ is the smart thing to do, not only for the everyday fixes as mentioned previously, but also for the triple-A setting in a large company. A typical Unreal mechanics development pipeline at a large studio might follow the following process:

  1. A designer has an idea for a mechanic and is given time to prototype it in Blueprint as a proof of concept.
  2. This mechanic is tested to see if it should be developed further.
  3. If it receives a green light, it will be a programmer’s job to convert the prototype into a more robust C++ system.

We’ve covered the tools for designing C++ systems to work with Blueprint effectively, but when faced with the aforementioned situation, how do you take another person’s vision and translate it into something that works efficiently yet doesn’t lose what made it good? Well, the obvious answer is to directly translate it. Node for node. That process is easy, as nodes in Blueprint are quite literally just C++ functions that you have to find in the engine source. Let’s take a closer look:

  1. The first step is to hover the mouse over the node. Every node has a Target class, and mousing over will tell you what that is.
  2. Next, we go to the Unreal Engine docs (https://www.unrealengine.com/en-US/bing-search?) and search for U< Target class name>::<Node name with no spaces>.
  3. The Unreal docs page for the function is likely to be bare, but it will give you the #include directory for the file header containing that function. Once a class has been included, it can be used and explored via autocompleting a dot accessor.

Important note

If the target is Actor, then it will have an A instead of a U at the beginning, as shown in the example in Figure 1.7. This is one of the oddities of UE5; each time there is one, it will be mentioned in a box like this.

Figure 1.7 – Showing the process from node to Unreal C++ documentation

Figure 1.7 – Showing the process from node to Unreal C++ documentation

This process may seem tedious but after a while of searching different things, you will start to see patterns and be able to work out where functions are likely to be. Each node with an execution pin (the white arrow) then becomes one line of code with input pins forming the function arguments, and output pins are generally the return type (multiple of which would form a struct).

Tip

Reading through the following headers will be useful for mastering the translation process as they are the most frequently used: AActor.h, UGameplayStatics.h, and UkismetSystemLibrary.h.

The next question is, how do you know where to leave the line between C++ and Blueprints? Theoretically, you could make everything in C++, but as we’ve already shown, that is not a good idea for teamworking reasons. The answer has already been hinted at, but generally, you want everything visual or not to do with the gameplay mechanics to be Blueprint-based. Where that line exactly sits is up to interpretation and not worth agonizing over.

Worked example

To cement this theory, let’s work through an example. In Figure 1.8, you can see an example Blueprint system designed to increment an integer when it is overlapped by a projectile; then, once it reaches 10 overlaps, it will play a sound and unhide a particle effect:

Figure 1.8 – A series of Blueprint nodes in a basic function; this piece of Blueprint has been arranged using a reroute node for readability but would normally be laid out more linearly

Figure 1.8 – A series of Blueprint nodes in a basic function; this piece of Blueprint has been arranged using a reroute node for readability but would normally be laid out more linearly

First, we need a C++ class for this to inherit from, and seeing as it is called BP_Target, we can name it Target. The Target class will need some variables; we can tell from the event that there is some kind of collision component named TargetCollision, which has its overlap event bound to this function. As a component, it needs to be stored in a pointer; otherwise, we would be referencing the class, not an instance. We also need an integer named TimesHit. As discussed prior, mechanics are made by a team of programmers, designers, and artists. Linking the right particle system for user feedback is a designer’s job, so we’ll leave that as Blueprint for now, but we do need a way to fire the Blueprint side, so a BlueprintImplementableEvent will be needed. With that in mind, the header for our new class will look something like this:

Target.h

#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Target.generated.h"
class USphereComponent;
UCLASS(Abstract)
class EXAMPLE_API ATarget : public AActor
{
    GENERATED_BODY()
    UPROPERTY(EditDefaultsOnly)
    USphereComponent* _TargetCollision;
    int _TimesHit;
public:
    ATarget();
    UFUNCTION()
    void OnTargetCollisionBeginOverlap(AActor* OtherActor,
        int32 OtherBodyIndex, bool bFromSweep, const
        FHitResult& SweepResult);
    UFUNCTION(BlueprintImplementableEvent)
    Void TenHitVisuals();
};

Important note

Notice how the UCLASS() call includes the Abstract tag. This will stop designers from accidentally creating instances of your C++ classes that have not had any visuals set up.

The next step is to populate the function bodies:

Target.cpp

#include "Target.h"
#include "Components/SphereComponent.h"
#include "ExampleProjectile.h"
ATarget::ATarget()
{
    _TargetCollision =CreateDefaultSubobject <USphereComponent>
        (TEXT("TargetCollision"));
    _TargetCollision->SetupAttachment(RootComponent);
    _TargetCollision->
        OnComponentBeginOverlap.AddDynamic( this,
        &ATarget::OnTargetCollisionBeginOverlap);
    _TimesHit = 0;
}
void ATarget::OnTargetCollisionBeginOverlap
    (UPrimitiveComponent* OverlappedComponent, AActor*
        OtherActor, UPrimitiveComponent* OtherComp, int32
        OtherBodyIndex, bool bFromSweep, const FHitResult&
        SweepResult)
{
    ExampleProjectile* otherProj =
        Cast<AExampleProjectile>(OtherActor);
    if (otherProj != nullptr)
    {
        _TimesHit++;
        if (_TimesHit == 10)
        {
            TenHitVisuals();
        }
    }
}

The constructor is going to be standard, creating the default sub-object for the collision component and binding the overlap function to that component’s overlap event (OnTargetCollisionBeginOverlap). In the overlap function, the cast node becomes a cast to a temporary “cache” variable with an if statement to check its value against nullptr. _TimesHit can then post increment, and the branch converts to an if statement which, if passed, will call the BlueprintImplementableEvent to pass the signal to the Blueprint child class.

Note

You are not required to build this example; it is here for reference only.

There will be plenty more examples of Blueprint to C++ conversion throughout the rest of this book, but if you would like to see some first-party examples, the template projects created by Epic can be loaded in both C++ and Blueprint versions.

You have been reading a chapter from
Game Development Patterns with Unreal Engine 5
Published in: Jan 2024
Publisher: Packt
ISBN-13: 9781803243252
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €18.99/month. Cancel anytime