keywords: UE4, Gameplay Development Notes

Switch Level

论坛上有不少资料说切换场景时使用GEngine->Browse():

if (FWorldContext* Context = GEngine->GetWorldContextFromWorld(GetWorld()))
{
    FString Error;
    FURL URL(TEXT("/Game/Demo/scecn_test/scecn_test02"));
    EBrowseReturnVal::Type RS = GEngine->Browse(*Context, URL, Error);
    if (EBrowseReturnVal::Type::Failure == RS)
    {
        WSI->ChangePlayerState(EPlayerState::EP_LoginFailed);
    }
}

GEngine->Browse这种方式第一次打开场景时正常,如果第二次切换场景(比如从别的场景再切回原场景),则会导致程序崩溃。建议用:UGameplayStatics::OpenLevel(GetWorld(), TEXT("/Game/Map/TestMap")); 这种方式来回切场景不会出现崩溃问题。

Level Event

Level changed (switch level) event:

//只有Standalone和Client中触发,Server不触发。
FCoreUObjectDelegates::PreLoadMap.AddUObject(this, &UMySubsystem::OnPreLoadMap);
FCoreUObjectDelegates::PostLoadMapWithWorld.AddUObject(this, &UMySubsystem::OnPostLoadMap);

Level destroyed (e.g. exit game) event:

GetWorld()->GetLevel(0)->OnCleanupLevel.AddUObject(this, &UMySubsystem::OnCleanupLevel);

Actor spawned event:

FOnActorSpawned::FDelegate Delegate;
Delegate.BindUObject(this, &AMyActor::OnActorAdded);
GetWorld()->AddOnActorSpawnedHandler(Delegate);

or

GEngine->OnLevelActorAdded().AddUObject(this, &AMyActor::OnActorSpawned);
GEngine->OnLevelActorDeleted().AddUObject(this, &AMyActor::OnActorDeleted);
GEngine->OnLevelActorListChanged().AddUObject(this, &AMyActor::OnLevelActorListChanged);
How to get UWorld
if(UWorld* World = GEngine->GetCurrentPlayWorld(nullptr))
{
    ULevel* Level = World->GetLevel(0);
}
Check if it’s server or client without WorldContext

Quoted from CoreMisc.h

bool IsRunningDedicatedServer();

bool IsRunningGame();

bool IsRunningClientOnly();
Subsystem (Unreal Stylized Singleton)

How to get customized Subsystem?
Quoted from GameInstance.h:

template <typename TSubsystemClass>
TSubsystemClass* GetSubsystem() const
{
    return SubsystemCollection.GetSubsystem<TSubsystemClass>(TSubsystemClass::StaticClass());
}

Or:
header:

public:
    static UMySubsystem* Get(const UObject* WorldContext);

cpp:

UMySubsystem* UMySubsystem::Get(const UObject* WorldContext)
{
    return UGameInstance::GetSubsystem<UMySubsystem>(UGameplayStatics::GetGameInstance(WorldContext));
}

How to disable initialization of GameInstanceSubsystem on dedicated server?
Quoted from:
Engine\Plugins\Experimental\CommonUI\Source\CommonUI\Private\CommonUISubsystemBase.cpp

bool UCommonUISubsystemBase::ShouldCreateSubsystem(UObject* Outer) const
{
    return !CastChecked<UGameInstance>(Outer)->IsDedicatedServerInstance();
}

APIs

Interface

Define: ReactToTriggerInterface.h

#pragma once

#include "ReactToTriggerInterface.generated.h"

UINTERFACE(MinimalAPI, Blueprintable)
class UReactToTriggerInterface : public UInterface
{
    GENERATED_BODY()
};

class IReactToTriggerInterface
{    
    GENERATED_BODY()

public:
    /** Add interface function declarations here */
};

Usage: check if an actor implements an interface.

if(MyActor->GetClass()->ImplementsInterface(UMyInterface::StaticClass()))
{ }

if(IMyInterface* Interface = Cast<IMyInterface>(MyActor))
{
    Interface->OnDamage(DamageValue, DamagePosition);
}

Reference: Unreal Interfaces


几时归去,作个闲人。对一张琴、一壶酒、一溪云。----宋·苏轼《行香子》