LoginSignup
9
10

More than 1 year has passed since last update.

Unity C# セーブデータ作成(暗号化と復号化)

Last updated at Posted at 2021-11-17

#はじめに
Unityでセーブをする時に、PlayerPrefsでは、レジストリに保存されてしまうので、
ローカルに保存できるようにセーブファイルを作成する方法を模索しました。
参考にしていただければと思います。
#目次

  • 流れ
  • コード
  • コードの説明
  • Unityに設定
  • 参考サイト

#流れ

ファイルを読み込む

ファイルを保存する

ファイルの値を反映する

#コード

必要なクラス

  • SaveData
  • GameData
  • Save
  • Read
  • DataManager

###SaveData.cs

まずセーブするための項目を用意します

SaveData
[System.Serializable]
public class SaveData
{
    public int numberInt;
    public float numberFloat;
    public string wordString;
    public bool isDoingSomething;
}

###GameData.cs
ゲーム中で保持しておきたい項目を用意します
(初期の値は任意です)

GameData
public class GameData
{
    public static int numberInt = 1;
    public static float numberFloat = 1.5f;
    public static string wordString = "Hellow";
    public static bool isDoingSomething = true;
}

###Save.cs
データをファイルに保存します

Save
using System.IO;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;

public class Save : MonoBehaviour
{
     void OnEnable()
    {
        DoSave();
    }

    private void DoSave()
    {
        //セーブファイルのパスを設定
        string SaveFilePath = Application.persistentDataPath + "/save.bytes";
        // セーブデータの作成
        SaveData saveData = CreateSaveData();
        // セーブデータをJSON形式の文字列に変換
        string jsonString = JsonUtility.ToJson(saveData);
        // 文字列をbyte配列に変換
        byte[] bytes = Encoding.UTF8.GetBytes(jsonString);
        // AES暗号化
        byte[] arrEncrypted = AesEncrypt(bytes);
        // 指定したパスにファイルを作成
        FileStream file = new FileStream(SaveFilePath, FileMode.Create, FileAccess.Write);

        //ファイルに保存する
        try
        {
            // ファイルに保存
            file.Write(arrEncrypted, 0, arrEncrypted.Length);
           
        }
        finally
        {
            // ファイルを閉じる
            if (file != null)
            {
                file.Close();
            }              
        }
        this.enabled = false;//このスクリプトをオフにする
    }

    // セーブデータの作成
    private SaveData CreateSaveData()
    {
        //セーブデータのインスタンス化
        SaveData saveData = new SaveData();
        //ゲームデータの値をセーブデータに代入
        saveData.numberInt = GameData.numberInt;
        saveData.numberFloat = GameData.numberFloat;
        saveData.wordString = GameData.wordString;
        saveData.isDoingSomething = GameData.isDoingSomething;

        return saveData;
    }


    /// AesManagedマネージャーを取得
 
    private AesManaged GetAesManager()
    {
        //任意の半角英数16文字
        string aesIv = "1234567890123456";
        string aesKey = "1234567890123456";

        AesManaged aes = new AesManaged();
        aes.KeySize = 128;
        aes.BlockSize = 128;
        aes.Mode = CipherMode.CBC;
        aes.IV = Encoding.UTF8.GetBytes(aesIv);
        aes.Key = Encoding.UTF8.GetBytes(aesKey);
        aes.Padding = PaddingMode.PKCS7;
        return aes;
    }

    /// AES暗号化
    public byte[] AesEncrypt(byte[] byteText)
    {
        // AESマネージャーの取得
        AesManaged aes = GetAesManager();
        // 暗号化
        byte[] encryptText = aes.CreateEncryptor().TransformFinalBlock(byteText, 0, byteText.Length);

        return encryptText;
    }

}

###Read.cs
ファイルのデータを読み込みます

Read
using System.IO;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;

public class Read : MonoBehaviour
{
    void OnEnable()
    {
        DoRead();
    }

    private void DoRead()
    {
        //セーブファイルのパスを設定
        string SaveFilePath = Application.persistentDataPath + "/save.bytes";

        //セーブファイルがあるか
        if (File.Exists(SaveFilePath))
        {
            //ファイルモードをオープンにする
            FileStream file = new FileStream(SaveFilePath, FileMode.Open, FileAccess.Read);
            try
            {
                // ファイル読み込み
                byte[] arrRead = File.ReadAllBytes(SaveFilePath);

                // 復号化
                byte[] arrDecrypt = AesDecrypt(arrRead);

                // byte配列を文字列に変換
                string decryptStr = Encoding.UTF8.GetString(arrDecrypt);

                // JSON形式の文字列をセーブデータのクラスに変換
                SaveData saveData = JsonUtility.FromJson<SaveData>(decryptStr);

                //データの反映
                ReadData(saveData);

            }
            finally
            {
                // ファイルを閉じる
                if (file != null)
                {
                    file.Close();
                }
            }
        }     
        else
        {
            Debug.Log("セーブファイルがありません");
            
        }

        this.enabled = false;

    }

    //データの読み込み(反映)
    private void ReadData(SaveData saveData)
    {
        GameData.numberInt = saveData.numberInt;
        GameData.numberFloat = saveData.numberFloat;
        GameData.wordString = saveData.wordString;
        GameData.isDoingSomething = saveData.isDoingSomething;
    }


    /// AesManagedマネージャーを取得
    private AesManaged GetAesManager()
    {
        //任意の半角英数16文字
        string aesIv = "1234567890123456";
        string aesKey = "1234567890123456";

        AesManaged aes = new AesManaged();
        aes.KeySize = 128;
        aes.BlockSize = 128;
        aes.Mode = CipherMode.CBC;
        aes.IV = Encoding.UTF8.GetBytes(aesIv);
        aes.Key = Encoding.UTF8.GetBytes(aesKey);
        aes.Padding = PaddingMode.PKCS7;
        return aes;
    }

    /// AES復号化
    public byte[] AesDecrypt(byte[] byteText)
    {
        // AESマネージャー取得
        var aes = GetAesManager();
        // 復号化
        byte[] decryptText = aes.CreateDecryptor().TransformFinalBlock(byteText, 0, byteText.Length);

        return decryptText;
    }

  }

###DataManager.cs
データをセーブしたり読み込んだりします

DataManager
using UnityEngine;

public class DataManager : MonoBehaviour
{
    //クラスの参照
    public Save saveClass;
    public Read readClass;

    void Start()
    {
        Read();
        Save();
        Read();
    }

    private void Read()
    {
        //読み込む
        readClass.enabled = true;
        Debug.Log("読み込みがおわりました");
    }

    private void Save()
    {
        //セーブする
        saveClass.enabled = true;     
        Debug.Log("セーブができました");
    }
}

#コードの説明

  • SaveData.cs

セーブデータに入れるデータです。

[System.Serializable]を付けて、publicで変数を設定してください。
  • GameData.cs

・ゲームの中で、常に持っておきたいデータです。

これは、変数にstaticを付けています。
データを読み込んで、各クラスの変数に代入する時には便利かと思います。
他に方法があると思いますので、参考程度にどうぞ。
  • Save.cs

・データを保存するスクリプトです。

セーブデータの場所を設定
↓
セーブデータを作成
↓
Json形式に変換
↓
byte配列に変換
↓
AES暗号化
↓
指定したパスにファイルを作成
↓
ファイルを保存
↓
ファイルを閉じる
・セーブデータの場所はこちらになります。(PC)
C:\Users\User(ユーザーネーム)\AppData\LocalLow\DefaultCompany(プロジェクトカンパニー)\SampleForQiita(プロジェクトネーム)
  • Read.cs

・データを読み込むスクリプトです。

セーブファイルの場所を設定
↓
セーブファイルがあるか確認
↓
ファイルモードをオープンにする
↓
byteのファイルを読み込み
↓
複合化
↓
byte配列を文字列に変換
↓
JSON形式の文字列をセーブデータのクラスに変換
↓
データを反映
↓
ファイルを閉じる
  • DataManager.cs

・Unityで設定します

空のGameObjectを作成
↓
そこに、Read.cs、Save.cs、DataManager.csをアタッチします。
↓
DataManager(Script)のところに、Read.csとSave.csをアタッチします。
↓
Read.csとSave.csをOFFにしておきます
↓
エディターを再生します。図1
↓
C:\Users\User(ユーザーネーム)\AppData\LocalLow\DefaultCompany(プロジェクトカンパニー)\SampleForQiita(プロジェクトネーム)
にセーブファイルが作成されます。図2
↓
セーブデータの中身が暗号化されています。図3

図1
ImageForQiita1.jpg

図2
ImageForQiita2.jpg

図3
ImageForQiita3.jpg

#参考サイト

「Unity C# データを暗号化・復号化(AESとXOR)」 By @OnederAppli様

〇こちらの記事を書くにあたり、大変参考になりました。ありがとうございました。

9
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
10