2.

UE5 SaveGame の保存場所と仕組み完全ガイド

編集
この記事の要点
  • Unreal Engine の SaveGame の保存先は環境で異なる: Editor / Packaged / プラットフォーム別
  • Editor PIE: /Saved/SaveGames/.sav
  • Packaged Build (Windows): %LOCALAPPDATA%\\Saved\SaveGames\.sav
  • API: UGameplayStatics::CreateSaveGameObject → 値設定 → SaveGameToSlot(slot, userIdx) / LoadGameFromSlot
  • USaveGame を継承した自作クラスに UPROPERTY を並べてシリアライズ。スロット名は文字列、UserIndex は 0 でも可
  • セキュリティ: .sav はバイナリだが平文 UPROPERTY なので暗号化 / ハッシュ署名は自前実装が必要

SaveGame の保存場所

Unreal Engine の SaveGame 機能で保存したファイル(拡張子 .sav)は、実行環境によって保存先が異なります。デバッグ時とリリース後で場所が変わるため、Steam 経由のセーブ移行や Mod 配布で混乱しないよう、構造を把握しておくことが重要です。

環境別の保存場所

環境保存場所
Editor / PIE/Saved/SaveGames/.sav
Packaged Build (Windows)%LOCALAPPDATA%\\Saved\SaveGames\.sav
(例: C:\Users\\AppData\Local\MyGame\Saved\SaveGames\
Packaged Build (macOS)~/Library/Application Support//Saved/SaveGames/
Packaged Build (Linux)~/.config/Epic//Saved/SaveGames/
iOSApp の Documents/Saved/SaveGames/ 内(サンドボックス)
Android/Android/data//files/UnrealGame//Saved/SaveGames/
Steam CloudSteam サーバーに同期されるが、ローカルは上記と同じ

Windows の %LOCALAPPDATA% は通常 C:\Users\<ユーザー名>\AppData\Local です。エクスプローラのアドレスバーに %LOCALAPPDATA% を直接入力すれば開けます。

SaveGame の使い方(基本)

1. USaveGame 継承クラスを作る

// MySaveGame.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/SaveGame.h"
#include "MySaveGame.generated.h"

UCLASS()
class MYGAME_API UMySaveGame : public USaveGame
{
    GENERATED_BODY()
public:
    UPROPERTY(BlueprintReadWrite, Category = "Save")
    FString PlayerName;

    UPROPERTY(BlueprintReadWrite, Category = "Save")
    int32 Score;

    UPROPERTY(BlueprintReadWrite, Category = "Save")
    FVector PlayerPosition;

    UPROPERTY(BlueprintReadWrite, Category = "Save")
    TArray InventoryItems;

    UPROPERTY(BlueprintReadWrite, Category = "Save")
    FDateTime SaveTime;
};

2. セーブする

// SaveSystem.cpp
#include "Kernel/GameplayStatics.h"

void USaveSystem::SaveGame(const FString& SlotName)
{
    UMySaveGame* SaveObj = Cast(
        UGameplayStatics::CreateSaveGameObject(UMySaveGame::StaticClass())
    );
    if (!SaveObj) return;

    SaveObj->PlayerName = TEXT("Hero");
    SaveObj->Score = 12345;
    SaveObj->PlayerPosition = GetOwner()->GetActorLocation();
    SaveObj->SaveTime = FDateTime::Now();

    bool bSuccess = UGameplayStatics::SaveGameToSlot(SaveObj, SlotName, 0);
    UE_LOG(LogTemp, Log, TEXT("Save %s: %s"), *SlotName, bSuccess ? TEXT("OK") : TEXT("Failed"));
}

3. ロードする

void USaveSystem::LoadGame(const FString& SlotName)
{
    if (!UGameplayStatics::DoesSaveGameExist(SlotName, 0))
    {
        UE_LOG(LogTemp, Warning, TEXT("No save: %s"), *SlotName);
        return;
    }

    UMySaveGame* SaveObj = Cast(
        UGameplayStatics::LoadGameFromSlot(SlotName, 0)
    );
    if (!SaveObj) return;

    UE_LOG(LogTemp, Log, TEXT("Loaded: %s / Score=%d"),
        *SaveObj->PlayerName, SaveObj->Score);
}

削除

UGameplayStatics::DeleteGameInSlot(SlotName, 0);

Blueprint での同等処理

  1. Content ブラウザ → 右クリック → Blueprint Class → 親クラスに SaveGame を選択(例: BP_MySaveGame
  2. 変数を追加(PlayerName: String、Score: Integer 等)
  3. セーブしたい場面で Create Save Game Object(Class: BP_MySaveGame)
  4. 変数に値をセット → Save Game to Slot(Slot Name、User Index 0)
  5. ロード時は Does Save Game ExistLoad Game from Slot → Cast to BP_MySaveGame

UserIndex の意味

SaveGameToSlot(Slot, UserIndex) の UserIndex は、同一マシン上の複数プレイヤー(スプリットスクリーン、コンソール)を分けるための ID です。多くの PC ゲームは 0 固定で OK。コンソールでは PS / Xbox 認識ユーザーごとに自動付与されます。

スロット名の命名

用途命名例
固定のオートセーブAutosave
手動 N スロットSaveSlot_01, SaveSlot_02, ...
キャラクタ別Save_Hero, Save_Mage
セッション ID 付きSave_2026_05_18_1430

同名で上書きすると既存ファイルは上書きされます。複数バックアップが欲しい場合はファイル名に世代を埋め込みます。

暗号化と改ざん防止

.sav ファイルは UE のシリアライザでバイナリ化されていますが、平文の文字列や数値は容易に読み取れます。チート対策が必要なら以下を実装します:

方法 1: バイト配列にして AES 暗号化

// MemoryWriter / MemoryReader で SaveObject を ByteArray にしてから暗号化
TArray Bytes;
FMemoryWriter Writer(Bytes, true);
FObjectAndNameAsStringProxyArchive Ar(Writer, true);
SaveObj->Serialize(Ar);

// AES 暗号化(FAES::EncryptData)
FAES::FAESKey Key;
FMemory::Memcpy(Key.Key, KeyBytes, FAES::FAESKey::KeySize);
FAES::EncryptData(Bytes.GetData(), Bytes.Num(), Key);

// ファイルに書き出し
FFileHelper::SaveArrayToFile(Bytes, *FilePath);

方法 2: ハッシュ署名で改ざん検出

SaveObject の内容から SHA1 / SHA256 ハッシュを取り、別フィールドに保存。ロード時に再計算と比較。

セーブ系の API 一覧

関数用途
CreateSaveGameObjectSaveGame オブジェクト生成(メモリ上)
SaveGameToSlotスロット名でディスクに同期保存
AsyncSaveGameToSlot非同期保存(5.0+、Delegate でコールバック)
LoadGameFromSlotスロット名から同期ロード
AsyncLoadGameFromSlot非同期ロード(5.0+)
DoesSaveGameExistスロット存在チェック
DeleteGameInSlotスロット削除

複数スロット管理

スロット一覧 UI を作る場合、Unreal はディレクトリ列挙 API を直接提供しないため、別途インデックスファイルを作って管理するのが定石です:

// SaveIndex.h
UCLASS()
class USaveIndex : public USaveGame
{
    GENERATED_BODY()
public:
    UPROPERTY()
    TArray SlotNames;
};

// 新規スロットを作る際にインデックスにも追加
void AddSlot(const FString& NewSlot)
{
    auto* Index = Cast(UGameplayStatics::LoadGameFromSlot(TEXT("Index"), 0));
    if (!Index) Index = Cast(UGameplayStatics::CreateSaveGameObject(USaveIndex::StaticClass()));
    Index->SlotNames.AddUnique(NewSlot);
    UGameplayStatics::SaveGameToSlot(Index, TEXT("Index"), 0);
}

Steam Cloud との連携

Steamworks SDK 連携時、Saved/SaveGames/ 配下を Auto Cloud 設定すれば自動同期されます。Steamworks の管理画面で:

  • Auto Cloud Root: %LocalAppData%//Saved/SaveGames/
  • Pattern: *.sav

FAQ

Q: パッケージ化したらセーブが PIE と別フォルダで困る
A: 仕様。PIE は /Saved/SaveGames/、パッケージは %LOCALAPPDATA%。手動コピーで移行可能(同じ .sav 形式)。

Q: Save Slot に階層フォルダを作れる?
A: 可能。Slot 名に / を含めると自動的にサブフォルダになる(例: Profiles/Player1/Slot01)。

Q: 大きなデータ(数 MB のセーブ)でゲームが固まる
A: AsyncSaveGameToSlot(UE5.0+)で非同期保存。Delegate で完了通知。

Q: .sav の中身を確認したい
A: バイナリエディタで開けば文字列リテラルは見える。完全な構造解析は UE の UObject::Serialize ロジックを追う必要あり。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. セーブするボタンを作成する方法
  2. セーブするとセーブファイルの実体がどこに保存されるか
  3. ロードするボタンを作成する方法