[UE4]Gameplay Dev Notes
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"));
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 create customized Subsystem?
header
UCLASS()
class MYGAME_API UMySubsystem : public UWorldSubsystem
{
GENERATED_BODY()
public:
UMySubsystem();
static UMySubsystem* Get(const UObject* WorldContext)
{
UMySubsystem* Ret = nullptr;
if (WorldContext)
{
Ret = WorldContext->GetWorld()->GetSubsystem<UMySubsystem>();
}
return Ret;
}
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
virtual void Deinitialize() override;
}
cpp
#include "MySubsystem.h"
UMySubsystem::UMySubsystem()
: UWorldSubsystem()
{
}
void UMySubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
Super::Initialize(Collection);
}
void UMySubsystem::Deinitialize()
{
Super::Deinitialize();
}
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();
}
Save Game / Load Game
void MyGameInstance::LoadSaveGame()
{
UMySaveGame* SaveGame = Cast<UMySaveGame>(
UGameplayStatics::LoadGameFromSlot(SaveSlotName, UserIndex));
if (!SaveGame)
{
if (UMySaveGame* SaveGame = Cast<UMySaveGame>(UGameplayStatics::CreateSaveGameObject(Instance()->SaveGameClass));)
{
UGameplayStatics::SaveGameToSlot(SaveGame, SaveGame->SaveSlotName, SaveGame->UserIndex);
MySaveGame = SaveGame;
}
}
else
{
MySaveGame = SaveGame;
}
}
How to get PlayerStart Point in Level
AActor* AGameModeBase::ChoosePlayerStart(AController* Player);
AActor* AGameModeBase::FindPlayerStart(AController* Player, const FString& IncomingName = TEXT(""));
Event
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 (spawned at runtime, not the actor placed in level):
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);
Engine Event
FGameDelegates::Get().GetExitCommandDelegate().AddUObject(this, &UMyGameInstance::OnEnginePreExit);
FGameDelegates::Get().GetExitCommandDelegate().AddUObject(this, &UMyGameInstance::OnEnginePreExit);
APIs
Interface Example
Define: PyWrapperBase.h
#pragma once
#include "PyWrapperBase.generated.h"
UINTERFACE(MinimalApi, BlueprintType)
class UPythonResourceOwner : public UInterface
{
GENERATED_UINTERFACE_BODY()
};
class IPythonResourceOwner
{
GENERATED_IINTERFACE_BODY()
public:
/**
* Release all Python resources owned by this object.
* Called during Python shutdown to free resources from lingering UObject-based instances.
*/
virtual void ReleasePythonResources() = 0;
};
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
几时归去,作个闲人。对一张琴、一壶酒、一溪云。----宋·苏轼《行香子》