見出し画像

UnityのPlayerPrefs徹底まとめ |ゲームを閉じてもデータを保存する方法

Unityでゲームを作っていると、

「ゲームを閉じてもハイスコアを残したい」
「音量設定を保存しておきたい」
「プレイヤー名を次回起動時にも表示したい」

という場面があります。

このようなときに使えるのが、Unityの PlayerPrefs です。

PlayerPrefsを使うと、簡単にデータを保存して、次にゲームを起動したときに呼び出すことができます。

この記事では、PlayerPrefsの基本的な使い方から、配列やListの保存方法まで、初心者向けにまとめます。



1. PlayerPrefsとは?

PlayerPrefsは、Unityで簡単なデータを保存するための機能です。

たとえば、次のようなデータを保存できます。

  • ハイスコア

  • プレイヤー名

  • 音量設定

  • ステージのクリア状況

  • アイテムの獲得状況

イメージとしては、ゲームの中にある小さなメモ帳のようなものです。

ゲームを閉じても保存されるため、次にゲームを起動したときに、前回のデータを読み込むことができます。


2. PlayerPrefsで保存できるデータ

PlayerPrefsで保存できる主なデータ型は、次の3つです。

  • int(整数型) スコア、レベル、クリア済みフラグなど

  • float(小数型) 音量、、移動速度、経過時間など

  • string(文字列型) プレイヤー名、選択中のキャラクター名など


3. データを保存する方法

PlayerPrefsでデータを保存するときは、次のような命令を使います。

intを保存する

PlayerPrefs.SetInt("HighScore", 100);
PlayerPrefs.Save();

これは、HighScore という名前で、100 という整数を保存しています。


floatを保存する

PlayerPrefs.SetFloat("BGMVolume", 0.5f);
PlayerPrefs.Save();

これは、BGMVolume という名前で、0.5 という小数を保存しています。

音量設定などによく使います。


stringを保存する

PlayerPrefs.SetString("PlayerName", "Taro");
PlayerPrefs.Save();

これは、PlayerName という名前で、Taro という文字列を保存しています。


Save()について

PlayerPrefs.Save(); は、変更した内容を実際に保存するための命令です。

Unityでは、アプリ終了時に自動で保存されることもありますが、確実に保存したい場合は Save() を呼んでおくと安心です。

ただし、ゲーム中に何度も連続して呼ぶ必要はありません。

たとえば、

  • ハイスコアを更新したとき

  • 設定画面で音量を変更したとき

  • ステージをクリアしたとき

など、保存したいタイミングで呼び出すのがよいです。


4. データを読み込む方法

保存したデータを読み込むときは、GetInt()、GetFloat()、GetString() を使います。

intを読み込む

int highScore = PlayerPrefs.GetInt("HighScore", 0);

これは、HighScore という名前で保存されている整数を読み込んでいます。

後ろの 0 は、まだデータが保存されていなかった場合に使う初期値です。

つまり、まだハイスコアが保存されていなければ、0 が入ります。


floatを読み込む

float bgmVolume = PlayerPrefs.GetFloat("BGMVolume", 1.0f);

これは、BGMVolume を読み込んでいます。

保存データがない場合は、1.0f が使われます。


stringを読み込む

string playerName = PlayerPrefs.GetString("PlayerName", "名無し");

これは、PlayerName を読み込んでいます。

保存データがない場合は、名無し という文字列が使われます。


5. データがあるか調べる方法

保存データが存在するかどうかを調べたい場合は、HasKey() を使います。

if (PlayerPrefs.HasKey("HighScore"))
{
    Debug.Log("ハイスコアのデータがあります");
}
else
{
    Debug.Log("まだハイスコアは保存されていません");
}

HasKey は、指定した名前のデータが存在するかを調べる命令です。

保存データがある場合は true、ない場合は false になります。


6. データを削除する方法

保存したデータを削除したい場合は、DeleteKey() を使います。

PlayerPrefs.DeleteKey("HighScore");

これは、HighScore という名前のデータだけを削除します。

すべてのPlayerPrefsデータを削除したい場合は、次のように書きます。

PlayerPrefs.DeleteAll();

ただし、DeleteAll() はすべての保存データを消してしまうため、使うときは注意が必要です。


7. ハイスコアを保存するサンプル

ここでは、ハイスコアを保存する簡単なサンプルを見てみます。

using UnityEngine;

public class ScoreManager : MonoBehaviour
{
    public int score;

    public void SaveHighScore()
    {
        int highScore = PlayerPrefs.GetInt("HighScore", 0);

        if (score > highScore)
        {
            PlayerPrefs.SetInt("HighScore", score);
            PlayerPrefs.Save();

            Debug.Log("ハイスコアを更新しました");
        }
    }

    public void LoadHighScore()
    {
        int highScore = PlayerPrefs.GetInt("HighScore", 0);
        Debug.Log("現在のハイスコア:" + highScore);
    }
}

このコードでは、現在のスコアが保存済みのハイスコアより高い場合だけ、新しいハイスコアとして保存しています。

ポイントは、次の部分です。

int highScore = PlayerPrefs.GetInt("HighScore", 0);

まず、保存されているハイスコアを読み込みます。

そして、

if (score > highScore)

現在のスコアがハイスコアより高ければ、保存し直します。


8. 配列・リストをPlayerPrefsに保存する方法

PlayerPrefsは便利ですが、配列やListをそのまま保存することはできません。

たとえば、次のようなListがあったとします。

List<string> itemList = new List<string>();

itemList.Add("Sword");
itemList.Add("Shield");
itemList.Add("Potion");

このListを、そのままPlayerPrefsに保存することはできません。

そのため、配列やListを保存したい場合は、いったん1つの文字列に変換して保存する必要があります。


8-1. 配列やListはそのまま保存できない

配列やListは、複数のデータをまとめて管理するためのものです。

たとえば、次のような配列があります。

string[] itemNames = { "Sword", "Shield", "Potion" };

中には、

Sword
Shield
Potion

という3つのデータが入っています。

しかし、PlayerPrefsはこの配列をそのまま保存できません。

そこで、これらのデータを次のような1つの文字列にします。

Sword@Shield@Potion

このように、データとデータの間に @ などの記号を入れて、1本の文字列に変換します。
※サンプルでは@を使っていますが、","、"/" など保存したい文字列に含まれない記号であればOKです。


8-2. 1つの文字列に変換し保存する

データをつなげるときに使う記号のことを、ここでは区切り文字として考えます。

たとえば、@ を区切り文字にすると、次のようになります。

Sword@Shield@Potion

この場合、

  • Sword

  • Shield

  • Potion

という3つのデータを、@ でつなげています。

保存するときは1つの文字列として保存し、読み込むときに @ の位置で分解します。このようにすれば、PlayerPrefsでも配列やListのようなデータを保存できます。

下はListを文字列に変換して保存するサンプルです。

using System.Collections.Generic;
using UnityEngine;

public class ItemSaveSample : MonoBehaviour
{
    public List<string> itemList = new List<string>();

    public void SaveItems()
    {
        string saveText = string.Join("@", itemList);

        PlayerPrefs.SetString("ItemList", saveText);
        PlayerPrefs.Save();

        Debug.Log("保存したデータ:" + saveText);
    }
}

ポイントは、次の部分です。

string saveText = string.Join("@", itemList);

string.Join() は、Listや配列の中身を指定した文字でつなげる命令です。

この例では、Listの中身を @ でつなげています。

たとえば、Listの中身が次のようになっていた場合、

Sword
Shield
Potion

保存される文字列は、次のようになります。

Sword@Shield@Potion

8-3. Splitで分解してListに戻す

保存した文字列を読み込むときは、Split() を使います。

using System.Collections.Generic;
using UnityEngine;

public class ItemLoadSample : MonoBehaviour
{
    public List<string> itemList = new List<string>();

    public void LoadItems()
    {
        string saveText = PlayerPrefs.GetString("ItemList", "");

        if (saveText != "")
        {
            string[] itemArray = saveText.Split('@');

            itemList = new List<string>(itemArray);
        }

        foreach (string item in itemList)
        {
            Debug.Log(item);
        }
    }
}

ポイントは、次の部分です。

string[] itemArray = saveText.Split('@');

Split('@') と書くことで、@ の位置で文字列を分解できます。

たとえば、保存されていた文字列が次のようなものだったとします。

Sword@Shield@Potion

これを @ で分解すると、

Sword
Shield
Potion

という3つのデータに戻すことができます。


8-4. 2次元配列を保存する考え方

ゲーム制作では、表のようなデータを保存したいこともあります。

たとえば、次のようなマップデータです。

このようなデータは、横方向と縦方向があります。

  • 横方向:Column

  • 縦方向:Row

2次元配列を保存する場合は、ColumnとRowで区切り文字を分けると扱いやすくなります。


8-5. ColumnとRowで区切り文字を分ける

たとえば、横方向のColumnは @ でつなげます。

Grass@Water@Wall

そして、縦方向のRowは / でつなげます。

Grass@Water@Wall/Grass@Grass@Wall/Start@Grass@Goal

この文字列は、次のような意味になります。

Grass@Water@Wall
Grass@Grass@Wall
Start@Grass@Goal

つまり、

  • Column同士は @ で区切る

  • Row同士は / で区切る

というルールにしています。

このようにしておくと、読み込むときに

  1. まず / でRowごとに分ける

  2. 次に @ でColumnごとに分ける

という流れで、元の2次元データに戻すことができます。


8-6. 2次元配列を保存するサンプル

次は、2次元配列をPlayerPrefsに保存するサンプルです。

using UnityEngine;

public class MapSaveSample : MonoBehaviour
{
    string[,] mapData = new string[,]
    {
        { "Grass", "Water", "Wall" },
        { "Grass", "Grass", "Wall" },
        { "Start", "Grass", "Goal" }
    };

    public void SaveMapData()
    {
        string saveText = "";

        int rowLength = mapData.GetLength(0);
        int columnLength = mapData.GetLength(1);

        for (int row = 0; row < rowLength; row++)
        {
            string rowText = "";

            for (int column = 0; column < columnLength; column++)
            {
                rowText += mapData[row, column];

                if (column < columnLength - 1)
                {
                    rowText += "@";
                }
            }

            saveText += rowText;

            if (row < rowLength - 1)
            {
                saveText += "/";
            }
        }

        PlayerPrefs.SetString("MapData", saveText);
        PlayerPrefs.Save();

        Debug.Log("保存したマップデータ:" + saveText);
    }
}

このコードを実行すると、次のような文字列が保存されます。

Grass@Water@Wall/Grass@Grass@Wall/Start@Grass@Goal

少し長く見えますが、考え方はシンプルです。

まず、1行分のデータを @ でつなげます。

Grass@Water@Wall

そして、それぞれの行を / でつなげます。

Grass@Water@Wall/Grass@Grass@Wall/Start@Grass@Goal

8-7. 2次元配列を読み込むサンプル

次に、保存した2次元データを読み込むサンプルです。

using UnityEngine;

public class MapLoadSample : MonoBehaviour
{
    public void LoadMapData()
    {
        string saveText = PlayerPrefs.GetString("MapData", "");

        if (saveText == "")
        {
            Debug.Log("保存データがありません");
            return;
        }

        string[] rows = saveText.Split('/');

        for (int row = 0; row < rows.Length; row++)
        {
            string[] columns = rows[row].Split('@');

            for (int column = 0; column < columns.Length; column++)
            {
                Debug.Log("Row:" + row + " Column:" + column + " Data:" + columns[column]);
            }
        }
    }
}

ポイントは、次の部分です。

string[] rows = saveText.Split('/');

まず、/ で分解してRowごとに分けます。

次に、

string[] columns = rows[row].Split('@');

Rowごとの文字列を、さらに @ で分解してColumnに分けます。

これで、保存されていた1つの文字列から、RowとColumnのデータを取り出すことができます。


8-8. 区切り文字を使うときの注意点

この方法はシンプルで便利ですが、注意点があります。

それは、データの中に区切り文字として使っている記号を入れないことです。

たとえば、@ を区切り文字にしている場合、データの中に @ が含まれていると、正しく分解できなくなります。

例として、次のようなデータがあったとします。

Sword@Fire@Shield

この場合、@ で分解すると、

Sword
Fire
Shield

の3つに分かれてしまいます。

もし本当は Sword@Fire という1つの名前として扱いたかった場合でも、正しく読み込めません。

そのため、区切り文字には、データの中に絶対に使わない記号を選ぶ必要があります。

よく使われる区切り文字には、次のようなものがあります。

@
/
|
,
:

ただし、プレイヤーが自由に名前を入力できるような場合は、どの記号が入力されるかわかりません。

そのような場合は、区切り文字で保存する方法ではなく、JSONなど別の保存方法を検討した方が安全です。


8-9. 複雑なデータはJSON保存も検討する

配列やListを保存する方法として、区切り文字を使う方法はとてもわかりやすいです。

初心者向けには、

string.Join()
Split()
PlayerPrefs.SetString()
PlayerPrefs.GetString()

の組み合わせで理解しやすいと思います。

ただし、次のような複雑なデータを保存したい場合は、JSON形式で保存する方法もあります。

  • キャラクターのステータス

  • アイテムの個数や種類

  • 複数のセーブデータ

  • ユーザーが自由に入力する文字列

  • 大きなマップデータ

PlayerPrefsはあくまで簡単なデータ保存に向いています。

複雑なセーブデータを扱う場合は、JSONファイルとして保存する方法も覚えておくとよいです。


9. まとめ

PlayerPrefsは、Unityで簡単なデータを保存するための便利な機能です。

保存するときは、データの種類に合わせて次の命令を使います。

PlayerPrefs.SetInt("Score", 100);
PlayerPrefs.SetFloat("BGMVolume", 0.5f);
PlayerPrefs.SetString("PlayerName", "Taro");

読み込むときは、次の命令を使います。

int score = PlayerPrefs.GetInt("Score", 0);
float bgmVolume = PlayerPrefs.GetFloat("BGMVolume", 1.0f);
string playerName = PlayerPrefs.GetString("PlayerName", "名無し");

そして、保存内容を確実に反映したい場合は、次のように Save() を呼び出します。

PlayerPrefs.Save();

また、配列やListを保存したい場合は、そのまま保存するのではなく、いったん1つの文字列に変換します。

たとえば、Listなら、

Sword@Shield@Potion

2次元配列なら、

Grass@Water@Wall/Grass@Grass@Wall/Start@Grass@Goal

のように、区切り文字を使って保存することができます。

PlayerPrefsは、初心者でも使いやすい保存機能です。

まずは、ハイスコアや音量設定など、簡単なデータの保存から試してみるとよいでしょう。


▼ Unity初心者向け記事まとめはこちら


こちらのマガジン「ミニゲーム作成講座 全8回セット」でもシーンの切り替えなどを活用して、初心者でも知識ゼロから作れるミニゲーム作成講座を紹介しています。

さらにステップアップの「スマホで遊ぶジャンプゲーム 8回セット」のマガジンもぜひご活用ください。


ファイブボックスでは、スクラッチやUnityの個別指導のオンラインレッスンを行っています。
ご興味のある方は当サイト、オンラインレッスンから、無料体験授業へお問い合わせ下さい。

いいなと思ったら応援しよう!

ファイブボックス よろしければ応援お願いします! いただいたチップはクリエイターとしての活動費に使わせていただきます!