Runtime Mask Access
Errant Biomes mask data can be accessed in runtime allowing you to drive your game logic by your world metadata.
Our subsystem will handle optimal streaming and caching of the data, leaving you with a simple performant interface for access.
Examples of use cases include:
- Playing audio based on player location in a biome.
- Limiting player allow behaviour based on nearby enviroment type.
- Controlling player hazards like area temperature with same data that is then used to generate enviroment.
Mask Setup
For mask to be available in runtime the Is Editor Only
property needs to be set to false(unchecked).
Biome Mask
To access mask painted for a biome you also need make it available in runtime.
As this asset is global it's done in the Project Settings under Errant Biomes Runtime->Editor Only Biome Masks
.
Custom Material Mask
This feature composes well with Custom Material Masks.
Custom material mask can be used for offline calculation/preperation of runtime accesed data for improved performance.
For example: Take a mask used to indicate water, calculate expanded, blurred area of that mask for better transitions and elimination of the need for sampling over a larger area in runtime.
Runtime Access
Access to the data is done through the UBiomesMaskWorldSubsystem
, mostly through the SampleMaskAsync
method.
The subsystem will manage streaming and caching data from masks.
Sampling the Biome Mask
For biome mask access use the UBiomesMaskWorldSubsystem::SampleBiomeMaskAsync
method. The returned index corresponds to a biome on the list in the setup tool.
Code Example
Provided here is an example implementation of a simple actor that samples mask under its location in runtime.
// BiomesSamplerTest.h
#pragma once
#include "CoreMinimal.h"
#include "BiomesMaskAsset.h"
#include "BiomesMaskWorldSubsystem.h"
#include "Components/StaticMeshComponent.h"
#include "Engine/World.h"
#include "GameFramework/Actor.h"
#include "BiomesSamplerTest.generated.h"
UCLASS()
class CURRENT_API ABiomesSamplerTest : public AActor
{
GENERATED_BODY()
public:
ABiomesSamplerTest()
{
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.bStartWithTickEnabled = true;
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
auto* MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
MeshComponent->SetStaticMesh(LoadObject<UStaticMesh>(nullptr, TEXT("StaticMesh'/Engine/BasicShapes/Cube.Cube'")));
MeshComponent->SetupAttachment(RootComponent);
}
virtual void Tick(float DeltaTime) override
{
if (!GetWorld() || !MaskAsset)
{
return;
}
UBiomesMaskWorldSubsystem* Subsystem = GetWorld()->GetSubsystem<UBiomesMaskWorldSubsystem>();
const float Value = Subsystem->SampleMask(*MaskAsset, FVector2D(GetActorLocation())).Get(FFloat16::MaxF16Float);
UE_LOG(LogTemp, Warning, TEXT("Sampled value: %f"), Value);
}
UPROPERTY(EditAnywhere, Category = "Test")
TObjectPtr<UBiomesMaskAsset> MaskAsset;
};