我读过很多关于字典和序列化等的文章,它们都有不同的处理方式。作为编码新手(在某种程度上),我很难弄清楚如何将我的字典放入列表或序列化以保存它,然后在播放时重新加载。顺便说一下,这是Unity。这是我用的。我有一个应用程序管理器,它主要是一组BOOL值,告诉我的任务系统是否完成了某些事情。比如&;GetWeapon false &;(然后当他们捡起它时,它会变成TRUE,告诉任务系统移动到下一个目标或完成)我有一个键值的起始列表。然后将它们放入字典中,并在其中更改值。我需要能够保存这些值并在LOAD时重新加载它们(游戏邦注:默认的PLAY模式是newgame——正如你在下面所看到的,它会重置字典并在开始状态下进行复制)。我知道这不会像我说的那么难,只是不理解整个连载的事情。大多数网站都显示像{key,value}这样的字典,所以我在迭代字典并捕获对并保存它们时迷失了方向。
以下是appmanager的部分代码(它是一个单例):// This holds any states you wish set at game startup
[SerializeField] private List<GameState> _startingGameStates = new List<GameState>();
// Used to store the key/values pairs in the above list in a more efficient dictionary
private Dictionary<string, string> _gameStateDictionary = new Dictionary<string, string>();
void Awake()
{
// This object must live for the entire application
DontDestroyOnLoad(gameObject);
ResetGameStates();
}
void ResetGameStates()
{
_gameStateDictionary.Clear();
// Copy starting game states into game state dictionary
for (int i = 0; i < _startingGameStates.Count; i++)
{
GameState gs = _startingGameStates[i];
_gameStateDictionary[gs.Key] = gs.Value;
}
OnStateChanged.Invoke();
}
public GameState GetStartingGameState(string key)
{
for (int i = 0; i < _startingGameStates.Count; i++)
{
if (_startingGameStates[i] != null && _startingGameStates[i].Key.Equals(key))
return _startingGameStates[i];
}
return null;
}
// Name : SetGameState
// Desc : Sets a Game State
public bool SetGameState(string key, string value)
{
if (key == null || value == null) return false;
_gameStateDictionary[key] = value;
OnStateChanged.Invoke();
return true;
}
尝试了类似的操作:
Dictionary<string, string> _gameStateDictionary = new Dictionary<string, string>
{
for (int i = 0; i < _gameStateDictionary.Count; i++)
string json = JsonConvert.SerializeObject(_gameStateDictionary, Formatting.Indented);
Debug.Log(json);
{
}
然而,我得到的只是列表中的第一项。(我确实在for循环中修改了上面的代码)我知道上面的代码是错误的,我做了其他迭代,只是为了让字典在控制台中打印出来。无论如何,只是要求一些代码帮助保存和加载字典。
既然你想保存和加载那些持久的无论如何,就我个人而言,我不会使用检查器,也不会为Unity序列化而烦恼,而是直接对json进行序列化/反序列化。
简单地把你的默认字典作为一个简单的json文件,例如
{
"Key1" : "Value1",
"Key2" : "Value2",
"Key3" : "Value3",
...
}
文件夹Assets/StreamingAssets
(如果它不存在,创建它)。如果到目前为止还不存在的话,这将是默认的备用文件。
运行时,您将从Application.streamingAssetsPath
加载它。
然后当你保存时,你不会把它放在那里,而是放在Application.persistentDataPath
using Newtonsoft.Json;
...
[SerializeField] private string fileName = "example.json";
private string defaultStatesPath => Path.Combine(Application.streamingAssetsPath, fileName);
private string persistentStatesPath => Path.Combine(Application.persistentDataPath, fileName);
private Dictionary<string, string> _gameStateDictionary
public void Load()
{
var filePath = persistentStatesPath;
if(!File.Exists(filePath))
{
filePath = defaultStatesPath;
}
var json = File.ReadAllText(filePath);
_gameStateDictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
}
public void Save()
{
var filePath = persistentStatesPath;
if(!Directory.Exists(Application.persistentDataPath))
{
Directory.CreateDirectory(Application.persistentDataPath);
}
var json = JsonConvert.SerializeObject(_gameStateDictionary, Formatting.intended);
File.WriteAllText(filePath, json);
}
如果你仍然想通过检查器编辑默认值,你可以合并两者,而不是使用StreamingAssets
do
[SerializeField] private GameState[] defaultStates;
public void Load()
{
var filePath = persistentStatesPath;
if(!File.Exists(filePath))
{
LoadDefaults();
return;
}
var json = File.ReadAllText(filePath);
_gameStateDictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
}
public void LoadDefaults()
{
_gameStateDictionary = defaultStates.ToDictionary(gameState => gameState.Key, gameState => gameState.Value);
}
然后你可以写
public string GetState(string key, string fallbackValue = "")
{
if(_gameStateDictionary.TryGetValue(key, out var value))
{
return value;
}
return fallbackValue;
}
您可以使用它的Keys
集合来迭代字典。
foreach (var key in myDictionary.Keys)
{
var val = myDictionary[key];
}
用键/值对填充你的数据结构,并序列化项目列表。
var missionItems = new List<MissionItem>();
foreach (var key in myDictionary.Keys)
{
var missionItem = new MissionItem();
missionItem.Key = key;
missionItem.Value = myDictionary[key];
missionItems.Add(missionItem);
}
var json = JsonUtility.ToJson(missionItems);
加载是直接的,反序列化数据,然后遍历所有项并将每个项添加到空字典中。
var missionItems = JsonUtility.FromJson<List<MissionItem>>(json);
foreach (var item in missionItems)
{
myDictionary.Add(item.Key, item.Value);
}
这是我最后的设置。我在另一个脚本(UI暂停菜单保存/加载按钮)中调用这些按钮
private bool useEncryption = true;
private string encryptionCodeWord = "CodeWordHere";
private static string fileName = "name.json";
private static string defaultStatesPath => Path.Combine(Application.streamingAssetsPath, fileName);
private static string persistentStatesPath => Path.Combine(Application.persistentDataPath, fileName);
public void SaveStates(int slotIndex)
{
var filePath = persistentStatesPath;
if(!Directory.Exists(Application.persistentDataPath))
{
Directory.CreateDirectory(Application.persistentDataPath);
}
var json = JsonConvert.SerializeObject(_gameStateDictionary, Formatting.Indented);
if (useEncryption)
{
Debug.Log("Using Encryption");
json = EncryptDecrypt(json);
}
File.WriteAllText(filePath + slotIndex, json);
}
public void LoadStates(int SlotIndex)
{
var filePath = persistentStatesPath;
if(!File.Exists(filePath + SlotIndex))
{
filePath = defaultStatesPath;
}
var json = File.ReadAllText(filePath + SlotIndex);
if (useEncryption)
{
Debug.Log("Using Encryption");
json = EncryptDecrypt(json);
}
_gameStateDictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
}
private string EncryptDecrypt(string data)
{
string modifiedData = "";
for (int i = 0; i < data.Length; i++)
{
modifiedData += (char)(data[i] ^ encryptionCodeWord[i % encryptionCodeWord.Length]);
}
return modifiedData;
}