ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
| この記事の要点 |
|
SaveGame の保存場所
Unreal Engine の SaveGame 機能で保存したファイル(拡張子 .sav)は、実行環境によって保存先が異なります。デバッグ時とリリース後で場所が変わるため、Steam 経由のセーブ移行や Mod 配布で混乱しないよう、構造を把握しておくことが重要です。
環境別の保存場所
| 環境 | 保存場所 |
|---|---|
| Editor / PIE | <ProjectDir>/Saved/SaveGames/<SlotName>.sav |
| Packaged Build (Windows) | %LOCALAPPDATA%\<GameName>\Saved\SaveGames\<SlotName>.sav(例: C:\Users\<User>\AppData\Local\MyGame\Saved\SaveGames\) |
| Packaged Build (macOS) | ~/Library/Application Support/<GameName>/Saved/SaveGames/ |
| Packaged Build (Linux) | ~/.config/Epic/<GameName>/Saved/SaveGames/ |
| iOS | App の Documents/Saved/SaveGames/ 内(サンドボックス) |
| Android | /Android/data/<PackageName>/files/UnrealGame/<GameName>/Saved/SaveGames/ |
| Steam Cloud | Steam サーバーに同期されるが、ローカルは上記と同じ |
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<FString> InventoryItems;
UPROPERTY(BlueprintReadWrite, Category = "Save")
FDateTime SaveTime;
};
2. セーブする
// SaveSystem.cpp
#include "Kernel/GameplayStatics.h"
void USaveSystem::SaveGame(const FString& SlotName)
{
UMySaveGame* SaveObj = Cast<UMySaveGame>(
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<UMySaveGame>(
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 での同等処理
- Content ブラウザ → 右クリック → Blueprint Class → 親クラスに SaveGame を選択(例:
BP_MySaveGame) - 変数を追加(PlayerName: String、Score: Integer 等)
- セーブしたい場面で Create Save Game Object(Class: BP_MySaveGame)
- 変数に値をセット → Save Game to Slot(Slot Name、User Index 0)
- ロード時は Does Save Game Exist → Load 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<uint8> 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 一覧
| 関数 | 用途 |
|---|---|
| CreateSaveGameObject | SaveGame オブジェクト生成(メモリ上) |
| 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<FString> SlotNames;
};
// 新規スロットを作る際にインデックスにも追加
void AddSlot(const FString& NewSlot)
{
auto* Index = Cast<USaveIndex>(UGameplayStatics::LoadGameFromSlot(TEXT("Index"), 0));
if (!Index) Index = Cast<USaveIndex>(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%/<GameName>/Saved/SaveGames/ - Pattern:
*.sav
FAQ
Q: パッケージ化したらセーブが PIE と別フォルダで困る
A: 仕様。PIE は <Project>/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 ロジックを追う必要あり。
ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
子ページはありません
- セーブするボタンを作成する方法
- セーブするとセーブファイルの実体がどこに保存されるか
- ロードするボタンを作成する方法
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript base URL 取得方法|window.location.origin と SSR/Node.js 対応
- 4 YouTube Data API v3 エラー一覧|403/400/404 の主要原因と切り分け
- 5 Spring Frameworkのアノテーション一覧
- 6 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 7 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- IPv6とは|128bitアドレス・コロン16進表記/::省略・リンクローカル・SLAAC・デュアルスタック NEW 2026-06-22 12:34:44
- VPNとは|暗号トンネル・サイト間/リモートアクセス・IPsec/SSL-VPN/WireGuardを解説 NEW 2026-06-22 12:19:10
- MAC アドレスフィルタリングの仕組みと限界 | ネットワーク入門 NEW 2026-06-22 12:19:10
- gRPC とは HTTP/2 + Protocol Buffers の高速 RPC | ネットワーク入門 NEW 2026-06-22 12:17:25
- HTTP/3 (QUIC) とは UDP ベースの低遅延 Web 通信 | ネットワーク入門 NEW 2026-06-22 12:17:25
- HTTP/2 とは 多重化・HPACK・バイナリフレーム | ネットワーク入門 NEW 2026-06-22 12:17:25
- Web通信プロトコル入門 HTTP/2・HTTP/3・WebSocket・gRPC・WebRTC | ネットワーク入門 NEW 2026-06-22 12:17:25
- WebSocket とは 全二重リアルタイム通信 ws/wss | ネットワーク入門 NEW 2026-06-22 12:17:25
- WebRTC とは ブラウザ間 P2P の音声・映像・データ通信 | ネットワーク入門 NEW 2026-06-22 12:17:25
- ファイアウォールとは|パケットフィルタ・ステートフル・DMZ・次世代FW(L4/L7)を解説 NEW 2026-06-22 12:17:24
- iptables/nftablesとは|テーブル・チェーン・ルール例・永続化をLinux視点で解説 NEW 2026-06-22 12:17:24
- HAProxy とは frontend/backend と設定例 | ネットワーク入門 NEW 2026-06-22 12:17:24
- 証明書と認証局(CA)とは|X.509・信頼チェーン・DV/OV/EV・失効(CRL/OCSP)を解説 NEW 2026-06-22 12:17:24
- CDN とは エッジキャッシュ・TTL・Cloudflare/CloudFront | ネットワーク入門 NEW 2026-06-22 12:17:24
- TLS/SSLの仕組み|ハンドシェイク・暗号スイート・前方秘匿性・証明書検証をわかりやすく解説 NEW 2026-06-22 12:17:24
コメントを削除してもよろしいでしょうか?