Я прочитал много сообщений о словарях, сериализации и т. д., и у всех у них разные способы ведения дел. Будучи новичком в кодировании (в некоторой степени), у меня возникли проблемы с выяснением того, как получить мой словарь в список или сериализовать, чтобы сохранить его, а затем перезагрузить в игре. Это Unity, кстати. Итак, вот что я использую. У меня есть диспетчер приложений, который в основном представляет собой набор значений BOOL, который сообщает моей системе миссий, было ли что-то выполнено или нет. Что-то вроде «GetWeapon FALSE» (затем, когда они поднимают его, оно меняется на TRUE, что говорит системе миссии перейти к следующей цели или завершить) Итак, у меня есть начальный список ключей, значений... затем они помещаются в словарь, и значения изменяются в нем. Мне нужно иметь возможность сохранять эти значения и перезагружать их при ЗАГРУЗКЕ (режим PLAY по умолчанию — новая игра — как вы видите ниже, он сбрасывает словарь и копирует его в начальные состояния). Я знаю, что это не может быть так сложно, как я это делаю, просто не понимаю всей сериализации. Большинство сайтов показывают словарь типа {key,value}, поэтому я теряюсь, перебирая словарь, захватывая пары и сохраняя их.
Вот частичный код менеджера приложений (это синглтон):
// 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). Я знаю, что приведенное выше неверно, я сделал другие итерации, чтобы просто распечатать словарь в консоли. В любом случае, просто попросите немного кода, чтобы сохранить и загрузить словарь.





Вы можете повторять словарь, используя его коллекцию 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);
}
Извините за 2-й комментарий, я действительно хочу поблагодарить вас за то, что нашли время ответить. Я знаю, что мне еще многому предстоит научиться! Особенно, если это ставит меня в тупик. Сохранение объекта и преобразований игрока было простым, понятия не имею, почему я нахожу это таким сложным...
Поскольку вы все равно хотите сохранять и загружать эти постоянные, лично я бы не стал использовать Inspector и вообще не беспокоиться о сериализации 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 сделать
[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;
}
Спасибо, я посмотрю на это поближе, извините за задержку, работаю 6 дней подряд и трудно добраться до ПК, чтобы наверстать упущенное! Я использую инспектор, потому что у меня есть специальное окно редактора, которое я могу использовать, которое позволяет мне добавлять эти значения в список, а затем изменять этот список в словарь, но диспетчер приложений также делает и другие вещи, например, отслеживает все объекты, доступные для сценариев. . Я включил только ту часть, с которой у меня проблемы.
Еще раз спасибо. Я немного изменил его, у меня есть 4 слота для сохранения, поэтому добавьте (int slotID) в сохранение / загрузку, затем добавил шифрование, так как это просто текстовый файл. Достаточно только для того, чтобы не допустить простого новичка, но в одиночной игре вы хотите обмануть, дерзайте. но в остальном он, кажется, работает сейчас. Я все еще использую свой метод списка, а затем словарь, не добавляя ключи/значения в код, как в вашем примере, он работал как бы «из коробки».
Вот моя последняя установка. Я вызываю их при нажатии кнопки в другом скрипте (кнопки сохранения/загрузки меню паузы пользовательского интерфейса)
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;
}
Спасибо за это. Я все еще немного борюсь. Я вижу, к чему вы клоните, и реализация может быть простой, но я пытаюсь заменить свои переменные для этого и натыкаюсь на контрольно-пропускной пункт. (не принимает уценку кода?) `var MissionItems = new List<MissionItem>(); foreach (ключ var в _gameStateDictionary.Keys) { var MissionItem = new MissionItem(); MissionItem.Key = ключ; MissionItem.Value = _gameStateDictionary[ключ]; МиссияЭлементы.Добавить(миссияЭлемент); }`