Unreal Engine 5

Linux Setup

The setup process for UE4 on Linux is pretty straight forward, and the official instructions are very well documented. Follow those steps, and return here once you're done. Below, I just outline some of the issues I encountered using UE4 on Linux post-installation and how I solved them.

Marketplace Assets

Epic Games doesn't seem to provide any support for the UE4 Marketplace for Linux. As a result, Epic also does not support downloading and adding any assets to your project. Bummer.

I would like to note a blog post on this same issue by alexandra-zaharia, I would have very much preferred her solution but after attempting it I could not get it to work. I could install Epic Games through Lutris, but symlinking my projects (or copying them) into Wine Windows FS did not result in the Epic Games launcher detecting the projects.

What I ended up doing was using the unofficial nmrugg/UE4Launcher on GitHub. It works great, but I do miss some things like asset engine version information and browsing the marketplace.

You can install assets with it though, as long as you own them and they're linked to the Epic account you sign in with. That's all I need for now, I'm just playing with the idea of learning some C++ for UE4.

UI Scaling

Initially the UI for Unreal was very large and practically unusable. This could be due to the fact that I'm running on an integrated graphics CPU, but I'm not sure. To fix this, I just opened a project and navigated to Edit->Editor Preferences and then unchecked the Enable High DPI Support option under the General/Appearance settings menus. After restarting UE4, everything was good and UI was normal again.

Application Launchers

The shortcuts initialized by Unreal during the build process didn't work for me. I couldn't figure out why, so I just made my own. I placed these files into ~/.local/share/applications/

You will need to change the Path value to point to the same directories on your local system for the following configurations.

For the Unreal Engine Editor, the following UnrealEngine.desktop file will launch a window to open or create a UE4 project

#!/usr/bin/env xdg-open

[Desktop Entry]
Version=1.0
Type=Application
Exec=UE4Editor
Path=/home/kapper/Code/Clones/UnrealEngine/Engine/Binaries/Linux
Name=Unreal Engine Editor
Icon=ubinary
Terminal=false
StartupWMClass=UE4Editor
MimeType=application/uproject
Comment=Open or create UE4 projects

And for the open source UE4Launcher, I created the following UnrealEngineLauncher.desktop file to run npm start in the UE4Launcher repository directory.

#!/usr/bin/env xdg-open

[Desktop Entry]
Version=1.0
Type=Application
Exec=npm start
Path=/home/kapper/Code/Clones/UE4Launcher/
Name=Unreal Engine Launcher
Icon=ubinary
Terminal=false
StartupWMClass=UE4Editor
MimeType=application/uproject
Comment=UE4 Project and asset management

In the editor you can create and save layouts under the Window->Load Layout toolbar menus. After creating a layout, it will by default be output into the UnrealEngine/Engine/Saved/Config/Layouts/ directory.

I thought it'd be really useful to store the layout in the root directory of a project (tracked by github) and hardlink it from there to ~/Code/Clones/UnrealEngine/Engine/Saved/Config/Layouts instead. This way, when you clone the project for development on another machine you keep your layout, and UE4 will still recognize it within the menus for loading and saving layouts.

To create the hardlink, I ran this command

ln ~/Code/Clones/UnrealEngine/Engine/Saved/Config/Layouts/EditorLayoutKapper.ini ~/Code/GameDev/UnrealProjects/ThirdPerson/EditorLayoutKapper.ini

Debugging

See Build Configuration documentaiton for more information of the various build targets that are made available when generating a C++ project solution with UE4. Also see Compiling Projects for how to build and debug with Visual Studio.

I watched this video on YouTube to learn how to debug UE4 projects using vscode. The instructions are for windows but it was very similar for linux. Just had to install vscode on Linux first.

Once you have vscode installed, open the UE4 editor as you normally would to edit your project. Then, go to Edit->Editor Preferences and navigate to the Source Code settings menu from the left. Select Visual Studio Code from the drop down. You'll get a prompt to restart the editor, which you should do before continuing.

Once the UE4 editor has been restarted, navigate to File->Generate Visual Studio Code Project, there will be some loading screen that appears and once that finishes you can go to File->Open Visual Studio Code

Once inside our UE4 vscode project, push CTRL+SHIFT+B and run the <YOUR_PROJECT_NAME>Editor (Development) build task. This task was defined for us by UE4 when we generated our vscode project in the previous step, and the entry within my launch.json is seen below.

{
	"name": "ThirdPersonEditor (Development)",
	"request": "launch",
	"preLaunchTask": "ThirdPersonEditor Linux Development Build",
	"program": "/home/kapper/Code/Clones/UnrealEngine/Engine/Binaries/Linux/UE4Editor",
	"args": [
		"/home/kapper/Code/GameDev/UnrealProjects/unrealgame/ThirdPerson.uproject"
	],
	"cwd": "/home/kapper/Code/Clones/UnrealEngine",
	"type": "lldb"
},
        

Running this task for the first time could take a bit of time depending on the size of your project. When this finishes building, it should automatically start a new UE4 editor with your project open and in debug mode. If it doesn't, just select the <YOUR_PROJECT_NAME>Editor (Development) debug configuration in the sidebar and click the run button.

I also had to run the following command to install a missing dependency. The first time I tried to build there was an error and after reading it I traced it to this package and installed. The development build was successful after installing.

sudo apt install libopenvr-dev

Now you can run the same debug configuration and once the UE4 editor launches make sure whatever script you're debugging is active within your scene or your code breakpoint will not be hit.

Debugging on Windows under Visual Studios is very well documented, so while I do also have a windows development setup for UE4 I wont cover that here.

No luck with CLion, I seen memory usage during the build jump from 6GB to 16GB, plus an additional 4GB of swap space was also ate up.

Possibly a better solution: Running UE4 from Qt Creator

Since writing this, I've been using Rider for Unreal Engine, It's in EA right now so you have to apply for access but I was accepted almost immediately so you shouldn't have any issues.

Gameplay Ability System

Example of using the GAS: GASShooter GitHub project

Unofficial but detailed GAS Documentation

Epic livestream in depth look at GAS

Highly recommended: Setting up GAS youtube tutorial

Notes

Any Actor that wishes to use GameplayAbilities, have Attributes, or receive GameplayEffects must have one AbilitySystemComponent (ASC) attached to them.
ASC can be assigned to weapons, players, or AI

The Actor with the ASC attached to it is referred to as the OwnerActor of the ASC.
The physical representation Actor of the ASC is called the AvatarActor
The OwnerActor and AvatarActor can either be the same or different depending on the use case

If your Actor will respawn and need persistence of Attributes or GameplayEffects between spawns (like a hero in a MOBA), then the ideal location for the ASC is on the PlayerState.

Brief

In the sections below, my game is named unrealgame5, and any appearances of this string should be replaced by your own project name. This page outlines the process of setting up the Gameplay Ability System for use in an Unreal Engine 5 game using C++. Blueprints can still be used for prototyping new abilities, which can later be translated to C++.

Project Plugins and Modules

To setup out UE5 project to use the required modules, we need to edit our <PROJECT_NAME>.build.cs file. This file should have been generated by Unreal Engine when your project was created, and for me my file is named unrealgame5.build.cs

Initial contents of unrealgame5.build.cs, before I made any changes.

using UnrealBuildTool;

public class unrealgame5 : ModuleRules
{
	public unrealgame5(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

		PublicDependencyModuleNames.AddRange(new string[] {"Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay"});
  }
}

Add "GameplayAbilities", "GameplayTags", "GameplayTasks" modules to unrealgame5.build.cs so your file looks like the following.

using UnrealBuildTool;

public class unrealgame5 : ModuleRules
{
	public unrealgame5(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay" });
		PublicDependencyModuleNames.AddRange(new string[] { "GameplayAbilities", "GameplayTags", "GameplayTasks" });
	}
}

Then within the editor go to Edit->Plugins... and enable the Gameplay Abilities plugin. You will need to restart the editor for the changes to apply.

C++ Initial Setup

To set up the scaffolding for the GAS, we need a few things -

So, to complete this setup you will at least need to define a few new classes for your project.

For my project I follow the same naming convention used with GASDocumentation. I'll paste it below, but for the first few files required to set up the Gameplay Ability System (GAS), we are defining the backend of the system so none of these conventions apply. For these files, I added the GAS_ convention.

Prefix 	Asset Type
GA_ 	GameplayAbility
GC_ 	GameplayCue
GE_ 	GameplayEffect
GAS_    GameplayAbilitySystem (Core Configurations)

Ability Enumeration

First, we need to modify the contents of the header file for our unreal project. My project is named unrealgame5 so the file is unrealgame5.h, and the contents are below. If you already have information here, just make sure the EGASAbilityInputID enumeration is added to the header file and save your changes. This enumeration is used to correlate input actions to activate certain abilities in our game.

Note: Attack below must either be changed to match or made to match some keybind within your Edit->Project Settings->Input options menu.

Ability System Component

Next, we need to create an AbilitySystemComponent. This will be the component that we attach to actors that we want to take use with the GAS. To create this component, open your project in unreal and create a new C++ source file, inheiriting from the AbilitySystemComponent base class.

This base class is provided by UE5, assuming you have the GameplayAbilities plugin installed to your project. In order to inherit from it, we need to create a new C++ Class. We must be in the C++ Classes subdirectory of our project in order to do this.

Next click All Classes and search for AbilitySystemComponent.

Click next and name your class, I'll name this class GAS_AbilitySystemComponent.

The generated files are seen below. You don't need to put anything else in here for now. Note that UE5 prefixed our original class name GAS_AbilitySystemComponent with a U - it's name in the source code is UGAS_AbilitySystemComponent, this is normal and to be expected.

// GAS_AbilitySystemComponent.h
// All content (c) Shaun Reed 2021, all rights reserved

#pragma once

#include "CoreMinimal.h"
#include "AbilitySystemComponent.h"
#include "GAS_AbilitySystemComponent.generated.h"

/**
 * 
 */
UCLASS()
class UNREALGAME5_API UGAS_AbilitySystemComponent : public UAbilitySystemComponent
{
	GENERATED_BODY()
    
};
// GAS_AbilitySystemComponent.cpp
// All content (c) Shaun Reed 2021, all rights reserved

#include "GAS_AbilitySystemComponent.h"

Gameplay Abilities

Next we'll setup the base class that we will use for adding abilities to our game. To do this we need to create another new C++ Source file like we did in the previous step, only this time we will inherit from the GameplayAbility class provided with the GameplayAbilities UE5 plugin.

I named this class GAS_GameplayAbility and the source code is seen below

// GAS_GameplayAbility.h
// All content (c) Shaun Reed 2021, all rights reserved

#pragma once

#include "../unrealgame5.h"

#include "CoreMinimal.h"
#include "Abilities/GameplayAbility.h"
#include "GAS_GameplayAbility.generated.h"

UCLASS()
class UNREALGAME5_API UGAS_GameplayAbility : public UGameplayAbility
{
	GENERATED_BODY()

public:
	UGAS_GameplayAbility();

	UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Ability")
		EGASAbilityInputID AbilityInputID = EGASAbilityInputID::None;
};
// All content (c) Shaun Reed 2021, all rights reserved
// GAS_GameplayAbility.cpp

#include "GAS_GameplayAbility.h"

UGAS_GameplayAbility::UGAS_GameplayAbility() { }

Attribute Sets

Next, we need to create an AttributeSet for our game. Repeat the process of creating a new C++ sourcce file for your ue5 project, but this time inherit from AttributeSet

I named this class GAS_AttributeSet and the files genereated are below

// GAS_AttributeSet.h
// All content (c) Shaun Reed 2021, all rights reserved

#pragma once

#include "AbilitySystemComponent.h"

#include "CoreMinimal.h"
#include "AttributeSet.h"
#include "GAS_AttributeSet.generated.h"

// Macros to define getters and setters for attributes (AttributeSet.h)
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
		GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
		GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
		GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
		GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)

UCLASS()
class UNREALGAME5_API UGAS_AttributeSet : public UAttributeSet
{
	GENERATED_BODY()
    
  UGAS_AttributeSet();

public:
	virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;

	/*
	* Attribute Definitions
	*/

	// Health

	UPROPERTY(BlueprintReadOnly, Category = "Attributes", ReplicatedUsing = OnRep_Health)
	FGameplayAttributeData Health;
	// Use macros we defined from AttributeSet.h to generate getters and setters
	ATTRIBUTE_ACCESSORS(UGAS_AttributeSet, Health);

	UFUNCTION()
		virtual void OnRep_Health(const FGameplayAttributeData& OldHealth);

	// Stamina

	UPROPERTY(BlueprintReadOnly, Category = "Attributes", ReplicatedUsing = OnRep_Stamina)
	FGameplayAttributeData Stamina;
	ATTRIBUTE_ACCESSORS(UGAS_AttributeSet, Stamina);

	UFUNCTION()
		virtual void OnRep_Stamina(const FGameplayAttributeData& OldStamina);

	// Attack Power

	UPROPERTY(BlueprintReadOnly, Category = "Attributes", ReplicatedUsing = OnRep_AttackPower)
	FGameplayAttributeData AttackPower;
	ATTRIBUTE_ACCESSORS(UGAS_AttributeSet, AttackPower);

	UFUNCTION()
		virtual void OnRep_AttackPower(const FGameplayAttributeData& OldAttackPower);
};
// GAS_AttributeSet.cpp
// All content (c) Shaun Reed 2021, all rights reserved

#include "Net/UnrealNetwork.h"  // DOREPLIFETIME
#include "GAS_AttributeSet.h"

UGAS_AttributeSet::UGAS_AttributeSet()
{
}

void UGAS_AttributeSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
  Super::GetLifetimeReplicatedProps(OutLifetimeProps);
  
  DOREPLIFETIME_CONDITION_NOTIFY(UGAS_AttributeSet, Health, COND_None, REPNOTIFY_Always);
  DOREPLIFETIME_CONDITION_NOTIFY(UGAS_AttributeSet, Stamina, COND_None, REPNOTIFY_Always);
  DOREPLIFETIME_CONDITION_NOTIFY(UGAS_AttributeSet, AttackPower, COND_None, REPNOTIFY_Always);

}

void UGAS_AttributeSet::OnRep_Health(const FGameplayAttributeData& OldHealth)
{
  GAMEPLAYATTRIBUTE_REPNOTIFY(UGAS_AttributeSet, Health, OldHealth);
}

void UGAS_AttributeSet::OnRep_Stamina(const FGameplayAttributeData& OldStamina)
{
  GAMEPLAYATTRIBUTE_REPNOTIFY(UGAS_AttributeSet, Stamina, OldStamina);
}

void UGAS_AttributeSet::OnRep_AttackPower(const FGameplayAttributeData& OldAttackPower)
{
  GAMEPLAYATTRIBUTE_REPNOTIFY(UGAS_AttributeSet, AttackPower, OldAttackPower);
}

Character Setup

In the files below, my character is named ThirdPersonCharacter, so any appearances of this string may need to be replaced with your character's name instead. To setup your character that inherits from ACharacter base class, make the following changes to your files.

In the ThirdPersonCharacter.h file, make sure you're inheriting from public IABilitySystemInterface. The start of your class should look like this. Pay attention to the includes.

// All content (c) Shaun Reed 2021, all rights reserved

#pragma once

// GAS includes
#include "AbilitySystemInterface.h"
#include <GameplatEffectTypes.h>

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "ThirdPersonCharacter.generated.h"

UCLASS()
class UNREALGAME5_API AThirdPersonCharacter : public ACharacter, public IAbilitySystemInterface
{
	GENERATED_BODY()

public:

// more code....
Character Components

Next, we add an instance of our GAS_AbilitySystem class using the UGAS_AbilitySystemComponent typename, and we also add an instance of our GAS_AttributeSet class using the UGAS_AttributeSet type.

UCLASS()
class UNREALGAME5_API AThirdPersonCharacter : public ACharacter, public IAbilitySystemInterface
{
	GENERATED_BODY()

public:
	// GAS declarations
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "GAS")
	class UGAS_AbilitySystemComponent* AbilitySystemComponent;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "GAS")
    class UGAS_AttributeSet* Attributes;
// more code....

Now we need to modify the character's constructor to add the new components we've declared. I removed the code from my constructor that wasn't related to the GAS. The additions are below.

// ThirdPersonCharacter.cpp

AThirdPersonCharacter::AThirdPersonCharacter()
{
 	// Initializing any components unrelated to GAS...
	// ...

	  // Initialize GAS related components
	AbilitySystemComponent = CreateDefaultSubobject<UGAS_AbilitySystemComponent>(TEXT("AbilitySystemComponent"));
	AbilitySystemComponent->SetIsReplicated(true);
	AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Minimal);
    Attributes = CreateDefaultSubobject<UGAS_AttributeSet>(TEXT("Attributes"));
}

So we have the components we need, and the next step is to provide the required definitions for virtual functions we've inheirted from IAbilitySystemInterface

Virtual Functions

To start, we declare the required virtual functions that we will need to define to use the GAS.

UCLASS()
class UNREALGAME5_API AThirdPersonCharacter : public ACharacter, public IAbilitySystemInterface
{
	GENERATED_BODY()

public:
	// GAS declarations
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "GAS")
	class UGAS_AbilitySystemComponent* AbilitySystemComponent;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "GAS")
    class UGAS_AttributeSet* Attributes;
    
	virtual class UAbilitySystemComponent* GetAbilitySystemComponent() const override;
    
// more code....

We implement GetAbilitySystemComponent, which is just a simple getter that returns our UGAS_AbilitySystemComponent component.

// ThirdPersonCharacter.cpp
UAbilitySystemComponent* AThirdPersonCharacter::GetAbilitySystemComponent() const
{
	return AbilitySystemComponent;
}

Next we need to overload a virtual function InitializeAttributes() to handle initializing the attributes for our game at the start. We also declare the DefaultAttributeEffect member variable to help define and apply the default attributes for our character.

// ThirdPersonCharacter.h
UCLASS()
class UNREALGAME5_API AThirdPersonCharacter : public ACharacter, public IAbilitySystemInterface
{
	GENERATED_BODY()

public:
	// GAS declarations
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "GAS")
	class UGAS_AbilitySystemComponent* AbilitySystemComponent;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "GAS")
    class UGAS_AttributeSet* Attributes;
    
	virtual class UAbilitySystemComponent* GetAbilitySystemComponent() const override;
    
    // Add these lines
  	virtual void InitializeAttributes();
    UPROPERTY(BlueprintReadOnly, EditDefaultOnly, Category = "GAS")
    TSubclassOf<class UGameplayEffect> DefaultAttributeEffect;
// more code....

Define InitializeAttributes()

// ThirdPersonCharacter.cpp
void AThirdPersonCharacter::InitializeAttributes()
{
	// If the ASC and DefaultAttributeEffect objects are valid
	if (AbilitySystemComponent && DefaultAttributeEffect)
	{
		// Create context object for this gameplay effecct
		FGameplayEffectContextHandle EffectContext = AbilitySystemComponent->MakeEffectContext();
		EffectContext.AddSourceObject(this);

		// Create an outgoing effect spec using the effect to apply and the context
		FGameplayEffectSpecHandle SpecHandle = AbilitySystemComponent->MakeOutgoingSpec(DefaultAttributeEffect, 1, EffectContext);

		if (SpecHandle.IsValid())
		{
			// Apply the effect using the derived spec
			// + Could be ApplyGameplayEffectToTarget() instead if we were shooting a target
			FActiveGameplayEffectHandle GEHandle = AbilitySystemComponent->ApplyGameplayEffectSpecToSelf(*SpecHandle.Data.Get());
		}
	}
}

Similar to how we defined default attributes, we define default abilities for our character by overloading the GiveAbilities() function. We also add the DefaultAbilities array to store the default abilities for the character.

Notice that we use the UPROPERTY macro to apply EditDefaultOnly to our components. This will later allow us to modify these components in the UE5 editor for our character's blueprint, so we can dynamically add and remove attributes and abilities for our player without modifying the code each time.

// ThirdPersonCharacter.h
UCLASS()
class UNREALGAME5_API AThirdPersonCharacter : public ACharacter, public IAbilitySystemInterface
{
	GENERATED_BODY()

public:
	// GAS declarations

	// Define components to store ASC and attributes
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "GAS")
	class UGAS_AbilitySystemComponent* AbilitySystemComponent;
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "GAS")
  class UGAS_AttributeSet* Attributes;

	virtual class UAbilitySystemComponent* GetAbilitySystemComponent() const override;
	// Overload to initialize attributes for GAS, and component to store default attributes
	virtual void InitializeAttributes();
	UPROPERTY(BlueprintReadOnly, EditDefaultOnly, Category = "GAS")
  TSubclassOf<class UGameplayEffect> DefaultAttributeEffect;

	// Overload to initialize abilities for GAS, and component to store default abilities
	virtual void GiveAbilities();
	UPROPERTY(BlueprintReadOnly, EditDefaultOnly, Category = "GAS")
	TArray<TSubclassOf<class UGAS_GameplayAbility>> DefaultAbilities;
public:	
// more code....

And we define GiveAbilities below to handle the allocation of default abilities to our character.

// ThirdPersonCharacter.cpp
void AThirdPersonCharacter::GiveAbilities()
{
	// If the server has the authority to grant abilities and there is a valid ASC
	if (HasAuthority() && AbilitySystemComponent)
	{
		// Foreach ability in DefaultAbilities, grant the ability
		for (TSubclassOf<UGAS_GameplayAbility>& StartupAbility : DefaultAbilities)
		{
			// `1` below is the level of the ability, which could later be used to allow abilities to scale with player level
			AbilitySystemComponent->GiveAbility(
				FGameplayAbilitySpec(StartupAbility, 1, static_cast<int32>(StartupAbility.GetDefaultObject()->AbilityInputID), this));
		}
	}
}

For the next step, we need to override PossessedBy and OnRep_PlayerState() to define how to update the server and client of the player state respectively.

// ThirdPersonCharacter.h
UCLASS()
class UNREALGAME5_API AThirdPersonCharacter : public ACharacter, public IAbilitySystemInterface
{
	GENERATED_BODY()

public:
	// GAS declarations

	// Define components to store ASC and attributes
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "GAS")
	class UGAS_AbilitySystemComponent* AbilitySystemComponent;
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "GAS")
  class UGAS_AttributeSet* Attributes;

	virtual class UAbilitySystemComponent* GetAbilitySystemComponent() const override;
	// Overload to initialize attributes for GAS, and component to store default attributes
	virtual void InitializeAttributes();
	UPROPERTY(BlueprintReadOnly, EditDefaultOnly, Category = "GAS")
  TSubclassOf<class UGameplayEffect> DefaultAttributeEffect;

	// Overload to initialize abilities for GAS, and component to store default abilities
	virtual void GiveAbilities();
	UPROPERTY(BlueprintReadOnly, EditDefaultOnly, Category = "GAS")
	TArray<TSubclassOf<class UGAS_GameplayAbility>> DefaultAbilities;
public:	
// more code....

And see the definitions for these functions below

// ThirdPersonCharacter.cpp
void AThirdPersonCharacter::PossessedBy(AController* NewController)
{
	Super::PossessedBy(NewController);

	// Owner and Avatar are bother this character
	AbilitySystemComponent->InitAbilityActorInfo(this, this);

	InitializeAttributes();
	GiveAbilities();
}

void AThirdPersonCharacter::OnRep_PlayerState()
{
	Super::OnRep_PlayerState();

	AbilitySystemComponent->InitAbilityActorInfo(this, this);
	InitializeAttributes();

	if (AbilitySystemComponent && InputComponent)
	{
		// Where the 3rd parameter is a string equal to enum typename defined in unrealgame5.h
		const FGameplayAbilityInputBinds Binds("Confirm", "Cancel", "EGASAbilityInputID", static_cast<int32>(EGASAbilityInputID::Confirm), static_cast<int32>(EGASAbilityInputID::Cancel));
		AbilitySystemComponent->BindAbilityActivationToInputComponent(InputComponent, Binds);
	}
}

As a final modification, add the following code to the function equivalent to ThirdPersonCharacter::SetupPlayerInputComponent() in your project. This is the same code as the last portion of OnRep_PlayerState

void AThirdPersonCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	// Code unrelated to GAS...
	// ...  
  
	// Make sure GAS is valid along with player input component
	if (AbilitySystemComponent && InputComponent)
	{
		// Where the 3rd parameter is a string equal to enum typename defined in unrealgame5.h
		const FGameplayAbilityInputBinds Binds("Confirm", "Cancel", "EGASAbilityInputID", static_cast<int32>(EGASAbilityInputID::Confirm), static_cast<int32>(EGASAbilityInputID::Cancel));
		AbilitySystemComponent->BindAbilityActivationToInputComponent(InputComponent, Binds);
	}
}

And just to be sure we have all the headers we need, here are the final includes for my character

// ThirdPersonCharacter.h
// GAS includes
#include "AbilitySystemInterface.h"
#include <GameplayEffectTypes.h>
#include "GAS_AbilitySystemComponent.h"
#include "GAS_GameplayAbility.h"
#include "GAS_AttributeSet.h"

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "ThirdPersonCharacter.generated.h"
// ThirdPersonCharacter.cpp
// All content (c) Shaun Reed 2021, all rights reserved

#include "ThirdPersonCharacter.h"

// Custom includes (Not related to GAS)
#include "ActorSpawner.h"  // Fireball spawner object
#include "BallActor.h"  // Fireball object

// Includes for GAS
#include "../unrealgame5.h"

// Engine includes
#include "Kismet/GameplayStatics.h" // For spawning fireball static mesh
#include "Camera/CameraComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "GameFramework/CharacterMovementComponent.h"

Defining Abilities

At this point we have configured GAS for our project and our character, so we're ready to start defining our abilities!

In my assets folder, I just created an Abilities subdirectory and continued with the steps below, creating the assets within this directory.

Default Abilities

First I created a new Blueprint Class using the editor and derived from the GameplayEffect class. Applying this effect will result in the player or character being granted a set of default abilities.

I named this GE_CharacterDefaults, and opened it for editing. The screenshot below contains all settings I modified under the Class Defaults panel. If it isn't in this screenshot, I didn't change it.

Then I opened my BP_ThirdPersonCharacter blueprint for editing and applied the following settings within the details panel. You should notice at this point that the DefaultAttributeEffect and DefaultAttributes in this screenshot are actually the components we exposed to the editor in our ThirdPersonCharacter.h file earlier with UPROPERTY and EditDefaultsOnly.

Damage Effect

To prove the system is working, create a new blueprint that derives from GameplayEffect and apply the settings below

Then, in the event chart for your BP_ThirdPersonCharacter add a BeginPlay node and apply the damage when the game starts.

Hit play and then open a console and type showdebug abilitysystem to see that your HP should now be 80 on the lefthand side. Remove the damage to your player when youre done testing, but you can keep the GE_Damage asset around to use it later.

Attack Ability

First, open the animation blueprint for your character and add a montage Slot 'DefaultSlot' to your anim graph. For me, the screen looks like the below after the changes have been made. Make sure to save and apply these changes.

Make a new blueprint deriving from the GAS_GameplayAbilitiy class that we defined earlier.

I named this GA_Attack and opened it for editing.

Make sure the Ability Input ID matches the input action we want the ability to be mapped to. This is found under the details panel.

Next, open GA_Attack for editing and add the following blueprint nodes. Add the GetActorInfo node in the context menu in the screenshot, be sure to uncheck 'Context Sensitive' if it isn't appearing at first.

Now right click the GetActorInfo node and select Split Struct Pin to split the actor into its components

And connect the skeletal mesh pins to finish the blueprint for GA_Attack

Under the Montage To Play pin on the Play Montage node, you may not have a montage available for your skeleton.

If you also don't have an animation, check out Mixamo for a free anmation and see the page on Retargeting Skeleton Animations

Then create a montage by watching this quick youtube video. If you're doing a simple punch animation, you probably just need to create a montage and click and drag the animation into the center of the screen and save. It's pretty simple, but you can use Motages to do some pretty neat things. Maybe for the first montage try making a one-off animation that doesn't loop like punching or a grab motion for interactions.

Once you have the montage made, select it here in this node, and then play the game. You'll now be able to see your character performing the attack!

Additional Abilities

At a higher level, the steps for adding a new ability are below

  1. Add the input action to the enum defined in unrealgame5.h (AKA <YOUR_PROJECT_NAME>.h)
  2. Recompile in the editor or within the IDE of your choice
  3. Restart the editor
  4. Create a blueprint deriving from GAS_GameplayAbility
  5. Define the ActivateAbilitiy event for this new blueprint, and assign an Ability Input ID within the Details panel
  6. Create a new Animation Montage for the ability, if needed (and assign to play on ActivateAbility event)
  7. Grant the abilitiy under the Details tab in the Default Abilities section while editing the BP_ThirdPersonCharacter blueprint
  8. Add the input action to your project under Edit->Input if it doesn't already exist

Debugging

To see useful information on the GAS, enter play mode and hit the tilde (~) key to open a console. Then, type showdebug abilitysystem, and youll notice you can see your character stats even if there's no UI elements to represent them yet.

Retarget Skeleton Animations

Mixamo to UE5

Animation Retargeting UE5

These systems have changed with the official release of UE5. See the links above for updated tutorials

If you're not an animator, you might also get use out of sites like Mixamo that provide some free animations. To use these though, you need to retarget the animation for your skeleton in UE5.

First, open the Skeleton asset for your character. For the UE4 Mannequin, it should be called something like UE4_Mannequin_Skeleton. Once it's open for editing, click Retarget Manager at the top of the screen.

It will reveal a new side panel like the below. Select the the Humanoid option from the dropdown menu and it should automatically populate all the bones for your skeleton if you are using the UE4 mannequin. If you are not, you will probably have to manually make these assignments, as I did for the next skeleton in this section.

Next, click the Save button in the above Set up Rig dialog, and save the rig someplace safe.

Open the other Skeleton asset that was used for the animation you want to use, and again click the Retarget Manager button at the top of the screen. Then select the Humanoid option from the dropdown, and assign the bones to their respective members on the skeleton.

When you're finished, it should look like the screenshot below. Click the Show Advanced button and do the same for as many bones as you can. Don't worry if you can't figure some of them out, you can still produce a good result most of the time. It might seem like overkill to assign each finger, but if you're doing a punching animation like I was it will look more like a slap if you don't.

Click the Save button and storre this Rig asset somewhere. Then, make sure you also save changes to both Skeleton assets, and right click the animation you want to retarget. Select Duplicate Anim Assets and Retarget from the context menu as seen in the screenshot below.

Select your skeleton on the left hand side and then set a name for the file and choose a location to save the retargeted animation.

If the Source and Target skeletons dont have similar poses in the above dialog, open the skeleton with the abnormal pose in the Retarget Manager and adjust it to match the more normal pose. Then, in the Set up Rig dialog select Modify Pose->Use Current Pose as seen in the screenshot below.

Once you're happy with the poses of the skeletons, you can retarget the animation and see the results. If you aren't happy with the retargeted animation, try defining more bones in the Rig assets for your skeletons, or maybe select a different animation.