Gamasutra is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Gamasutra: The Art & Business of Making Gamesspacer
arrowPress Releases







If you enjoy reading this site, you might also want to check out these UBM Tech sites:


 

UE4Cookery CPP009: Referencing assets for C++ lovers

by Artur Kh on 06/21/21 10:22:00 am

The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

 

Many developers prefer to move all logic that they can in C++ to gain more control and optimization. However, this can cause another problem and that problem is referencing assets. For example, one can face it while refactoring UMG components to custom Slate widgets. Of course, referencing can be done by creating static class, that will be a container for asset path names. But in this case renaming and assets dependencies are out, so there must be a more handy way!

Suppose, that we have many different fonts, button styles, textures and so on, imported and designed for our UI. If all our widgets are in C++ (custom Slate widgets), then to apply that suff we need a way to reference them in code. How can we solve that? First of all, we can create custom asset

 

UIData.h

#pragma once

#include "UObject/NoExportTypes.h"
#include "Fonts/SlateFontInfo.h"
#include "UIData.generated.h"

UCLASS()
class CPP009_API UUIData : public UObject {

	GENERATED_BODY()

public:

	const FSlateFontInfo& GetMenuFontInfo() const { return MenuFontInfo; }

	const FSlateFontInfo& GetGameFontInfo() const { return GameFontInfo; }

protected:

	UPROPERTY(EditDefaultsOnly, Category = "UI Data: Menu Font Info")
		FSlateFontInfo MenuFontInfo;

	UPROPERTY(EditDefaultsOnly, Category = "UI Data: Game Font Info")
		FSlateFontInfo GameFontInfo;
};

 

Ok, so that is our UI Data asset. To be able to create it right in Editor we need to add Editor module to our project and create two classes based on UFactory and UAssetTypeActions_Base. After that is done, we can create UI Data asset right in Content folder

Playing with asset in Editor

 

So, we have referenced all stuff around UI and that is fine, but how can we reference UI Data asset itself? Let see. We can create another object class and that will be

 

#include "GameDataSingleton.h"

#pragma once

#include "UObject/NoExportTypes.h"
#include "GameDataSingleton.generated.h"

class UUIData;

UCLASS(Blueprintable)
class CPP009_API UGameDataSingleton : public UObject {

	GENERATED_UCLASS_BODY()

public:

	UUIData* GetUIData() const { return MyUIData; }

protected:

	UPROPERTY(EditDefaultsOnly)
		UUIData* MyUIData;

public:

	static UGameDataSingleton* GetInstance() { 
		static UGameDataSingleton* instance = Cast<UGameDataSingleton>(GEngine->GameSingleton);
		return instance;
	}
};

UGameDataSingleton::UGameDataSingleton(const FObjectInitializer& ObjInitializer) :Super(ObjInitializer) {}

 

Here we have created static function to access singleton instance, however we don't create it by our selves, rather we are trying just to pick it up from GEngine->GameSingleton. We can create blueprint around UGameDataSingleton and fill all props in it, lets name it BP_GameDataSingleton. To make it all happen to work, there is only one step left - we need to change Project Settings:

Project Settings

It will be Engine, who will create UGameDataSingleton by provided class and will store it in GEngine->GameSingleton.

 

For demonstration purposes we can create Slate widget in project Game mode class and set some of widget props by accessing UGameDataSingleton:

 

CPP009GameModeBase.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "CPP009GameModeBase.generated.h"

class STextBlock;

UCLASS()
class CPP009_API ACPP009GameModeBase : public AGameModeBase
{
	GENERATED_BODY()
	
public:

	virtual void BeginPlay() override;

	virtual void EndPlay(EEndPlayReason::Type reason) override;

protected:

	TSharedPtr<STextBlock> MyTextBlock;
};

 

CPP009GameModeBase.cpp

#include "CPP009GameModeBase.h"
#include "Kismet/GameplayStatics.h"
#include "Slate/SGameLayerManager.h"
#include "Slate/SceneViewport.h"
#include "Widgets/Text/STextBlock.h"
#include "GameDataSingleton.h"
#include "UIData.h"

void ACPP009GameModeBase::BeginPlay() {
	Super::BeginPlay();

	auto uiData = UGameDataSingleton::GetInstance()->GetUIData();

	if (auto controller = UGameplayStatics::GetPlayerController(this, 0)) {
		auto localPlayer = Cast<ULocalPlayer>(controller->Player);
		if (localPlayer && localPlayer->ViewportClient) {
			auto layerManager = localPlayer->ViewportClient->GetGameLayerManager();
			if (layerManager.Get()) {
				layerManager->AddWidgetForPlayer(localPlayer, SAssignNew(MyTextBlock, STextBlock).Text(FText::FromString("Hello, Game Data Singleton!")).Font(uiData->GetMenuFontInfo()), 0);
			}
		}
	}
}

void ACPP009GameModeBase::EndPlay(EEndPlayReason::Type reason) {
	Super::EndPlay(reason);

	if (MyTextBlock.IsValid()) {	
		if (auto controller = UGameplayStatics::GetPlayerController(this, 0)) {
			auto localPlayer = Cast<ULocalPlayer>(controller->Player);
			if (localPlayer && localPlayer->ViewportClient) {
				auto layerManager = localPlayer->ViewportClient->GetGameLayerManager();
				if (layerManager.Get()) {
					layerManager->RemoveWidgetForPlayer(localPlayer, MyTextBlock.ToSharedRef());
				}
			}
		}
		MyTextBlock.Reset();
	}
}

 

Finally, we have

Hello, Game Data Singleton!


Related Jobs

Insomniac Games
Insomniac Games — Burbank, California, United States
[07.23.21]

Technical Artist - Pipeline
Insomniac Games
Insomniac Games — Burbank, California, United States
[07.23.21]

Engine Programmer
Legends of Learning
Legends of Learning — Baltimore, Maryland, United States
[07.23.21]

Senior Gameplay Engineer - $160k - Remote OK
Bytro Labs GmbH
Bytro Labs GmbH — Hamburg, Germany
[07.23.21]

Senior Product Owner / Live-Ops Owner (f/m/x)





Loading Comments

loader image