Je trouve le meilleur moyen de sauvegarder les données de jeu dans le moteur de jeu Unity3D.
Au début, je sérialise des objets en utilisant BinaryFormatter
.
Mais j'ai entendu que cette façon de faire posait quelques problèmes et ne pouvait pas être sauvegardée.
Alors, quel est le meilleur moyen ou recommandé pour sauvegarder l'état du jeu?
Dans mon cas, le format de sauvegarde doit être un tableau d'octets.
Mais j'ai entendu que cette façon avait quelques problèmes et ne pouvait pas être sauvegardée.
C'est vrai. Sur certains appareils, il y a des problèmes avec BinaryFormatter
. Cela empire lorsque vous mettez à jour ou changez la classe. Vos anciens paramètres peuvent être perdus car les classes ne correspondent plus. Parfois, vous obtenez une exception lors de la lecture des données enregistrées à cause de cela.
De plus, sur iOS, vous devez ajouter Environment.SetEnvironmentVariable("MONO_REFLECTION_SERIALIZER", "yes");
ou vous aurez des problèmes avec BinaryFormatter
.
La meilleure façon d'économiser est avec PlayerPrefs
et Json
. Vous pouvez apprendre à le faire ici .
Dans mon cas, le format de sauvegarde doit être un tableau d'octets
Dans ce cas, vous pouvez le convertir en json puis convertir le tableau json string
en byte
. Vous pouvez ensuite utiliser File.WriteAllBytes
et File.ReadAllBytes
pour enregistrer et lire le tableau d'octets.
Voici une classe générique qui peut être utilisée pour enregistrer des données. Presque identique à this mais il n'utilise pas PlayerPrefs
. Il utilise un fichier pour enregistrer les données json.
DataSaver
classe:
public class DataSaver
{
//Save Data
public static void saveData<T>(T dataToSave, string dataFileName)
{
string tempPath = Path.Combine(Application.persistentDataPath, "data");
tempPath = Path.Combine(tempPath, dataFileName + ".txt");
//Convert To Json then to bytes
string jsonData = JsonUtility.ToJson(dataToSave, true);
byte[] jsonByte = Encoding.ASCII.GetBytes(jsonData);
//Create Directory if it does not exist
if (!Directory.Exists(Path.GetDirectoryName(tempPath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(tempPath));
}
//Debug.Log(path);
try
{
File.WriteAllBytes(tempPath, jsonByte);
Debug.Log("Saved Data to: " + tempPath.Replace("/", "\\"));
}
catch (Exception e)
{
Debug.LogWarning("Failed To PlayerInfo Data to: " + tempPath.Replace("/", "\\"));
Debug.LogWarning("Error: " + e.Message);
}
}
//Load Data
public static T loadData<T>(string dataFileName)
{
string tempPath = Path.Combine(Application.persistentDataPath, "data");
tempPath = Path.Combine(tempPath, dataFileName + ".txt");
//Exit if Directory or File does not exist
if (!Directory.Exists(Path.GetDirectoryName(tempPath)))
{
Debug.LogWarning("Directory does not exist");
return default(T);
}
if (!File.Exists(tempPath))
{
Debug.Log("File does not exist");
return default(T);
}
//Load saved Json
byte[] jsonByte = null;
try
{
jsonByte = File.ReadAllBytes(tempPath);
Debug.Log("Loaded Data from: " + tempPath.Replace("/", "\\"));
}
catch (Exception e)
{
Debug.LogWarning("Failed To Load Data from: " + tempPath.Replace("/", "\\"));
Debug.LogWarning("Error: " + e.Message);
}
//Convert to json string
string jsonData = Encoding.ASCII.GetString(jsonByte);
//Convert to Object
object resultValue = JsonUtility.FromJson<T>(jsonData);
return (T)Convert.ChangeType(resultValue, typeof(T));
}
public static bool deleteData(string dataFileName)
{
bool success = false;
//Load Data
string tempPath = Path.Combine(Application.persistentDataPath, "data");
tempPath = Path.Combine(tempPath, dataFileName + ".txt");
//Exit if Directory or File does not exist
if (!Directory.Exists(Path.GetDirectoryName(tempPath)))
{
Debug.LogWarning("Directory does not exist");
return false;
}
if (!File.Exists(tempPath))
{
Debug.Log("File does not exist");
return false;
}
try
{
File.Delete(tempPath);
Debug.Log("Data deleted from: " + tempPath.Replace("/", "\\"));
success = true;
}
catch (Exception e)
{
Debug.LogWarning("Failed To Delete Data: " + e.Message);
}
return success;
}
}
[~ # ~] utilisation [~ # ~] :
Exemple de classe à enregistrer:
[Serializable]
public class PlayerInfo
{
public List<int> ID = new List<int>();
public List<int> Amounts = new List<int>();
public int life = 0;
public float highScore = 0;
}
Enregistrer les données:
PlayerInfo saveData = new PlayerInfo();
saveData.life = 99;
saveData.highScore = 40;
//Save data from PlayerInfo to a file named players
DataSaver.saveData(saveData, "players");
Charger les données:
PlayerInfo loadedData = DataSaver.loadData<PlayerInfo>("players");
if (loadedData == null)
{
return;
}
//Display loaded Data
Debug.Log("Life: " + loadedData.life);
Debug.Log("High Score: " + loadedData.highScore);
for (int i = 0; i < loadedData.ID.Count; i++)
{
Debug.Log("ID: " + loadedData.ID[i]);
}
for (int i = 0; i < loadedData.Amounts.Count; i++)
{
Debug.Log("Amounts: " + loadedData.Amounts[i]);
}
Supprimer les données:
DataSaver.deleteData("players");