// ========================================
// 方法1: GameInstanceでの実装
// ========================================
// MyGameInstance.h
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "MyGameInstance.generated.h"
UCLASS()
class MYGAME_API UMyGameInstance : public UGameInstance
{
GENERATED_BODY()
public:
UMyGameInstance();
protected:
virtual void Init() override;
virtual void Shutdown() override;
private:
// アプリケーション終了時のデリゲート
FDelegateHandle OnExitHandle;
UFUNCTION()
void OnApplicationWillTerminate();
};
// MyGameInstance.cpp
#include "MyGameInstance.h"
#include "Engine/Engine.h"
#include "Framework/Application/SlateApplication.h"
#include "HAL/PlatformFilemanager.h"
UMyGameInstance::UMyGameInstance()
{
}
void UMyGameInstance::Init()
{
Super::Init();
// アプリケーション終了時のデリゲートをバインド
if (FSlateApplication::IsInitialized())
{
OnExitHandle = FSlateApplication::Get().OnApplicationActivationStateChanged().AddUObject(
this, &UMyGameInstance::OnApplicationWillTerminate);
}
// 別の方法: エンジンのデリゲート使用
FCoreDelegates::OnExit.AddUObject(this, &UMyGameInstance::OnApplicationWillTerminate);
UE_LOG(LogTemp, Warning, TEXT("GameInstance initialized"));
}
void UMyGameInstance::Shutdown()
{
// 終了時の処理
OnApplicationWillTerminate();
// デリゲートのクリーンアップ
if (FSlateApplication::IsInitialized() && OnExitHandle.IsValid())
{
FSlateApplication::Get().OnApplicationActivationStateChanged().Remove(OnExitHandle);
}
Super::Shutdown();
}
void UMyGameInstance::OnApplicationWillTerminate()
{
// 標準出力への書き込み
printf("Application is terminating...\n");
fprintf(stdout, "Cleanup complete. Game session ended.\n");
fflush(stdout);
// UE_LOGも使用可能
UE_LOG(LogTemp, Warning, TEXT("Application terminating - Final cleanup"));
// デバッグ出力(開発時のみ)
#if UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT
FString ExitMessage = FString::Printf(TEXT("Exit Time: %s"), *FDateTime::Now().ToString());
UE_LOG(LogTemp, Log, TEXT("%s"), *ExitMessage);
#endif
}
// ========================================
// 方法2: カスタムEngineクラスでの実装
// ========================================
// MyGameEngine.h
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameEngine.h"
#include "MyGameEngine.generated.h"
UCLASS()
class MYGAME_API UMyGameEngine : public UGameEngine
{
GENERATED_BODY()
public:
virtual void PreExit() override;
virtual void FinishDestroy() override;
};
// MyGameEngine.cpp
#include "MyGameEngine.h"
#include "HAL/PlatformFilemanager.h"
void UMyGameEngine::PreExit()
{
// アプリケーション終了前の処理
printf("=== APPLICATION SHUTDOWN SEQUENCE INITIATED ===\n");
fprintf(stdout, "Engine PreExit called\n");
// ファイルへの書き込みも可能
FString LogPath = FPaths::ProjectLogDir() / TEXT("shutdown.log");
FString ShutdownLog = FString::Printf(
TEXT("Application shutdown at: %s\n"),
*FDateTime::Now().ToString()
);
FFileHelper::SaveStringToFile(ShutdownLog, *LogPath,
FFileHelper::EEncodingOptions::AutoDetect, &IFileManager::Get(),
FILEWRITE_Append);
fflush(stdout);
Super::PreExit();
}
void UMyGameEngine::FinishDestroy()
{
printf("Engine cleanup completed\n");
fflush(stdout);
Super::FinishDestroy();
}
// ========================================
// 方法3: グローバル関数での実装
// ========================================
// MyApp.cpp (プロジェクトのメインファイル)
#include "CoreMinimal.h"
#include "RequiredProgramMainCPPInclude.h"
// グローバル終了ハンドラ
void GlobalExitHandler()
{
printf("\n=== GLOBAL EXIT HANDLER CALLED ===\n");
printf("Application terminated gracefully\n");
printf("Thank you for using our application!\n");
fflush(stdout);
}
// アプリケーション開始時に登録
void RegisterExitHandler()
{
// C標準ライブラリのatexit使用
atexit(GlobalExitHandler);
// またはUnreal Engineのデリゲート使用
FCoreDelegates::OnExit.AddStatic(GlobalExitHandler);
}
// ========================================
// 方法4: PlayerControllerでの実装
// ========================================
// MyPlayerController.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "MyPlayerController.generated.h"
UCLASS()
class MYGAME_API AMyPlayerController : public APlayerController
{
GENERATED_BODY()
public:
AMyPlayerController();
protected:
virtual void BeginDestroy() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
};
// MyPlayerController.cpp
#include "MyPlayerController.h"
AMyPlayerController::AMyPlayerController()
{
// コンストラクタでの初期化
}
void AMyPlayerController::BeginDestroy()
{
printf("PlayerController being destroyed\n");
fprintf(stdout, "Player session ended\n");
fflush(stdout);
Super::BeginDestroy();
}
void AMyPlayerController::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
FString ReasonString;
switch(EndPlayReason)
{
case EEndPlayReason::Destroyed:
ReasonString = TEXT("Destroyed");
break;
case EEndPlayReason::LevelTransition:
ReasonString = TEXT("Level Transition");
break;
case EEndPlayReason::EndPlayInEditor:
ReasonString = TEXT("End Play in Editor");
break;
case EEndPlayReason::RemovedFromWorld:
ReasonString = TEXT("Removed from World");
break;
case EEndPlayReason::Quit:
ReasonString = TEXT("Application Quit");
break;
default:
ReasonString = TEXT("Unknown");
break;
}
printf("EndPlay called with reason: %s\n", TCHAR_TO_ANSI(*ReasonString));
fflush(stdout);
Super::EndPlay(EndPlayReason);
}
// ========================================
// 追加: プロジェクト設定での登録方法
// ========================================
/*
Config/DefaultEngine.ini に以下を追加:
[/Script/EngineSettings.GameMapsSettings]
GameInstanceClass=/Script/MyGame.MyGameInstance
または
[/Script/Engine.Engine]
GameEngine=/Script/MyGame.MyGameEngine
*/