ゲームを保存して読み込む

ゲームを保存して読み込む方法の概要です。

Windows
MacOS
Linux

実装方法を選んでください。

Blueprints

C++

「ゲームを保存する」という意味はゲームによって大きく変わりますが、最新ゲームにおいて一般的な考え方ではプレイヤーはゲームを終了し、後から終了した場所からゲームを再開できることを表します。必要になる情報は作成するゲームの種類によって大きく変わります。プレイヤーが到達した最後のチェックポイントや、プレイヤーが見つけたアイテムの種類など、ごく少量の基本情報の場合もあれば、プレイヤーの他のインゲーム キャラクターとのソーシャル インタラクションに関する長いリスト、またはさまざまなクエスト、ミッションの目的、サブプロットの現状など、かなり詳細な情報の場合もあります。Unreal Engine 4 (UE4) は、複数のプレイ セッションにわたり保持するために必要なすべての情報を含め、ゲームの特定のニーズを満たすために作成する 1 つ以上のカスタム SaveGame クラスを中心に回転するシステムを保存およびロードします。複数の保存したゲーム ファイルをもち、異なる SaveGame クラスをこれらのファイルに保存する機能をサポートします。これは、グローバルにロック解除された機能をプレイスルー専用のゲーム データから分離する場合に便利です。

SaveGame オブジェクトの作成

SaveGame オブジェクトを作成するには、 Blueprint クラスを作成する を参照してください。[Pick Parent Class (親クラスを選択)] ダイアログが開いたら、 [Custom Classes] を展開し、 [SaveGame] を選択します。検索ボックスを使って SaveGame へ直接ジャンプすることができます。新規のブループリントに MySaveGame と名前を付けます。

savegame.png

新規の SaveGame object ブループリントで、保存したい情報に対する変数を作成します。

このサンプルでは、 SaveSlotName と UserIndex に対するデフォルト値の保存の宣言に使用する変数もあるので、 この SaveGame オブジェクトに保存される各クラスには、これらの変数を個別に設定する必要はありません。ここの部分はオプションです。デフォルト値が変更されない場合、上書される保存スロットは 1 つになります。

SaveGameVariables.png

ブループリントのコンパイル後に、変数のデフォルト値を設定できます。

SaveGame オブジェクトの作成

USaveGame クラスは、 Kismet/GameplayStatics.h に宣言される関数の保存およびロードのためにターゲットとして使用されるオブジェクトを設定します。

C++ クラス ウィザード を使って USaveGame をもとに新規クラスを作成することができます。

SaveGameCode.png

このサンプルでは、新規の USaveGame クラスは「UMySaveGame」と呼びます。これを使用するには、その他の #include ディレクティブの後にゲーム モジュールのヘッダ ファイルに以下の行を追加します。

MyProject.h

#include "MySaveGame.h"
#include "Kismet/GameplayStatics.h"

ヘッダ

SaveGame オブジェクトのヘッダファイルの中では、 SaveGame を格納するためのどんな変数でも宣言することができます。

UPROPERTY(VisibleAnywhere, Category = Basic)
FString PlayerName;

このサンプルでは、SaveSlotName と UserIndex に対するデフォルト値の保存の宣言に使用する変数もあるので、 この SaveGame オブジェクトに保存される各クラスには、これらの変数を個別に設定する必要はありません。ここの部分はオプションです。デフォルト値が変更されない場合、上書される保存スロットは 1 つになります。

MySaveGame.h

#pragma once

#include "GameFramework/SaveGame.h"
#include "MySaveGame.generated.h"

/**
 * 
 */
UCLASS()
class [PROJECTNAME]_API UMySaveGame : public USaveGame
{
    GENERATED_BODY()

    public:

    UPROPERTY(VisibleAnywhere, Category = Basic)
    FString PlayerName;

    UPROPERTY(VisibleAnywhere, Category = Basic)
    FString SaveSlotName;

UPROPERTY(VisibleAnywhere, Category = Basic
    uint32 UserIndex;

    UMySaveGame();
};

ソース

一般的に、保存システムに何か特別に機能をここで追加したい場合を除き、 SaveGame オブジェクトのソースファイルは関数に対して特定のコードを必要としません。

このサンプルでは、クラス コンストラクタで SaveSlotNameUserIndex の値を定義するので、ゲームプレイ クラスによる読み取りと使用が可能です。

MySaveGame.cpp

// Copyright 1998-2018 Epic Games, Inc.All Rights Reserved.

#include "[ProjectName].h"
#include "MySaveGame.h"

UMySaveGame::UMySaveGame()
{
    SaveSlotName = TEXT("TestSaveSlot");
    UserIndex = 0;
}

ゲームを保存する

作成された SaveGame クラスは、ゲームのデータに格納するために変数を使って追加することができます。たとえば、整数変数を作成するとプレイヤーの得点を、あるいは文字列変数を使ってプレイヤーの名前を格納できます。ゲームを保存するときに、その情報は現在のゲーム ワールドから SaveGame オブジェクトへ転送されます。そしてゲームを読み込むときに、SaveGame オブジェクトからそれを Characters、Player Controller、Game Mode などのオブジェクトへコピーします。

まず最初に、Create Save Game Object ノードを使って、SaveGame クラスに基づいたオブジェクトを作成します。Save Game Class 入力ピンのドロップダウンを作成したクラス (ここでは「MySaveGame」」) に設定されていることを確認してください。Create Save Game Object ノードは、Save Game Class 入力ピンで指定したタイプに合うように自動的に出力ピンの種類が自動的に変更され、Cast To ノードを使わず直接それを使えるようになります。作成したばかりの MySaveGame オブジェクトを簡単に再利用できるように、結果として生じたオブジェクトを Promote to Variable を使って変数へ保存しておくと良いです。

SaveGameBP_1.png

Save Game Instance 変数はカスタムした SaveGame オブジェクトがあるので、そこに情報を送ることができます。例えば、Player Name フィールドを "PlayerOne" に設定することができます。保存したゲーム ファイルに格納したいデータがすべて含まれるまで、SaveGame オブジェクト内にフィールドを設定します。

SaveGameBP_2.png

SaveGame オブジェクトがすべて入力されたら、ASync Save Game To Slot ノードを使ってゲームの保存を完了します。ファイル名とユーザー ID も提供する必要があります。この例のファイル名とユーザー ID は前に作成されたデフォルト値です。ゲーム保存操作が完了すると、すぐに実行ピンが 1 番上から 2 番目のピンへすぐに続きます。2 番目のピンが実行されるまで出力ピンは有効にはなりません。

SaveGameBP_3.png

Async Save Game To Slot は、大容量のデータを保存する場合でも引きつりを回避できることから、ゲームの保存に推奨される方法です。しかしながら、保存するゲーム データが小さい場合、またはメニューやポーズ画面から保存する場合は以下のように Save Game To Slot ノードでゲームを保存することもできます。

SaveGameBP_4.png

以下のスクリーンショットは、MySaveGame クラスを使ってゲームを保存するためのブループリントでのすべてのプロセスを表しています。

上の画像をクリックして拡大表示

まず、新しい UMySaveGame オブジェクトを取得するために CreateSaveGameObject (UGameplayStatics ライブラリから) を呼び出します。オブジェクトを取得したら、保存するデータを使って入力します。最後に、SaveGameToSlot または AsyncSaveGameToSlot を呼び出してデバイスにデータを書き出します。

非同期保存

AsyncSaveGameToSlot はゲームの保存に推奨されるメソッド法です。非同期で実行することにより急なフレーム レートの引きつりを防ぎ、プレイヤーへの通知を減らして幾つかのプラットフォーム上で起こりうる認証問題を回避します。保存処理が完了したら、(FAsyncSaveGameToSlotDelegate のタイプの) デリゲートがスロット名、ユーザー インデックス、成功または失敗を示す bool と一緒に呼び出されます。

if (UMySaveGame* SaveGameInstance = Cast<UMySaveGame>(UGameplayStatics::CreateSaveGameObject(UMySaveGame::StaticClass())))
{
    // Set up the (optional) delegate.
    FAsyncSaveGameToSlotDelegate SavedDelegate;
    // USomeUObjectClass::SaveGameDelegateFunction is a void function that takes the following parameters: const FString& SlotName, const int32 UserIndex, bool bSuccess
    SavedDelegate.BindUObject(SomeUObjectPointer, &USomeUObjectClass::SaveGameDelegateFunction);

    // Set data on the savegame object.
    SaveGameInstance->PlayerName = TEXT("PlayerOne");

    // Start async save process.
    UGameplayStatics::AsyncSaveGameToSlot(SaveGameInstance, SlotNameString, UserIndexInt32, SavedDelegate);
}

同期保存

SaveGameToSlot は、小さな SaveGame 形式、およびポーズ中またはメニュー内でのゲームの保存に十分です。ゲームをすぐに保存して成功または失敗を示す bool を返すので簡単に使用できます。容量が大きいデータの場合、またはプレイヤーがゲーム ワールドとアクティブにインタラクトしている間にゲームを自動保存する場合は、AsyncSaveGameToSlot の方が適しています。

if (UMySaveGame* SaveGameInstance = Cast<UMySaveGame>(UGameplayStatics::CreateSaveGameObject(UMySaveGame::StaticClass())))
{
    // Set data on the savegame object.
    SaveGameInstance->PlayerName = TEXT("PlayerOne");

    // Save the data immediately.
    if (UGameplayStatics::SaveGameToSlot(SaveGameInstance, SlotNameString, UserIndexInt32))
    {
        // Save succeeded.
    }
}

バイナリ保存

SaveGameToMemory 機能を使って SaveGame オブジェクトをメモリに転送することができます。この関数は同期での操作のみを提供しますが、ドライブへの保存より高速です。呼び出し元はデータが格納されたバッファ (TArray<uint8>&amp;) へ参照を提供します。成功した場合は True を返します。

TArray<uint8> OutSaveData;
if (UGameplayStatics::SaveGameToMemory(SaveGameObject, OutSaveData))
{
    // The operation succeeded, and OutSaveData now contains a binary represenation of the SaveGame object.
}

`SaveGameToSlot` 関数と同様に、バッファ (`const TArray<uint8>&`)、スロット名、ユーザー ID 情報を使って `SaveDataToSlot` を呼び出すことでバイナリ データをファイルに直接保存することもできます。`SaveGameToMemory` のように、この関数は同期操作のみ提供し、成功または失敗を示すために `bool` を返します。
if (UGameplayStatics::SaveDataToSlot(InSaveData, SlotNameString, UserIndexInt32))
{
    // The operation succeeded, and InSaveData has been written to the save file defined by the slot name and user ID we provided.
}

開発プラットフォームでは、保存されたゲーム ファイルは .sav 拡張子を使い、プロジェクトの「`Saved\SaveGames」フォルダに表示されます。他のプラットフォーム、特にコンソールでは、特定のファイル システムに対応するために異なります。

ゲームをロードする

保存したゲームをロードするには、ゲームを保存するときに使用したスロット名とユーザー ID を指定する必要があります。指定した SaveGame が存在する場合、エンジンはエンジンが含む SaveGame オブジェクトにデータを追加し、基本となる SaveGame (クラス USaveGame) オブジェクトとして返します。その後でオブジェクトをカスタム SaveGame クラスにキャストし、データにアクセスすることができます。 SaveGame タイプに含まれるデータの種類によって、コピーを保存したり、またはデータのみを使用しオブジェクトを破棄することもできます。

保存と同様に、ロードも同期または非同期で行うことができます。データ量が大きい場合、またはロード時間中にロード中の画面またはアニメーションを使用したい場合、非同期の方法をお勧めします。データが小さくすぐにロードしたい場合は同期の方法があります。

同期的にロードするには Load Game From Slot を使用します。このノードはとても分かりやすいです。指定したスロット名と ID が有効な SaveGame ファイルを特定すると有効な SaveGame オブジェクトを返します。ロード操作の進行中はゲームが停止します。

LoadGameBP.png

Async Load Game From Slot はおおよそ同じように機能しますが、実行出力ピンが 2 つあります。1 つめのピンはロード操作の開始時に、 2 つめのピンはロード操作の完了時に実行します。2 番目のピンが実行されるまで変数出力ピンは有効にはなりません。Success ピンはロード操作が成功したかどうかを示しますが、返されたオブジェクトを Is Valid ノードに渡したり、Cast To ノードからロード処理でのあらゆるエラーとして失敗を処理することもできます。

LoadGameBPAsync.png

非同期的なロード方法

AsyncLoadGameFromSlot で非同期的にロードする場合、システムがロードするデータを受け取るためにコールバック デリゲートを提供しなければなりません。

// Set up the delegate.
FAsyncLoadGameFromSlotDelegate LoadedDelegate;
// USomeUObjectClass::LoadGameDelegateFunction is a void function that takes the following parameters: const FString& SlotName, const int32 UserIndex, USaveGame* LoadedGameData
LoadedDelegate.BindUObject(SomeUObjectPointer, &USomeUObjectClass::LoadGameDelegateFunction);
UGameplayStatics::AsyncLoadGameFromSlot(SlotName, 0, LoadedDelegate);

同期的なロード方法

LoadGameFromSlot 関数は、USaveGame オブジェクトを作成し、成功した場合に USaveGame オブジェクト返します。

// Retrieve and cast the USaveGame object to UMySaveGame.
if (UMySaveGame* LoadedGame = Cast<UMySaveGame>(UGameplayStatics::LoadGameFromSlot(SlotName, 0)))
{
    // The operation was successful, so LoadedGame now contains the data we saved earlier.
    UE_LOG(LogTemp, Warning, TEXT("LOADED: %s"), *LoadedGame->PlayerName);
}

バイナリ形式のロード方法

LoadDataFromSlot を使ってファイルから SaveGame データを生のバイナリ形式でロードすることができます。この関数は、SaveGame を作成しないという点を除き、LoadGameFromSlot と非常によく似ています。このロード方法の場合は、同期操作のみ使用できます。

TArray<uint8> OutSaveData;
if (UGameplayStatics::LoadDataFromSlot(OutSaveData, SlotNameString, UserIndexInt32))
{
    // The operation succeeded, and OutSaveData now contains a binary represenation of the SaveGame object.
}

You can also convert this binary data to a SaveGame object by calling`LoadGameFromMemory を呼び出すことで、このバイナリ データを SaveGame オブジェクトに変換することもできます。これは同期呼び出しで、成功すると新しい USaveGame` オブジェクトを、失敗すると null ポインタを返します。

if (UMySaveGame* SaveGameInstance = Cast<UMySaveGame>(LoadGameFromMemory(InSaveData)))
{
    // The operation succeeded, and SaveGameInstance was able to cast to type we expected (UMySaveGame).
}
Select Skin
Light
Dark

新しい Unreal Engine 4 ドキュメントサイトへようこそ!

あなたの声を私たちに伝えるフィードバックシステムを含め、様々な新機能について開発をおこなっています。まだ広く使える状態にはなっていないので、準備ができるまでは、ドキュメントフィードバックフォーラムで、このページについて、もしくは遭遇した問題について教えていただけると助かります。

新しいシステムが稼働した際にお知らせします。

フィードバックを送信