【Unity入門】スコアを保存!コピペで終わるPlayerPrefsの実装方法

みなさんこんにちは!

フリーランスプログラマーのsatoです。

ゲームを作る上で、もっとも重要な機能の一つにセーブがあると思います。

スコアや進捗の保存は是非とも実装したい機能ですよね。

とはいえ初心者にはハードルが高く見えるため、躊躇してしまう点だと思います。

しかしご安心ください。

Unityはセーブも簡単に実装できるようになっています!

その機能が今回の主役PlayerPrefsなんです。

それでは今回のアジェンダです。

[基本]PlayerPrefsとは?
[基本]PlayerPrefsの使い方!
[基本]PlayerPrefsをもっと詳しく!
[応用]PlayerPrefsを使う上でのよくある疑問

まず基本的な使い方を学び、続けて保存場所や安全性などのよくある疑問ついても見ていきましょう。

目次

PlayerPrefsとは?

PlayerPrefsとは一言で行ってしまえば「セーブ・ロード」などを行ってくれる仕組みです。

これを使えば、セーブもロードも自由自在です!

何はともあれ、まずは使い方を学んでみましょうか。

実際に使用する際には、PlayerPrefsクラスをスクリプトで呼び出す形で使用します。

PlayerPrefsの使い方!

今回は「スコアを保存する」といったシュチュエーションを軸にPlayerPrefsの使い方を見てみましょうか。

そのために、まず以下の記事を参考に、スコアを表示した状況から導入を開始します。

スコアを表示したら、そのスコアをゲーム開始時・終了時に保存することにしましょう。

一通り実装してみよう!

今回はいきなり一式実装してしまいましょう!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using UnityEngine.UI;  // 追加しましょう

public class ScoreManager : MonoBehaviour {

    public GameObject score_object = null; // Textオブジェクト
    public int score_num = 0; // スコア変数

    // 初期化時の処理
    void Start ()
    {
        // スコアのロード
        score_num = PlayerPrefs.GetInt ("SCORE", 0);
    }
    // 削除時の処理
    void OnDestroy(){
        // スコアを保存
        PlayerPrefs.SetInt ("SCORE", score_num);
        PlayerPrefs.Save ();
    }

    // 更新
    void Update ()
    {
        // オブジェクトからTextコンポーネントを取得
        Text score_text = score_object.GetComponent<Text> ();
        // テキストの表示を入れ替える
        score_text.text = "Score:" + score_num;

        score_num += 1; // とりあえず1加算し続けてみる
    }
}

先ほどのリンク先で作成している、スコアの管理者ScoreManagerクラスに処理を追記しました。

具体的な追記箇所のみを抽出すると、以下の部分になります。

// 初期化時の処理
void Start ()
{
    // スコアのロード
    score_num = PlayerPrefs.GetInt ("SCORE", 0);
}
// 削除時の処理
void OnDestroy(){
    // スコアを保存
    PlayerPrefs.SetInt ("SCORE", score_num);
    PlayerPrefs.Save ();
}

①初期化時に、PlayerPrefs.GetInt関数を使用して、スコアをロードしている。
②削除時に、PlayerPrefs.SetInt関数を利用し、スコアを保存している。

行っている内容としては、ただこれだけです!

※各関数の詳細は後ほど説明しますね!

実行してみよう!

実際に実行して挙動を見てみましょう!

ちょっとわかりづらいかもしれませんが…

一度目に起動後した時のスコアが、二度目の起動時に保持されていることがわかると思います。

「セーブ・ロード」は、意外に簡単に実装できることがわかったと思います。

PlayerPrefsをもっと詳しく!

では続けて、先ほどの処理を詳しく見てみましょうか。

保存(セーブ)について

// スコアを保存
PlayerPrefs.SetInt ("SCORE", score_num);
PlayerPrefs.Save ();

PlayerPrefs.SetInt関数を使用してスコアを保存しています。

第一引数に保存するデータの名前(これをロード時指定することになります)、第二引数に保存する数値を入れているわけですね。

一つ注意が必要なのは、PlayerPrefsへ保存データの設定が一通り終わったら、からなず最後にPlayerPrefs.Save関数実行する必要があることです。

なぜならPlayerPrefs.Save関数が呼び出された時に、PlayerPrefsに登録されている数値を実際に保存しているからです。

最後にPlayerPrefs.Save関数を呼び出さなければ保存がされないので注意しましょう!

読み込み(ロード)について

// スコアのロード
score_num = PlayerPrefs.GetInt ("SCORE", 0);

PlayerPrefs.GetInt関数は「第一引数に指定した名前で保存されている値」を戻り値として取得する関数です。

第二引数は、もし保存されていなかった場合、何を返すかの設定になります。

保存が理解でいていれば読み込みは簡単ですね!

Int型以外の保存について

ここまででSetInt・GetInt関数を使用したセーブ・ロード方法を見てきました。

しかしSetInt・GetInt関数は、その名の通りInt型でセーブ・ロードを行うため、他の型ではうまくいかないです。

そこで他の型での保存方法も見てみましょうか。

実はPlayerPrefsには、Int・Float・String形式で保存する関数が用意されているため、他の型での保存も簡単です!

SetIntkey で識別される設定情報の値(Int型)を設定します。
GetIntキーが存在する場合、key に対応する値(Int型)を取得します。
SetFloatkey で識別される設定情報の値(Float型)を設定します。
GetFloatキーが存在する場合、key に対応する値(Float型)を取得します。
SetStringkey で識別される設定情報の値(String型)を設定します。
GetStringキーが存在する場合、key に対応する値(String型)を取得します。

使い方は実例で見たときと同じです!

// スコアを保存
PlayerPrefs.SetString ("USER_NAME", "ユーザーの名前");
PlayerPrefs.Save ();

例えば、文字列型で保存したければ、こんな感じですね!

保存データが存在するか?

保存データが存在するかチェックする方法も準備されています。

それがPlayerPrefs.HasKey関数です。

これは引数で指定したデータが存在すればtreu、なければfalseを返してくれる関数です。

主な使い方としては以下のように、if文で「存在するとき」と「しないとき」の処理を分ける使い方でしょうか。

if (PlayerPrefs.HasKey ("SCORE")) {
    // 存在する
} else{
    // 存在しない
}

削除について

削除も簡単です。

PlayerPrefsには以下の二つを削除関数が用意されています。

// 保存データの全てを削除する
PlayerPrefs.DeleteAll();
// 引数で指定したキーを削除する
PlayerPrefs.DeleteKey("削除したいキー");

例えば先ほどのSCOREとして保存したデータのみを削除したい場合は以下のようにしましょう。

PlayerPrefs.DeleteKey("SCORE");

PlayerPrefsを使う上でのよくある疑問

ここまでで一通りPlayerPrefsの使い方を学んできました。

しかしまだまだ疑問が残っている人も多いのではないでしょうか。

そこでここからはよくある質問をまとめておきます。

参考にしてみてください。

どこに保存されるの?

環境によって保存場所は違います。

例えばMac環境ならば以下の箇所に保存されています。

/Users/[ユーザー名]/Library/Preferences/unity.[company name].[product name].plist

ちなみにWindowsの場合は、レジストリ。

iosならば「/Library/Preferences/[bundle identifier].plist」。

androidならば「/data/data/pkg-name/shared_prefs/pkg-name.xml」へデータが保存されます。

それぞれ保存場所が違うため気をつけましょう。

※また、プロジェクトに[company name]をつけていない場合、「DefaultCompany」となるので注意しましょう。

改ざんされない?

PlayerPrefsはローカル環境(ユーザーのPCやスマホの中)に保存されます。

つまりデータはユーザーの手元にあるわけです。

解析・改ざんされる可能性は高いことを理解しましょう。

一般商用のアプリケーションなどでは、その辺りの対策として、重要なデータはサーバーで保持し改ざんを防いでいます。

逆に改ざんを許容できるレベルの、個人作品ならばPlayerPrefsを使用しても問題ないでしょう。

壊れたりしない?

基本的にそうそう壊れることはありません。

ただし、ユーザーが間違えて手動で消してしまう可能性や、保存時の失敗で壊れる可能性も全くないわけではありません。

趣味レベルの規模の開発ならば、最悪消えてしまっても良いかもしれません。

しかしビジネスレベルの開発ならば、改ざんへの対策にもなりますし、サーバーに重要データを保存するなりの手段をとることが必要でしょう。

[補足]改ざん・破損への対策について

この辺りをビジネスレベルで実装する場合、やはり改ざん・破損が悩ましい部分になると思います。

そんなとき、それらを解決するメジャーな手段は以下の手段でしょう。

・重要データは通信でサーバーに保存し、ローカルには保持しない
・メールアドレスなどを使用した引き継ぎ機能の実装

過去自分が参加したプロジェクトでもこのような手段をとって対策を行いました。

一例の参考にしてみてください。

まとめ

今回はUnityでのデータのセーブ・ロードを見てきました。

PlayerPrefsを使えば、なかなか簡単に実現できることをわかっていただけたなら幸いです。

また最後の解析・改ざんについては、恐すぎてプロジェクトの進捗が遅れてしまっては本末転倒です。

その辺りのリスクはどこまで許容できるか、きっちり話し合ってどこまでコストをかけるかはちゃんと相談して進めましょう。

この記事を書いた人

学生時代を含めると、かれこれ10年以上プログラマーとして過ごしています。
様々な言語や環境、プロジェクトに関わってきましたので、より実践的な記事をみなさんにお届きるよう情報発信していきます!

目次