Unreal Engine: Difference between revisions

From Andreida
No edit summary
 
(212 intermediate revisions by the same user not shown)
Line 1: Line 1:
= Installation =
Currently using UE4 (4.10.4)

* UE5: https://www.unrealengine.com
** Do NOT install 5.3 if you don't have VERY good reasons
** DO install 5.4+
* ASP.NET Core Runtime 3.1.32
https://dotnet.microsoft.com/en-us/download/dotnet/3.1
https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-3.1.32-windows-x64-installer
* Visual Studio 2022: https://visualstudio.microsoft.com/downloads/
** Workloads / Desktop development with C++ (was suggested by Visual Studio when I loaded a UE5 project)
** Workloads / .NET desktop development (was suggested by Visual Studio when I loaded a UE5 project)
** Workloads / Game Development with C++
*** don't unselect anything
*** Windows 10 SDK (1.0.20*)
*** Unreal Engine Test Adapter
*** Unreal Engine uproject support
** Individual components / .NET 6.0 Runtime (Long Term Support) (was suggested by Visual Studio when I loaded a UE5 project)
** Individual components / .NET Framework 4.8.1 SDK (or higher)
** Individual components / .NET Framework 4.6.2 targeting pack (was suggested by Visual Studio when I loaded a UE5 project)
** Individual components / MSVC 143 - VS 2022 C++ x64/x86 build tools (v14.36-17.6 or newer?) (was suggested by Visual Studio when I loaded a UE5 project)
** After you install VS 2022, look in the VS Installer at the "Update" button. Enabled? UE5.4+? Yes, update... no problem.
* Unreal Engine Visual Studio Integration Tool plugin: https://aka.ms/vsituemarketplace (repeat after new engine installation, as of 2024-05-28: available for 5.4)
* naming convention checker: ".editorconfig" parallel to your .uproject file. <br> Content: https://raw.githubusercontent.com/microsoft/vc-ue-extensions/main/Source/.editorconfig
* HLS configuration file: "shadertoolsconfig.json" parallel to your .uproject file. <br> Content: automatically created, defaults to:
<pre>
{
"hlsl.preprocessorDefinitions": {
},
" hlsl.additionalIncludeDirectories": [
],
"hlsl.virtualDirectoryMappings": {
}
}
</pre>


= Links =
= Links =


== Blender ==
== Unreal Engine ==

* [https://docs.unrealengine.com/5.2/en-US/recommended-asset-naming-conventions-in-unreal-engine-projects/ Recommended Asset Prefixes]
* [https://www.youtube.com/watch?v=IaU2Hue-ApI The Unreal Engine Game Framework: From int main() to BeginPlay (video)]
* [https://www.youtube.com/watch?v=JOJP0CvpB8w Multiplayer in Unreal Engine: How to Understand Network Replication (video)]
* [https://forums.unrealengine.com/t/error-compiling-the-automation-tool-after-updating-visual-studio-today-unreal-5-3-2/1393088/30 Error compiling the Automation Tool after updating Visual Studio today (Unreal 5.3.2)]
* [https://www.tomlooman.com/unreal-engine-cpp-guide/ Unreal Engine C++ Complete Guide] (This guy knows what he is talking about, he is not trying things and failing a lot like beginner-me.)
* [https://forums.unrealengine.com/t/mini-tutorial-using-upawnsensingcomponent-in-c/12894 Mini-Tutorial: Using UPawnSensingComponent in C++ (by a deleted user?)
* [https://dev.epicgames.com/documentation/en-us/unreal-engine/asserts-in-unreal-engine UE Asserts]

= Blender =


* [http://gryllus.net/Blender/3D.html Blender 3D Design Course]


* Export Options (so that the object is not lying on the side after Export/Import):
* Export Options (so that the object is not lying on the side after Export/Import):
Line 18: Line 60:
= C++ =
= C++ =


<blockquote style="background-color: lightgrey; border: solid thin grey;text-align: center;">
=== Variable names ===
the First Amendment to the C++ Standard states: <br>
"The committee shall make no rule that prevents C++ programmers from shooting themselves in the foot." <br>
-- Thomas Becker
</blockquote>

<blockquote style="background-color: lightgrey; border: solid thin grey;text-align: center;">
[...] C++ is for people that punch bears and eat concrete and track their own memory. <br>
the bottom line is, if you can't do these things; go use C# <br>
-- zap0
</blockquote>


== Variable names ==
If you want to use real variable names but have nice names in the UE editor too, then use meta/DisplayName
If you want to use real variable names but have nice names in the UE editor too, then use meta/DisplayName
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, Meta = (DisplayName = "First Person Camera Component") )
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, Meta = (DisplayName = "First Person Camera Component") )
UCameraComponent* m_pFirstPersonCameraComponent;
UCameraComponent* m_pFirstPersonCameraComponent;


=== owner / client /server ===
== owner / client /server ==
The instance that spawned the class is always ROLE_Authority. If an Actor is spawned on the client, the client is the authority.
The instance that spawned the class is always ROLE_Authority. If an Actor is spawned on the client, the client is the authority.
-- OmaManfred
-- OmaManfred
Line 42: Line 97:
</pre>
</pre>


=== Logging ===
== Logging ==
The following is just a copy/paste/change from the UE4 wiki and was really done from different persons, I am just using the work of different people here.
The following is just a copy/paste/change from the UE4 wiki and was really done from different persons, I am just using the work of different people here.
Put it in a Log.h and include it into your <your_project>.h file after the #include "Engine.h".
Because <your_project>.h is in every of your files, you will now be able to use these macros in every .cpp file.


Put it in a Log.h and include it in .cpp files where you want to use these macros.


<pre>
<pre>
#pragma once
#pragma once


#include "Log.h"
#include "CoreMinimal.h"
#include "Engine.h"
</pre>


<pre>
// macros
// macros
// - LOG_LINE
// - LOG_LINE;
// - PLOG_LINE;
// - LOG -> output log
// - LOG -> output log
// -- LOG("text");
// -- LOG("text");
// -- LOG("text %s %f %d", "text", 1.2, 5);
// -- LOG("textStatic %s %.2f %d", L"textDynamic", 1.2, 5);
// - PRINT -> screen
// - PRINT -> screen
// -- PRINT("text");
// -- PRINT("text");
// -- PRINT("text %s %f %d", "text", 1.2, 5);
// -- PRINT("textStatic %s %.2f %d", L"textDynamic", 1.2, 5);
// - PLOG -> output log + screen
// -- PLOG("textStatic %s %.2f %d", L"textDynamic", 1.2, 5);


#if _MSC_VER
#if _MSC_VER
Line 72: Line 126:


#define LOG_LINE UE_LOG(LogTemp, Warning, TEXT("%s, file: %s, line %d"), FUNC_NAME, *FString(__FILE__), __LINE__);
#define LOG_LINE UE_LOG(LogTemp, Warning, TEXT("%s, file: %s, line %d"), FUNC_NAME, *FString(__FILE__), __LINE__);

//#define LOG_NULL(s, p) UE_LOG(LogTemp, Warning, TEXT("pointer %s %s"),s, (p?TEXT("ok"):TEXT("null") ) );
#define PLOG_LINE \
{ \
LOG_LINE; \
PRINT("%s, file: %s, line %d", FUNC_NAME, *FString(__FILE__), __LINE__); \
}


#define PRINT(format, ...) \
#define PRINT(format, ...) \
Line 86: Line 145:
const FString sMsg = FString::Printf(TEXT(format), ##__VA_ARGS__); \
const FString sMsg = FString::Printf(TEXT(format), ##__VA_ARGS__); \
UE_LOG(LogTemp, Warning, TEXT("%s() : %s"), FUNC_NAME, *sMsg);\
UE_LOG(LogTemp, Warning, TEXT("%s() : %s"), FUNC_NAME, *sMsg);\
}

#define PLOG(format, ...) \
{ \
LOG(format, ##__VA_ARGS__); \
PRINT(format, ##__VA_ARGS__); \
}
}


</pre>
</pre>


=== Am I client or server ? ===
=== Example Usage ===
#include "Log.h"

LOG_LINE;
PLOG_LINE; // still being tested
LOG("I am a line of text in the log,");
PRINT("but me, I am a line of text on the display screen, so there!");

LOG("textStatic %s %.2f %d", L"textDynamic", 1.2, 5);
PRINT("textStatic %s %.2f %d", L"textDynamic", 1.2, 5);
PLOG("textStatic %s %.2f %d", L"textDynamic", 1.2, 5);

FString sPssst("a Secret");
PLOG("I am telling you: %s", *sPssst);

=== Custom Log ===
If you want your own selectable category in the log filter to be able to only show your log messages, then you have to
* add this line in the Log.h above any defines:
DECLARE_LOG_CATEGORY_EXTERN(aProjectLog, Log, All);
* replace all "LogTemp" with "aProjectLog"
* add this line to each .cpp where you want to use these macros:
DEFINE_LOG_CATEGORY(aProjectLog);

You will - in most cases - remove (nearly) all log messages when your code is running well. So... do this only if you need this, not because you think this is the "better" way to use it.

== Am I client or server ? ==
https://answers.unrealengine.com/questions/416305/how-to-know-if-listenserverclient-owner-for-rpc.html
https://answers.unrealengine.com/questions/416305/how-to-know-if-listenserverclient-owner-for-rpc.html


Line 116: Line 206:
</pre>
</pre>


== UI ==
=== UMG with C++ base class ===
I know currently of three types which might be relevant here:
# Canvas: Derive from HUD and overwrite "DrawHUD()"
# Slate: Controls usable from C++
# UMG: visual editor for Slate


* Make sure your <project>.Build.cs has something like
PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
* Normally don't use the first method with drawing directly into a canvas.

=== UMG with C++ base class (old, not verified again, yet) ===
* create a normal UMG widget
* create a normal UMG widget
* create a C++ class with base class UserWidget (UUserWidget)
* create a C++ class with base class UserWidget (UUserWidget)
Line 122: Line 223:
* set the parent class of the UMG widget to your C++ class
* set the parent class of the UMG widget to your C++ class
* in <Project>.Build.cs add "UMG", "SLATE", "SLATECORE":
* in <Project>.Build.cs add "UMG", "SLATE", "SLATECORE":
<pre>
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "UMG" });

PrivateDependencyModuleNames.AddRange(new string[] { });

// Uncomment if you are using Slate UI
PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
</pre>
* put into <Project>.h
* put into <Project>.h
<pre>
<pre>
Line 140: Line 233:


=== SLATE ===
=== SLATE ===
https://wiki.unrealengine.com/Slate_Introduction_%E2%80%92_Basic_Menu_Part_1

The "canvas" in UMG is "SConstraintCanvas" in Slate.
The "canvas" in UMG is "SConstraintCanvas" in Slate.


=== Multiplayer / Sessions ===
== Multiplayer / Sessions ==
Do not search for "multiplayer", search for "sessions".
Do not search for "multiplayer", search for "sessions".
Good tutorial:
https://wiki.unrealengine.com/How_To_Use_Sessions_In_C%2B%2B


This is a Youtube video I found which gives you an overview, so you already have an idea how it works before you start learning the details: [https://www.youtube.com/watch?v=JOJP0CvpB8w Multiplayer in Unreal Engine: How to Understand Network Replication].
= Misc =

== String conversions ==
from: https://docs.unrealengine.com/en-us/Programming/UnrealArchitecture/StringHandling/FString
FString TestHUDString = FString(TEXT("This is my test FString."));
FName TestHUDName = FName(*TestHUDString);
FText TestHUDText = FText::FromString(TestHUDString);

;FName
: text strings optimized for higher performance
;FText
: text strings for displaying information to players that may be localized
: TEXT("CameraBoom") would mark the text for translation and automatically usable with multiple platforms
;FString
: regular mutable text strings (do NOT ask, NO idea what that means, but it sounds really important, right?)

(definitions from "Unreal Engine 5 Game Development with C++ Scripting")

== Classes ==
* You can create and use normal C++, like, create a normal C++ class and use new and delete with it.
* But if you want to use UE stuff, you must use UE stuff and be sure to not mix it with normal C++ handling. This sounds complicated, but it is just a reminder to for example never use "new" for an actor.
* You can create classes however you want:
** Get the UE editor to create them (Slow, but it just works. If you don't know better, use this!)
** Use the UI of your source editor (Visual Studio for example) to create them
** create them manually (I still have to modify the properties of the created .cpp files, not funny)

=== UE classes ===
Please keep in mind that my information might be wrong.

A very common error seems to be the naming of the files.
You have to know that common UE classes have an 'U' in front of the class name and actors have an 'A' there.
So, if you'd like a 'MyFirstActor', then
* the files are MyFirstActor.h and MyFirstActor.cpp
* the class is "AMyFirstActor"
* the generated file is "MyFirstActor.generated.h"

If you think you know what you are doing and use Visual Studio to create a new class "AMyFirstActor" it will default to the file names AMyFirstActor.h and AMyFirstActor.cpp which is wrong. I mean, it is not wrong, but it is not what you need here. :-)

About categories, there seem to be some ... reserved? ones. Whatever the reason, they don't work. I never got the category "Test" to show, there should be others. So, do not use "Test" as category if you have the same effect, just change the category name instead of trying to force it.

==== DLLEXPORT ====
Your classes will be inside a DLL and have to be exported to be usable. If you use UE to create a class you will see something like this:
class P01_TEST_API AMyFirstActor : public AActor
The "P01_TEST_API" between "class" and your class's name is probably just a define like
#define P01_TEST_API DLLEXPORT

Now you ask of course why there is a different define for each project if it is just "DLLEXPORT"?
Good question. Next.
Sorry. I just don't know (yet).

Update:
Ok, I have an idea.<br>
If you want to use the same header files but without "DLLEXPORT", then you just change the define. And that has - of course - to be done per project. So, yes, it does make sense.

==== minimum ====
The minimum of a UE class would be like this:
===== header file =====
<pre>
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyFirstActor.generated.h"

UCLASS()
class P01_TEST_API AMyFirstActor : public AActor
{
GENERATED_BODY()
public:
</pre>

===== Source file =====
<pre>
#include "MyFirstActor.h"
</pre>

===== *.generated.h =====
#include "MyFirstActor.generated.h"
Write it just like that, you don't create it, you don't look into it, you don't really care about it. BUT you have to include it as LAST include file in your header file.

===== UCLASS() =====
This has just to be there. For certain things to work you have to add words inside the brackets.
An example would be:
UCLASS(BlueprintType, Blueprintable)
These words do what they say. You can use the class as a type in a blueprint or you can create a blueprint from this class.

===== GENERATED_BODY() =====
The default for a struct is public and the default for a class is private.
That means "GENERATED_BODY()" in this code
<pre>
class P01_TEST_API AMyFirstActor : public AActor
{
GENERATED_BODY()
</pre>
is private.

Don't think, just put it before any access specifiers, it works.

==== Variables and the like ====
You might want certain functionality from UE for certain enums, member variables or methods. Like.. it should work as expected and not be cleared by the system which seems to be able to be happen to certain UE container classes if you don't make them UE properties.

<blockquote style="background-color: lightgrey; border: solid thin grey;text-align: center;">
If you don't see the changes from C++ in your blueprint, try
"Asset Actions" / Reload
</blockquote>

And if you don't see variables or stuff you would expect to see, right-click into the blueprint's graph and try "get<YourVariable>".

* UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Misc", Meta=(DisplayName="Cool Name"))

===== Enums =====
UE enums must be outside of classes (since 4.12). This means you have to be creative with your naming or will slap yourself if you have two enum types which you called EStatus. (This might not even be possible now.)

Example:
Header, before the class:
<pre>
UENUM()
enum AMySuicideActor_EStatus
{
Task UMETA(DisplayName = "Task"),
Idle UMETA(DisplayName = "Idle"),
};
</pre>

Inside the class:
<pre>
protected:
UPROPERTY()
TEnumAsByte<AMySuicideActor_EStatus> m_eStatus;
</pre>

Inside the .cpp
m_eStatus = AMySuicideActor_EStatus::Idle;

Now, that is nice and all but why would you want it?
BECAUSE!
No, really, you can now change
UPROPERTY()
TEnumAsByte<AMySuicideActor_EStatus> m_eStatus;
to
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "My Tests | Part 1", meta = (DisplayName = "Status") )
TEnumAsByte<AMySuicideActor_EStatus> m_eStatus;
and suddenly you fall in love with UE.
This is an actor, so you can drag it into the world in the UE editor. And then you can see the category "My Tests" and below it the subcategory "Part 1" and inside you see a label "Status" and behind it a combo box with the two possible selections: "Idle" and "Task".

* BlueprintReadWrite: blueprints can read and write this thing/property/variable.
* EditAnywhere: Edit it in the "Details" and (sometimes) in the "class defaults" and .. oehm.. no idea if there are more places.
* Category: The area where this data is put when you look at an instance/class/blueprint of it
* DisplayName: The name which is used to show this data's label (instead of the variable name)

===== Variables =====
You can of course do the same things you did with the enums with variables
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Stats, Meta = (DisplayName = "Armor"))
float m_fArmor;

There you are. Now you can edit the m_fArmor variable of your instance directly in the editor, after you created an instance by dragging the class into the world, of course.

Sounds sweet? It is!

===== Functions =====
You can expose functions like this:
UFUNCTION(BlueprintCallable, Category = "Data Access")
int32 getArmor();

==== Instantiating UE classes ====
===== Actors =====
The most simple code that works is something like
GetWorld()->SpawnActor<AMyFirstActor>();

There are of course multiple ways to do it and just SpawnActor has like 7 or so overloads.

===== UClass =====
If you want to instantiate a U* class instead of an actor then you'll probably be using something like
UAcRandomScaleChange* pAcRandomScaleChange = CreateDefaultSubobject<UAcRandomScaleChange>("RandomScaleChange");
but I can't say anything about it (yet). It works but ... understanding.... hehe.

I found the following sentence, I don't know yet if it is true. But if it is true, you really want to know it:

<blockquote style="background-color: lightgrey; border: solid thin grey;text-align: center;">
CreateDefaultSubobject works only in constructor. Everywhere else use NewObject.
</blockquote>

===== Examples =====
* [[Unreal Engine, from C++ spawn Blueprint inherited from C++ class, very small example]]
* [[Unreal Engine, from C++ add an ActorComponent to an Actor, very small example]]

== Iterating ==
The following code really works. No "GetWorld()", no fumbling and no idea if it has drawbacks.

#include "Components/PointLightComponent.h"

for (TObjectIterator<UPointLightComponent> it; it; ++it)
{
UPointLightComponent* pPlc = *it;
pPlc->SetVisibility(false);
}

== Delegates ==
Methods for delegates seem to need to have the return type "void". So, if you need a return value, use some referenced parameter like
bool& bOk
==== The idea ====
If a class says, "I have delegates, and therefore I am super cool" (anyone played Magicka?)
DECLARE_DELEGATE(FStandardDelegateSignature)
UCLASS()
class XY_API AWithDelegate : public ...

and then has members like
FStandardDelegateSignature m_standardDelegate01;

then another (or the same) class can say, "hey, I want you to execute some code of me if your delegate01 is activated":
AWithDelegate*......->m_standardDelegate01.BindUObject(this, &AThisIsMe::coolFunctionYouShouldCall);

and then a third class can say, "yo my man, if you have something connected to your delegate01, pretty please execute that stuff now":
AWithDelegate*......->m_standardDelegate01.ExecuteIfBound();

You would - of course - not give access to your member variable directly but instead use something like
<pre>
public:

FStandardDelegateSignature& getStandardDelegate01();

protected:

FStandardDelegateSignature m_StandardDelegate01;
</pre>

==== disconnect ====
->getDelegateWithParam02().Unbind();

<blockquote style="background-color: lightgrey; border: solid thin grey;text-align: center;">
Do the connecting in BeginPlay and the disconnecting in EndPlay if you don't know better.
</blockquote>

=== Other types of Delegates ===
==== One Parameter ====
DECLARE_DELEGATE_OneParam(FParamDelegateSignature, int)

FParamDelegateSignature m_ParameterDelegate02;

FParamDelegateSignature& getDelegateWithParam02();

.....->getDelegateWithParam02().ExecuteIfBound(42);

==== Multicast ====
If you use "BindUObject" multiple times on the same delegate, only the last bind will be remembered.
If you want to have multiple listeners at once, you use the multicast delegate:

DECLARE_MULTICAST_DELEGATE(FMulticastDelegateSignature)

FMulticastDelegateSignature& getMulticastDelegate03();

FMulticastDelegateSignature m_MulticastDelegate03;

.....->getMulticastDelegate03().AddDynamic(this, &AMulticastDelegateListener::MyCoolFunction);
.....->getMulticastDelegate03().RemoveDynamic(this, &AMulticastDelegateListener::MyCoolFunction);

.....->getMulticastDelegate03().Broadcast();

===== Example =====
* [https://forums.unrealengine.com/t/mini-tutorial-using-upawnsensingcomponent-in-c/12894 Mini-Tutorial: Using UPawnSensingComponent in C++ (by a deleted user?)

=== Custom Events ===
One class says it will have a custom event "CeBeginOverlap" which is a completely free too choose name at this moment:
DECLARE_EVENT(AMyTriggerVolume, CeBeginOverlap)
UCLASS()
class P02_API AMyTriggerVolume : public AActor

Then it has of course to have that event:
public:
CeBeginOverlap OnBeginOverlap;

Now this class will tell you at some point in time that this event has happened:
void AMyTriggerVolume::NotifyActorBeginOverlap(AActor* OtherActor)
{
OnBeginOverlap.Broadcast();

This is nice and everything, but now we need someone who is interested in that stuff.
There a multiple ways, one would be something like this:
<pre>
Super::BeginPlay();

for (TObjectIterator<AMyTriggerVolume> it; it; ++it)
{
AMyTriggerVolume* pTrigger = *it;
pTrigger->OnBeginOverlap.AddUObject(this, &AYourListenerClass::OnTriggerEvent);
}
</pre>
The advantage would be that you would connect to every source of this type.

Another way would be to have something like this in the header:
UPROPERTY(EditAnywhere)
AMyTriggerVolume* m_pEventSource;
and then set the source in the UE-Editor and use code like this
if (m_pEventSource!= nullptr)
{
m_pEventSource->OnBeginOverlap.AddUObject(this, &AYourListenerClass::OnTriggerEvent);
}

== Enhanced Input ==
* An (U)InputAction is just a name. Like "action1", "jump" or "move". They have no meaning by itself.
** A character might have multiple of these.
* An (U)InputMappingContext has two reasons for existence:
** Map a key/mouse/control to an (U)InputAction
** Collect multiple InputActions
** A (A)PlayerController might manage one or more of these
* A character's "SetupPlayerInputComponent" will connect InputActions to methods.

So you have:
Input -> InputMappingContext -> InputAction -> Method

=== Example ===
* [[Unreal Engine, C++ Enhanced Input, very small example]]
* [https://codingbabble.com/posts/ue5-enhanced-input-in-pure-cpp/ Tutorial for a different way to use it, by Kochab (not verified yet)]

= UE Editor =

== Escape key stops simulation in editor ==
If you want to change this behavior, open "Edit/Editor Preferences" and search for "stop".
Then change under "Play World/Stop" the shortcut "Escape" to whatever you want, for example shift-Escape.

== Details/Text/Line-Break ==
If you are shown a text in the Details tab, chances are you can use shift-return to create a line break.

== Removing projects from "Project Open" dialog ==
Open (use the correct engine version)
%USERPROFILE%\AppData\Local\UnrealEngine\5.3\Saved\Config\WindowsEditor\EditorSettings.ini
and modify/remove
CreatedProjectPaths
RecentlyOpenedProjectFiles

== Volume of Sound after building in Visual Studio ==
* Content Drawer / Settings / Show Engine Content
* Engine / Content / EditorSounds / Notifications / *_Cue
* Volume Multiplier

== Migrating Blueprint which has C++ class as parent ==
=== Variant that works for me ===

==== c++ ====
* copy the c++ *.h and *.cpp files to the other project
* right-click the DLLEXPORT macro (class bla_API YourClass, here bla_API is meant) in one of the copied header files
** select "rename"
*** give the DLLEXPORT macro of your new project
*** skip: yes
*** scop: current project
*** apply
* compare the YourProject.Build.cs between the two projects, add modules as needed
* re-generate or refresh the c++-project from the UE-Editor (probably for the includes in .cpp/properties/nmake)
* make sure the project can compile and link before you do the next steps

==== Blueprints ====
* open "YourNewProject\Config\DefaultEngine.ini"
* goto (or add, but it should already exist)
[/Script/Engine.Engine]
* There might exist two lines which you can just copy/paste for the following
* add the following lines

+ActiveGameNameRedirects=(OldGameName="OLD_PROJECT",NewGameName="/Script/NEW_PROJECT")
+ActiveGameNameRedirects=(OldGameName="/Script/OLD_PROJECT",NewGameName="/Script/NEW_PROJECT")

* Close the UE-Editor with the new project
* Open the UE-Editor with the old project
* Open the UE-Editor with the new project
* in the old project, select the blueprints you want to migrate
** right-click
** asset actions
** migrate
** select the content folder of the new project
* in the UE-Editor with the new project
** open each of the migrated blueprints once
*** compile
*** save

=== Variants that don't work for me and would be so easy to use ===
There should be a better variant, I read you can add something like this

[CoreRedirects]
+ClassRedirects=(MatchSubstring=True,OldName="MyOldProjectName",NewName="MyNewProjectName")
and it should work for the whole project without having to do it for every class.

I read another variant where you do something like
ClassRedirects=(MatchSubstring=True,OldName="/MyOldProjectName",NewName="/MyNewProjectName")

These two variants do either nothing or make my UE-Editor unable to load the project. Too bad, I'd like to have less work. :-(

But you can try them, maybe you are lucky. Or you understand what you are doing and do it right.

= Source control =

Don't use Mercurial (or git) for game development. That would be just plain stupid. </br>
Use Subversion or something like that.


== Source control ==
The minimum you have to put under source control:
The minimum you have to put under source control:
/Config
/Config
Line 157: Line 636:
/Source
/Source
Project.uproject
Project.uproject

Depending on your project:
/.editorconfig
/shadertoolsconfig.json


For ignores, have a look at [[Subversion, svn#svn, ignore|ignoring files with svn]].

== External Actors ==
Under "Content" you will probably after some time see "EXTERNAL_ACTOR" or stuff like that. These are your map's actors, so multiple people can work on different parts of the map at the same time. That is the theory I read. :-)

So, no, don't delete them.

Here is the [https://dev.epicgames.com/documentation/en-us/unreal-engine/world-partition-in-unreal-engine?application_version=5.3 documentation about it].

== Developer Folder ==
If you have the developer folder(s) enabled "Content / View Options / Show Developers Content" then make sure to not reference it from outside when cooking a project.

= Visual Studio =

== Show errors after build ==
Tools / Options / Projects and Solutions / Always show Error List if build finishes with errors

== Generate Visual Studio Project file ==
=== Delete temporary files ===
To get a cleaner project you could create a "delete-temps.cmd" with content like the following (match it with your needs):
<pre>
del *.sln
del .vsconfig
rmdir /s /q .vs
rmdir /s /q Binaries
rmdir /s /q Build
rmdir /s /q DerivedDataCache
rmdir /s /q Intermediate
rmdir /s /q Intermediate
rmdir /s /q Releases
rmdir /s /q Saved
</pre>

=== Generate project file(s) ===
After you cleaned away the trash you can right-click your *.uproject file and select "Generate Visual Studio Project file".
This might remove some problems. Or create new ones. So far it only helped me, but it IS a bit brutal, right?

== Finding the include file for a class ==
* Select the class or just have your cursor inside the name
* Press ctrl+, (press ctrl and "comma" at the same time)
* Double-left-click the entry with the correct looking header file.
* Then you right-click the tab name and select "copy full path".
* Now you include that path and remove the beginning.
** How much to leave... "you much have to learn".

If the includes are correct and you want to see the header of something again:
* Press F12 with your cursor on the class you want to know about to go to the definition.

Just want to switch between header and source?
ctrl-k/-o
Meaning: hold ctrl, press 'k' once, after that press 'o' (letter, not digit) once while still holding ctrl.

=== Example 1 ===
C:\ue\UE_5.4\Engine\Source\Runtime\Engine\Classes\Particles\ParticleSystemComponent.h
Correct include:
#include "Particles/ParticleSystemComponent.h"

=== Example 2 ===
C:\ue\UE_5.4\Engine\Plugins\EnhancedInput\Source\EnhancedInput\Public\InputActionValue.h
Correct include:
#include "InputActionValue.h"

== TODO list / Task list ==
Add a comment like
/// todo: use instead something from algorithm
Menu / View / Other Windows / Task List

Keywords are managed here: Tools / Options / Environment / Task List

("///" instead of "//" because of [[Style guide ad02#comments|Style guide ad02: Comments]])

== Less searching and clicking ==
* In the solution explorer on the left side right-click your game inside "Games" and select "Scope to this"
* Menu / View / Code Definition Window
** Just work normally and observe what you can see in this window depending on your current selection, you will probably be amazed. Or you are using it already since years and don't understand how anybody could not know about it.

= Misc =




Line 170: Line 732:
* Microsoft Public License, or
* Microsoft Public License, or
* Apache License.
* Apache License.

== Other ==

=== Black Screens or flickering/invisible new action popup ===
[https://nvidia.custhelp.com/app/answers/detail/a_id/5157/~/after-updating-to-nvidia-game-ready-driver-461.09-or-newer%2C-some-desktop-apps Disable multiplane overlay]

= Errors =
== Visual Studio ==
=== cannot open source file "CoreMinimal.h" ===
Error List: "Build + Intelli Sense" => "Build Only"

([https://forums.unrealengine.com/t/ue5-c-vs2019-a-new-project-can-not-open-coreminimal-h-and-with-7135-faults/582748/2 source])

I am pretty sure this is NOT a solution but a workaround.

=== Error MSB3073 [...] -WaitMutex -FromMsBuild" exited with code 6 ===

If you want to build with Visual Studio and get something like
<pre>
Error MSB3073 The command "C:\ue\UE_5.3\[...]ShowActor.uproject" -WaitMutex -FromMsBuild" exited with code 6.
</pre>
then you can do this:
* UE-Editor
** Edit / Editor Preferences
*** Live Coding
**** Enable Live Coding: no
** File / Save All

<span style="color: Green">
Yes, you do this change in the EDITOR's preferences and YES, you have to do it for every project and YES, that makes absolutely NO sense at all.
</span>

=== IntelliSense Error: "can't open file" for includes or "red squiggles under my includes" ===
Make sure the .cpp-files have in Properties/NMake:
Include Search Path: $(ClCompile_AdditionalIncludeDirectories)
Copy it from other .cpp-files to be sure to get the correct value for your UE-Version/system.

Or just save everything, close everything, and recreate the c++ files from the .uproject file. That worked like a charm for me when I did not want to modify a lot of .cpp files. (Lazy, HERE?)

=== Can't build Solution ===
* UE / Edit / Editor Preferences / Live Coding / Enable Life Coding: disable
* Use the context menu on your project and select "Set as Startup Project".
* Use "Build <project> (ctrl-B) to build.

This works for me but I am pretty sure there should be a way to have "Live Coding" enabled AND build from Visual Studio. I mean... the UE developers will themselves want to have both options, right? So it should be possible?

Update 1: <br>
I found out that I have to fix the errors in the other (there are ca. 7) projects in the solution to be able to build the solution and to do that I'd have to get the source version of UE. Currently I am very unhappy with all this. A UE5 installation on top of a functioning UE4 installation works. But if you only install UE 5.3 onto a new system, not working :-(

Update 2: <br>
UE 5.4 works pretty well. If you have 5.3, switch to 5.4+, if you are told by someone to install 5.3, ignore him and block him for like ever. And [https://www.reddit.com/r/TwoBestFriendsPlay/comments/108r3ne/most_creative_insults_youve_ever_heard/ curse] him!

Latest revision as of 20:40, 13 June 2024

Installation

 https://dotnet.microsoft.com/en-us/download/dotnet/3.1
 https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-3.1.32-windows-x64-installer
  • Visual Studio 2022: https://visualstudio.microsoft.com/downloads/
    • Workloads / Desktop development with C++ (was suggested by Visual Studio when I loaded a UE5 project)
    • Workloads / .NET desktop development (was suggested by Visual Studio when I loaded a UE5 project)
    • Workloads / Game Development with C++
      • don't unselect anything
      • Windows 10 SDK (1.0.20*)
      • Unreal Engine Test Adapter
      • Unreal Engine uproject support
    • Individual components / .NET 6.0 Runtime (Long Term Support) (was suggested by Visual Studio when I loaded a UE5 project)
    • Individual components / .NET Framework 4.8.1 SDK (or higher)
    • Individual components / .NET Framework 4.6.2 targeting pack (was suggested by Visual Studio when I loaded a UE5 project)
    • Individual components / MSVC 143 - VS 2022 C++ x64/x86 build tools (v14.36-17.6 or newer?) (was suggested by Visual Studio when I loaded a UE5 project)
    • After you install VS 2022, look in the VS Installer at the "Update" button. Enabled? UE5.4+? Yes, update... no problem.
  • Unreal Engine Visual Studio Integration Tool plugin: https://aka.ms/vsituemarketplace (repeat after new engine installation, as of 2024-05-28: available for 5.4)
  • naming convention checker: ".editorconfig" parallel to your .uproject file.
    Content: https://raw.githubusercontent.com/microsoft/vc-ue-extensions/main/Source/.editorconfig
  • HLS configuration file: "shadertoolsconfig.json" parallel to your .uproject file.
    Content: automatically created, defaults to:
{
  "hlsl.preprocessorDefinitions": {
  },
  " hlsl.additionalIncludeDirectories": [
  ],
  "hlsl.virtualDirectoryMappings": {
  }
}

Links

Unreal Engine

Blender

  • Export Options (so that the object is not lying on the side after Export/Import):
    • Forward: Y Forward
    • Up: Z up
  • Changing the object's origin to its bottom:
    • Switch to Edit Mode if needed (Tab). With vertex selection on, choose the center vertex in the bottom. Press Shift+S and choose Cursor to Selected. The 3D cursor will move to the selected vertex. Deselect all and switch to Object Mode (Tab).
    • In Tools choose Set Origin and then Origin to 3D Cursor.
    • Make sure the object's coordinates are set to 0,0,0. Now the object should be placed properly on the XY plane.

C++

the First Amendment to the C++ Standard states:
"The committee shall make no rule that prevents C++ programmers from shooting themselves in the foot."
-- Thomas Becker

[...] C++ is for people that punch bears and eat concrete and track their own memory.
the bottom line is, if you can't do these things; go use C#
-- zap0


Variable names

If you want to use real variable names but have nice names in the UE editor too, then use meta/DisplayName

UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, Meta = (DisplayName = "First Person Camera Component") )
    UCameraComponent* m_pFirstPersonCameraComponent;

owner / client /server

The instance that spawned the class is always ROLE_Authority. If an Actor is spawned on the client, the client is the authority. 
-- OmaManfred

OmaManfred::

 
And concerning the owner stuff:


When you spawn an instance of a class on the server FOR Client A, you have to set him as the owner.

FActorSpawnParameters params;
params.Owner = PlayerAPlayerController;

SpawnActor<Class>(Class:StaticClass(),params);

Then on Client B you can say IsOwner(PlayerBPlayerController), which should return false. 

Logging

The following is just a copy/paste/change from the UE4 wiki and was really done from different persons, I am just using the work of different people here.

Put it in a Log.h and include it in .cpp files where you want to use these macros.

#pragma once

#include "CoreMinimal.h"

// macros
// - LOG_LINE;
// - PLOG_LINE;
// - LOG -> output log
// -- LOG("text");
// -- LOG("textStatic %s %.2f %d", L"textDynamic", 1.2, 5);
// - PRINT -> screen
// -- PRINT("text");
// -- PRINT("textStatic %s %.2f %d", L"textDynamic", 1.2, 5);
// - PLOG -> output log + screen
// -- PLOG("textStatic %s %.2f %d", L"textDynamic", 1.2, 5);

#if _MSC_VER
#define FUNC_NAME    TEXT(__FUNCTION__)
#else // FIXME - GCC?
#define FUNC_NAME    TEXT(__func__)
#endif

#define LOG_LINE UE_LOG(LogTemp, Warning, TEXT("%s, file: %s, line %d"), FUNC_NAME, *FString(__FILE__), __LINE__);

#define PLOG_LINE \
{ \
	LOG_LINE; \
	PRINT("%s, file: %s, line %d", FUNC_NAME, *FString(__FILE__), __LINE__); \
}

#define PRINT(format, ...) \
{ \
	const FString sFunc = FString::Printf(TEXT("%s"), FUNC_NAME); \
	const FString sText = FString::Printf(TEXT(format), ##__VA_ARGS__); \
	const FString sMsg = FString::Printf(TEXT("%s() : %s"), *sFunc, *sText); \
	if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 5, FColor::White, sMsg); \
}

#define LOG(format, ...) \
{ \
    const FString sMsg = FString::Printf(TEXT(format), ##__VA_ARGS__); \
    UE_LOG(LogTemp, Warning, TEXT("%s() : %s"), FUNC_NAME, *sMsg);\
}

#define PLOG(format, ...) \
{ \
	LOG(format, ##__VA_ARGS__); \
	PRINT(format, ##__VA_ARGS__); \
}

Example Usage

#include "Log.h"
LOG_LINE;
PLOG_LINE; // still being tested
LOG("I am a line of text in the log,");
PRINT("but me, I am a line of text on the display screen, so there!");
LOG("textStatic %s %.2f %d", L"textDynamic", 1.2, 5);
PRINT("textStatic %s %.2f %d", L"textDynamic", 1.2, 5);
PLOG("textStatic %s %.2f %d", L"textDynamic", 1.2, 5);
 FString sPssst("a Secret");
 PLOG("I am telling you: %s", *sPssst);

Custom Log

If you want your own selectable category in the log filter to be able to only show your log messages, then you have to

  • add this line in the Log.h above any defines:
DECLARE_LOG_CATEGORY_EXTERN(aProjectLog, Log, All);
  • replace all "LogTemp" with "aProjectLog"
  • add this line to each .cpp where you want to use these macros:
DEFINE_LOG_CATEGORY(aProjectLog);

You will - in most cases - remove (nearly) all log messages when your code is running well. So... do this only if you need this, not because you think this is the "better" way to use it.

Am I client or server ?

https://answers.unrealengine.com/questions/416305/how-to-know-if-listenserverclient-owner-for-rpc.html

To answer questions 1 and 2: you can use AActor::GetNetMode() 
which returns whether you are a listen server, dedicated server or network client.

         if (GetNetMode() == ENetMode::NM_ListenServer)
         {
         }
         

The ENetMode values are:

    NM_Standalone = 0

    NM_DedicatedServer = 1

    NM_ListenServer = 2

    NM_Client = 3 // is only when you are actually connected to a server

The ordering of the ENetMode values allows you to check multiple things at once: 
GetNetMode() <= 2 means you are the server or standalone, so you have 'global authority'.

UI

I know currently of three types which might be relevant here:

  1. Canvas: Derive from HUD and overwrite "DrawHUD()"
  2. Slate: Controls usable from C++
  3. UMG: visual editor for Slate


  • Make sure your <project>.Build.cs has something like
PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
  • Normally don't use the first method with drawing directly into a canvas.

UMG with C++ base class (old, not verified again, yet)

  • create a normal UMG widget
  • create a C++ class with base class UserWidget (UUserWidget)
  • build the project
  • set the parent class of the UMG widget to your C++ class
  • in <Project>.Build.cs add "UMG", "SLATE", "SLATECORE":
  • put into <Project>.h
#include "Runtime/UMG/Public/UMG.h"
#include "Runtime/UMG/Public/UMGStyle.h"
#include "Runtime/UMG/Public/Slate/SObjectWidget.h"
#include "Runtime/UMG/Public/IUMGModule.h"
#include "Runtime/UMG/Public/Blueprint/UserWidget.h"

SLATE

The "canvas" in UMG is "SConstraintCanvas" in Slate.

Multiplayer / Sessions

Do not search for "multiplayer", search for "sessions".

This is a Youtube video I found which gives you an overview, so you already have an idea how it works before you start learning the details: Multiplayer in Unreal Engine: How to Understand Network Replication.

String conversions

from: https://docs.unrealengine.com/en-us/Programming/UnrealArchitecture/StringHandling/FString

FString TestHUDString = FString(TEXT("This is my test FString."));
FName TestHUDName = FName(*TestHUDString);
FText TestHUDText = FText::FromString(TestHUDString);
FName
text strings optimized for higher performance
FText
text strings for displaying information to players that may be localized
TEXT("CameraBoom") would mark the text for translation and automatically usable with multiple platforms
FString
regular mutable text strings (do NOT ask, NO idea what that means, but it sounds really important, right?)

(definitions from "Unreal Engine 5 Game Development with C++ Scripting")

Classes

  • You can create and use normal C++, like, create a normal C++ class and use new and delete with it.
  • But if you want to use UE stuff, you must use UE stuff and be sure to not mix it with normal C++ handling. This sounds complicated, but it is just a reminder to for example never use "new" for an actor.
  • You can create classes however you want:
    • Get the UE editor to create them (Slow, but it just works. If you don't know better, use this!)
    • Use the UI of your source editor (Visual Studio for example) to create them
    • create them manually (I still have to modify the properties of the created .cpp files, not funny)

UE classes

Please keep in mind that my information might be wrong.

A very common error seems to be the naming of the files. You have to know that common UE classes have an 'U' in front of the class name and actors have an 'A' there. So, if you'd like a 'MyFirstActor', then

  • the files are MyFirstActor.h and MyFirstActor.cpp
  • the class is "AMyFirstActor"
  • the generated file is "MyFirstActor.generated.h"

If you think you know what you are doing and use Visual Studio to create a new class "AMyFirstActor" it will default to the file names AMyFirstActor.h and AMyFirstActor.cpp which is wrong. I mean, it is not wrong, but it is not what you need here. :-)

About categories, there seem to be some ... reserved? ones. Whatever the reason, they don't work. I never got the category "Test" to show, there should be others. So, do not use "Test" as category if you have the same effect, just change the category name instead of trying to force it.

DLLEXPORT

Your classes will be inside a DLL and have to be exported to be usable. If you use UE to create a class you will see something like this:

class P01_TEST_API AMyFirstActor : public AActor

The "P01_TEST_API" between "class" and your class's name is probably just a define like

#define P01_TEST_API DLLEXPORT

Now you ask of course why there is a different define for each project if it is just "DLLEXPORT"? Good question. Next. Sorry. I just don't know (yet).

Update: Ok, I have an idea.
If you want to use the same header files but without "DLLEXPORT", then you just change the define. And that has - of course - to be done per project. So, yes, it does make sense.

minimum

The minimum of a UE class would be like this:

header file
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyFirstActor.generated.h"

UCLASS()
class P01_TEST_API AMyFirstActor : public AActor
{
	GENERATED_BODY()
	
public:	
Source file
#include "MyFirstActor.h"
*.generated.h
#include "MyFirstActor.generated.h"

Write it just like that, you don't create it, you don't look into it, you don't really care about it. BUT you have to include it as LAST include file in your header file.

UCLASS()

This has just to be there. For certain things to work you have to add words inside the brackets. An example would be:

UCLASS(BlueprintType, Blueprintable)

These words do what they say. You can use the class as a type in a blueprint or you can create a blueprint from this class.

GENERATED_BODY()

The default for a struct is public and the default for a class is private. That means "GENERATED_BODY()" in this code

 class P01_TEST_API AMyFirstActor : public AActor
 {
	GENERATED_BODY()

is private.

Don't think, just put it before any access specifiers, it works.

Variables and the like

You might want certain functionality from UE for certain enums, member variables or methods. Like.. it should work as expected and not be cleared by the system which seems to be able to be happen to certain UE container classes if you don't make them UE properties.

If you don't see the changes from C++ in your blueprint, try "Asset Actions" / Reload

And if you don't see variables or stuff you would expect to see, right-click into the blueprint's graph and try "get<YourVariable>".

  • UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Misc", Meta=(DisplayName="Cool Name"))
Enums

UE enums must be outside of classes (since 4.12). This means you have to be creative with your naming or will slap yourself if you have two enum types which you called EStatus. (This might not even be possible now.)

Example: Header, before the class:

UENUM()
enum AMySuicideActor_EStatus
{
	Task	UMETA(DisplayName = "Task"),
	Idle	UMETA(DisplayName = "Idle"),
};

Inside the class:

protected:	
	UPROPERTY()
	TEnumAsByte<AMySuicideActor_EStatus> m_eStatus;

Inside the .cpp

m_eStatus = AMySuicideActor_EStatus::Idle;

Now, that is nice and all but why would you want it? BECAUSE! No, really, you can now change

UPROPERTY()
TEnumAsByte<AMySuicideActor_EStatus> m_eStatus;

to

UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "My Tests | Part 1", meta = (DisplayName = "Status") )
TEnumAsByte<AMySuicideActor_EStatus> m_eStatus;

and suddenly you fall in love with UE. This is an actor, so you can drag it into the world in the UE editor. And then you can see the category "My Tests" and below it the subcategory "Part 1" and inside you see a label "Status" and behind it a combo box with the two possible selections: "Idle" and "Task".

  • BlueprintReadWrite: blueprints can read and write this thing/property/variable.
  • EditAnywhere: Edit it in the "Details" and (sometimes) in the "class defaults" and .. oehm.. no idea if there are more places.
  • Category: The area where this data is put when you look at an instance/class/blueprint of it
  • DisplayName: The name which is used to show this data's label (instead of the variable name)
Variables

You can of course do the same things you did with the enums with variables

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Stats, Meta = (DisplayName = "Armor"))
float m_fArmor;

There you are. Now you can edit the m_fArmor variable of your instance directly in the editor, after you created an instance by dragging the class into the world, of course.

Sounds sweet? It is!

Functions

You can expose functions like this:

UFUNCTION(BlueprintCallable, Category = "Data Access")
int32 getArmor();

Instantiating UE classes

Actors

The most simple code that works is something like

GetWorld()->SpawnActor<AMyFirstActor>();

There are of course multiple ways to do it and just SpawnActor has like 7 or so overloads.

UClass

If you want to instantiate a U* class instead of an actor then you'll probably be using something like

UAcRandomScaleChange* pAcRandomScaleChange = CreateDefaultSubobject<UAcRandomScaleChange>("RandomScaleChange");

but I can't say anything about it (yet). It works but ... understanding.... hehe.

I found the following sentence, I don't know yet if it is true. But if it is true, you really want to know it:

CreateDefaultSubobject works only in constructor. Everywhere else use NewObject.

Examples

Iterating

The following code really works. No "GetWorld()", no fumbling and no idea if it has drawbacks.

#include "Components/PointLightComponent.h"
 for (TObjectIterator<UPointLightComponent> it; it; ++it)
 {
   UPointLightComponent* pPlc = *it;
   pPlc->SetVisibility(false);
 }

Delegates

Methods for delegates seem to need to have the return type "void". So, if you need a return value, use some referenced parameter like

bool& bOk

The idea

If a class says, "I have delegates, and therefore I am super cool" (anyone played Magicka?)

DECLARE_DELEGATE(FStandardDelegateSignature)
UCLASS()
class XY_API AWithDelegate : public ...

and then has members like

FStandardDelegateSignature m_standardDelegate01;

then another (or the same) class can say, "hey, I want you to execute some code of me if your delegate01 is activated":

AWithDelegate*......->m_standardDelegate01.BindUObject(this, &AThisIsMe::coolFunctionYouShouldCall);

and then a third class can say, "yo my man, if you have something connected to your delegate01, pretty please execute that stuff now":

AWithDelegate*......->m_standardDelegate01.ExecuteIfBound();

You would - of course - not give access to your member variable directly but instead use something like

  public:

    FStandardDelegateSignature& getStandardDelegate01();

  protected:

    FStandardDelegateSignature m_StandardDelegate01;

disconnect

->getDelegateWithParam02().Unbind();

Do the connecting in BeginPlay and the disconnecting in EndPlay if you don't know better.

Other types of Delegates

One Parameter

DECLARE_DELEGATE_OneParam(FParamDelegateSignature, int)
FParamDelegateSignature m_ParameterDelegate02;
FParamDelegateSignature& getDelegateWithParam02();
.....->getDelegateWithParam02().ExecuteIfBound(42);

Multicast

If you use "BindUObject" multiple times on the same delegate, only the last bind will be remembered. If you want to have multiple listeners at once, you use the multicast delegate:

DECLARE_MULTICAST_DELEGATE(FMulticastDelegateSignature)
FMulticastDelegateSignature& getMulticastDelegate03();
FMulticastDelegateSignature m_MulticastDelegate03;
.....->getMulticastDelegate03().AddDynamic(this, &AMulticastDelegateListener::MyCoolFunction);
.....->getMulticastDelegate03().RemoveDynamic(this, &AMulticastDelegateListener::MyCoolFunction);
.....->getMulticastDelegate03().Broadcast();
Example

Custom Events

One class says it will have a custom event "CeBeginOverlap" which is a completely free too choose name at this moment:

DECLARE_EVENT(AMyTriggerVolume, CeBeginOverlap)
UCLASS()
class P02_API AMyTriggerVolume : public AActor

Then it has of course to have that event:

public:	
   CeBeginOverlap OnBeginOverlap;

Now this class will tell you at some point in time that this event has happened:

void AMyTriggerVolume::NotifyActorBeginOverlap(AActor* OtherActor)
{
  OnBeginOverlap.Broadcast();

This is nice and everything, but now we need someone who is interested in that stuff. There a multiple ways, one would be something like this:

  Super::BeginPlay();

  for (TObjectIterator<AMyTriggerVolume> it; it; ++it)
  {
    AMyTriggerVolume* pTrigger = *it;
    pTrigger->OnBeginOverlap.AddUObject(this, &AYourListenerClass::OnTriggerEvent);
  }

The advantage would be that you would connect to every source of this type.

Another way would be to have something like this in the header:

 UPROPERTY(EditAnywhere)
 AMyTriggerVolume* m_pEventSource;

and then set the source in the UE-Editor and use code like this

if (m_pEventSource!= nullptr)
{
  m_pEventSource->OnBeginOverlap.AddUObject(this, &AYourListenerClass::OnTriggerEvent);
}

Enhanced Input

  • An (U)InputAction is just a name. Like "action1", "jump" or "move". They have no meaning by itself.
    • A character might have multiple of these.
  • An (U)InputMappingContext has two reasons for existence:
    • Map a key/mouse/control to an (U)InputAction
    • Collect multiple InputActions
    • A (A)PlayerController might manage one or more of these
  • A character's "SetupPlayerInputComponent" will connect InputActions to methods.

So you have:

Input -> InputMappingContext -> InputAction -> Method

Example

UE Editor

Escape key stops simulation in editor

If you want to change this behavior, open "Edit/Editor Preferences" and search for "stop". Then change under "Play World/Stop" the shortcut "Escape" to whatever you want, for example shift-Escape.

Details/Text/Line-Break

If you are shown a text in the Details tab, chances are you can use shift-return to create a line break.

Removing projects from "Project Open" dialog

Open (use the correct engine version)

%USERPROFILE%\AppData\Local\UnrealEngine\5.3\Saved\Config\WindowsEditor\EditorSettings.ini

and modify/remove

CreatedProjectPaths
RecentlyOpenedProjectFiles

Volume of Sound after building in Visual Studio

  • Content Drawer / Settings / Show Engine Content
  • Engine / Content / EditorSounds / Notifications / *_Cue
  • Volume Multiplier

Migrating Blueprint which has C++ class as parent

Variant that works for me

c++

  • copy the c++ *.h and *.cpp files to the other project
  • right-click the DLLEXPORT macro (class bla_API YourClass, here bla_API is meant) in one of the copied header files
    • select "rename"
      • give the DLLEXPORT macro of your new project
      • skip: yes
      • scop: current project
      • apply
  • compare the YourProject.Build.cs between the two projects, add modules as needed
  • re-generate or refresh the c++-project from the UE-Editor (probably for the includes in .cpp/properties/nmake)
  • make sure the project can compile and link before you do the next steps

Blueprints

  • open "YourNewProject\Config\DefaultEngine.ini"
  • goto (or add, but it should already exist)
[/Script/Engine.Engine]
  • There might exist two lines which you can just copy/paste for the following
  • add the following lines

+ActiveGameNameRedirects=(OldGameName="OLD_PROJECT",NewGameName="/Script/NEW_PROJECT") +ActiveGameNameRedirects=(OldGameName="/Script/OLD_PROJECT",NewGameName="/Script/NEW_PROJECT")

  • Close the UE-Editor with the new project
  • Open the UE-Editor with the old project
  • Open the UE-Editor with the new project
  • in the old project, select the blueprints you want to migrate
    • right-click
    • asset actions
    • migrate
    • select the content folder of the new project
  • in the UE-Editor with the new project
    • open each of the migrated blueprints once
      • compile
      • save

Variants that don't work for me and would be so easy to use

There should be a better variant, I read you can add something like this

[CoreRedirects]
+ClassRedirects=(MatchSubstring=True,OldName="MyOldProjectName",NewName="MyNewProjectName")

and it should work for the whole project without having to do it for every class.

I read another variant where you do something like

ClassRedirects=(MatchSubstring=True,OldName="/MyOldProjectName",NewName="/MyNewProjectName")

These two variants do either nothing or make my UE-Editor unable to load the project. Too bad, I'd like to have less work. :-(

But you can try them, maybe you are lucky. Or you understand what you are doing and do it right.

Source control

Don't use Mercurial (or git) for game development. That would be just plain stupid.
Use Subversion or something like that.

The minimum you have to put under source control:

/Config
/Content
/Source
Project.uproject

Depending on your project:

/.editorconfig
/shadertoolsconfig.json


For ignores, have a look at ignoring files with svn.

External Actors

Under "Content" you will probably after some time see "EXTERNAL_ACTOR" or stuff like that. These are your map's actors, so multiple people can work on different parts of the map at the same time. That is the theory I read. :-)

So, no, don't delete them.

Here is the documentation about it.

Developer Folder

If you have the developer folder(s) enabled "Content / View Options / Show Developers Content" then make sure to not reference it from outside when cooking a project.

Visual Studio

Show errors after build

Tools / Options / Projects and Solutions / Always show Error List if build finishes with errors

Generate Visual Studio Project file

Delete temporary files

To get a cleaner project you could create a "delete-temps.cmd" with content like the following (match it with your needs):

del *.sln
del .vsconfig
rmdir /s /q .vs
rmdir /s /q Binaries
rmdir /s /q Build
rmdir /s /q DerivedDataCache
rmdir /s /q Intermediate
rmdir /s /q Intermediate
rmdir /s /q Releases
rmdir /s /q Saved

Generate project file(s)

After you cleaned away the trash you can right-click your *.uproject file and select "Generate Visual Studio Project file". This might remove some problems. Or create new ones. So far it only helped me, but it IS a bit brutal, right?

Finding the include file for a class

  • Select the class or just have your cursor inside the name
  • Press ctrl+, (press ctrl and "comma" at the same time)
  • Double-left-click the entry with the correct looking header file.
  • Then you right-click the tab name and select "copy full path".
  • Now you include that path and remove the beginning.
    • How much to leave... "you much have to learn".

If the includes are correct and you want to see the header of something again:

  • Press F12 with your cursor on the class you want to know about to go to the definition.

Just want to switch between header and source?

ctrl-k/-o

Meaning: hold ctrl, press 'k' once, after that press 'o' (letter, not digit) once while still holding ctrl.

Example 1

C:\ue\UE_5.4\Engine\Source\Runtime\Engine\Classes\Particles\ParticleSystemComponent.h

Correct include:

#include "Particles/ParticleSystemComponent.h"

Example 2

C:\ue\UE_5.4\Engine\Plugins\EnhancedInput\Source\EnhancedInput\Public\InputActionValue.h

Correct include:

#include "InputActionValue.h"

TODO list / Task list

Add a comment like

/// todo: use instead something from algorithm

Menu / View / Other Windows / Task List

Keywords are managed here: Tools / Options / Environment / Task List

("///" instead of "//" because of Style guide ad02: Comments)

Less searching and clicking

  • In the solution explorer on the left side right-click your game inside "Games" and select "Scope to this"
  • Menu / View / Code Definition Window
    • Just work normally and observe what you can see in this window depending on your current selection, you will probably be amazed. Or you are using it already since years and don't understand how anybody could not know about it.

Misc

Other Licenses (examples)

not allowed

  • GNU General Public License (GPL),
  • Lesser GPL (LGPL) (unless you are merely dynamically linking a shared library), or
  • Creative Commons Attribution-ShareAlike License.

Code or content under the following licenses, for example, are allowed

  • BSD License,
  • MIT License,
  • Microsoft Public License, or
  • Apache License.

Other

Black Screens or flickering/invisible new action popup

Disable multiplane overlay

Errors

Visual Studio

cannot open source file "CoreMinimal.h"

Error List: "Build + Intelli Sense" => "Build Only"

(source)

I am pretty sure this is NOT a solution but a workaround.

Error MSB3073 [...] -WaitMutex -FromMsBuild" exited with code 6

If you want to build with Visual Studio and get something like

Error	MSB3073	The command "C:\ue\UE_5.3\[...]ShowActor.uproject" -WaitMutex -FromMsBuild" exited with code 6.	

then you can do this:

  • UE-Editor
    • Edit / Editor Preferences
      • Live Coding
        • Enable Live Coding: no
    • File / Save All

Yes, you do this change in the EDITOR's preferences and YES, you have to do it for every project and YES, that makes absolutely NO sense at all.

IntelliSense Error: "can't open file" for includes or "red squiggles under my includes"

Make sure the .cpp-files have in Properties/NMake:

Include Search Path: $(ClCompile_AdditionalIncludeDirectories)

Copy it from other .cpp-files to be sure to get the correct value for your UE-Version/system.

Or just save everything, close everything, and recreate the c++ files from the .uproject file. That worked like a charm for me when I did not want to modify a lot of .cpp files. (Lazy, HERE?)

Can't build Solution

  • UE / Edit / Editor Preferences / Live Coding / Enable Life Coding: disable
  • Use the context menu on your project and select "Set as Startup Project".
  • Use "Build <project> (ctrl-B) to build.

This works for me but I am pretty sure there should be a way to have "Live Coding" enabled AND build from Visual Studio. I mean... the UE developers will themselves want to have both options, right? So it should be possible?

Update 1:
I found out that I have to fix the errors in the other (there are ca. 7) projects in the solution to be able to build the solution and to do that I'd have to get the source version of UE. Currently I am very unhappy with all this. A UE5 installation on top of a functioning UE4 installation works. But if you only install UE 5.3 onto a new system, not working :-(

Update 2:
UE 5.4 works pretty well. If you have 5.3, switch to 5.4+, if you are told by someone to install 5.3, ignore him and block him for like ever. And curse him!