Обновление: эта проблема может быть вызвана проблемами бинарного форматирования при редактировании данных в существующих полях.Комментарий, который я больше не могу найти, описывает альтернативные методы, которые я сейчас реализую.Обновится после того, как эти методы будут предприняты, если это решение проблемы.
Я должен начать с того, что я студент, поэтому, пожалуйста, будьте осторожны со мной, я получил уведомление, когда впервые начал приезжать сюда, и надеюсь, чтоПродолжай учиться.Я новичок в единстве, мой C # приличный, но полный пробелов, так как мое обучение было довольно ужасным.Я смотрел сотни часов уроков по единству и изучаю новые концепции, которые я изучаю по 4 часа каждую ночь после того, как я ухожу с работы, поэтому, если вы видите что-то, просто дайте мне знать.
На самом деле это проблемаЯ имел некоторое время, но думал, что я исправил несколько месяцев назад.Я пытался сохранить игры в первый раз, и читал в двоичном формате и тому подобное, чтобы сохранить.У меня были проблемы с его установкой, но мне удалось его сохранить и правильно извлечь из файла.Я проверяю, что данные, поступающие в файл, верны, а выходящие данные верны, и даже сделали данные частными с помощью функции управления, так что ничто не сможет получить к ним доступ и изменить их, не выполняя мою отладку.И все же после того, как я покидаю область, в которой я определяю данные, они меняются, не имея доступа к моей функции обновления.
Чтобы разбить его, у меня есть класс PlayerType, в котором хранится вся информация об игроке, включая мой менеджер сцены, и он сериализует ее и сохраняет в виде списка.Я создаю цикл for, используя текущую длину загруженного списка, используя экземпляр класса saveload (это то, что содержит список сохраненных игр и доступ к файлу), и он перебирает экземпляры моих кнопок в порядке.Слот 1 будет нажимать, чтобы сохранить игру 1 и так сказать.Проблема, с которой я сталкиваюсь - щелчок по слоту 1, щелчок по слоту 16, так же как и по слоту 2. На первый взгляд кажется, что кнопки на какой слот идут практически случайно.Здесь я должен сказать, что не уверен, идет ли он в неправильный слот или просто переименовывает имена игроков неправильно, но в любом случае это не так.
Вот моя функция загрузки
public void Load() //Loads file from .gd file after checking if exists, then deserializes it back into a list
{
accessDataPath(false);
Debug.Log("Size of Save File" + listSize);
for (int i = 0; i < listSize; i++)
{
Debug.Log("First Loop " + SavedGames[i].returnName());
}
foreach (PlayerType player in GameManager.instance.saveStorage.returnList())
{
Debug.Log("Second Loop" + player.returnName());
}
}
и вот моя функция accessDataPath
public void accessDataPath(bool isSave)
{
//This stucture checks if file exists or not, then checks if saving or loading for 4 outcomes
if (isSave && SavedGames == null)//if saving and save file to update has nothing in it
{
Debug.Log("Error attempted to save null list in SaveLoad.accessDataPath!");
}
if (File.Exists(Application.persistentDataPath + "/SavedGames.gd"))//if the file exists
{
if (isSave)//if you are saving
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + "/SavedGames.gd", FileMode.Open);
bf.Serialize(file, SavedGames);
file.Close();
}
else //if you are not saving
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + "/SavedGames.gd", FileMode.Open);
SavedGames = (List<PlayerType>)bf.Deserialize(file);
file.Close();
listSize = SavedGames.Count;
}
}
else//if the file does not exist
{
if (isSave)//if you are saving
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Create(Application.persistentDataPath + "/SavedGames.gd");
bf.Serialize(file, SavedGames);
file.Close();
}
else//if you are not saving
Debug.Log("Error Loading File. Does not Exist!");//Display Later that file does not exist to user
}
updateNames();
}//End accessDataPath
вот функция, которая обновляет имена
public void updateNames()
{
for (int i = 0; i < listSize; i++)
{
SavedGames[i].updateName("Player " + i);
Debug.Log("Bump " + i);
}
}
Как видите, я проверяю, существует ли она, затем проверьте, сохраняю ли я или загружаю.Вызов функции сохранения с истиной, а SavedGames - это список, извлекаемый из файла.Теперь, после запуска изменения имени, я могу проверить, работает ли оно, и оно работает.Запустив проверку здесь, они все возвращаются как правильное имя, однако к тому времени, когда он возвращается к моей функции загрузки и запускает мой первый цикл, они ошибаются, он никогда не покидает этот раздел кода, но как только он выходит из области, которую они изменяютбыть почти случайным.Теперь у меня была эта проблема некоторое время, но я подумал, что это связано с моим файлом, возможно, с поврежденными данными, поэтому я удалил игру сохранения и создал новые для тестирования.Числа изменились, но все еще были не правы.Это говорит мне о том, что файл каким-то образом влияет на имена, хотя я переименую их почти сразу после их выхода.Я не привык к загрузке или сохранению в файлах, поэтому я не уверен, с чего начать.
Я опубликую больше своего кода ниже на случай, если какой-то из них окажется явно неправильным, я также ценю советпо структуре, когда я брал уроки в колледже по программированию игр, но они были ужасны и заполнены пробелами, даже если вы не нашли ответа на мою проблему.
Сначала я включил или выключил настройку системы меню., вызванный событиями onclick.
public class SaveMenu : MonoBehaviour {
public GameObject menu;
bool isActive;
bool isSave;
PopulateSave playerSaves;
public static SaveMenu instance;
void Awake()
{
isSave = false;
instance = this;
menu = GameObject.Find ("SaveList");
menu.SetActive (false);
isActive = false;
playerSaves = menu.GetComponentInChildren<PopulateSave> ();
}
public bool getActive()
{
return isActive;
}
public void toggleMenu(bool saveLoad)
{
if (isActive)
{
menu.SetActive (false);
isActive = false;
} else
{
menu.SetActive (true);
isActive = true;
}
bool isSave = saveLoad;
menu.transform.Find("Scroll View").transform.Find("Viewport").transform.Find("Content").transform.Find("NewSave").gameObject.SetActive(isSave);
Debug.Log(isSave);
}
public void updateSave()
{
playerSaves.startList();//Seems redundant but is used to make this access public with limited use
}
public bool getSave()
{
return isSave;
}
}
После того, как все создано, я называю populateaves ребенком, потому что у меня не было проблем с ним, когда я пытался вызвать его через инспектора.PopulateSaves - это место, где находится большая часть моего функционального кода.
public class PopulateSave : MonoBehaviour{
public Button NewSave;
public Button OldSaves; // This is our prefab object that will be exposed in the inspector
void Awake()
{
GameManager.instance.saveStorage.Load();
Populate();
}
void Update()
{
}
void Populate()
{
Button newObj = Instantiate(NewSave, transform); // Create GameObject instance
newObj.name = "NewSave";
startList();
}
public void startList()
{
clearList();
for (int i = 1; i < GameManager.instance.saveStorage.returnCount() + 1; i++)
{
createButton(i);
}
Debug.Log("Done creating");
}
public void updateList(PlayerType newSave)
{
Button newObj;
newObj = (Button)Instantiate(OldSaves, transform);
//GameManager.instance.saveStorage.Save(i);
}
public void clearList()
{
GameObject[] gameObjects;
gameObjects = GameObject.FindGameObjectsWithTag("SaveSlot");
for (var i = 0; i < gameObjects.Length; i++)
Destroy(gameObjects[i]);
Debug.Log("Done Destroying");
}
public void ButtonClicked(int slot)
{
if (SaveMenu.instance.getSave())
{
Debug.Log("Save");
GameManager.instance.saveStorage.Save(slot);
}
else
{
Debug.Log("load");
GameManager.instance.currentPlayer.newPlayer(slot);
}
}
public void createButton(int i)
{
// Create new instances of our prefab until we've created as many as is in list
Button newObj = (Button)Instantiate(OldSaves, transform);
//increment slot names
newObj.name = "Slot " + i;
newObj.GetComponentInChildren<Text>().text = "Slot " + i;
newObj.onClick.AddListener(() => ButtonClicked(i));
}
}
Теперь я также никогда не писал слушателю со сценарием, как у меня здесь, может ли этот раздел назначать им неправильный номер?Я проверил, чтобы убедиться, что все мои индексы имеют правильные числа, если они не равны 1.Один из моих циклов может использовать настройку, которая имеет значение 1, но я больше беспокоюсь о том, чтобы снять это с земли и исправить особенности в этой точке.
Вот хранилище моего игрока
[System.Serializable]
public class PlayerType {
string playerName;
SceneManagement currentScene;
public PlayerType()
{
playerName = "Starting Name";
}
public void updateName(string name)
{
//Debug.Log("New Name: " + name);
playerName = name;
}
public void updateScene(SceneManagement newScene)
{
currentScene = newScene;
}
public string returnName()
{
return playerName;
}
public SceneManagement returnScene()
{
return currentScene;
}
public void newPlayer(int slotSave)
{
//Tmp player has wrong name from this point, initiated wrong?
//Debug.Log("New Name to update" + tmpPlayer.returnName());
this.updateName(GameManager.instance.saveStorage.returnSaves(slotSave).returnName());
this.updateScene(GameManager.instance.saveStorage.returnSaves(slotSave).returnScene());
}
}
Обновление: Bump корректно отображает 0-16, затем Размер файла сохранения отображает 17 полных сохранений. Первый цикл начинается с вывода «First Loop Player 15» в общей сложности 16 раз. Затем он отображает 16, так что последний правильный, хотя и один.я думаюВторой цикл делает то же самое, что и первый, что неудивительно.
Я оставил вызов updateNames, но закомментировал строки и выполнил его, включая устранение неровностей.Он начинается с 17-ти сохранений снова и 16-кратной итерации 15-го игрока, однако на этот раз вокруг последнего отображается «Temp Name», которое я определяю только один раз в начале сценария sceneManagement для текущего игрока, оно никогда не должно быть сохраненои даже если бы это должно было быть перезаписано моим именем цикла, по крайней мере, это было моим намерением.
SceneManagement
[System.Serializable]
public class SceneManagement : MonoBehaviour {
DialogueManager dialogueManager;
PlayerType currentPlayer;
bool isSave;
bool isActive;
string sceneName;
int lineCount;
void Start()
{
isSave = false;
//loads player object for the current save
currentPlayer = new PlayerType();
currentPlayer.updateName ("Temp Name");
//This loads the prologue from the DB and sets the dialoguemanager up, defaults to prologue for now but can be updated to another scene later
isActive = true;
sceneName = "Prologue";
string conn = "URI=file:" + Application.dataPath + "/Text/Game.sqlite3";
List<string> sceneLines = new List<string>();
List<string> sceneCharacters = new List<string>();
int tmpInt;
string tmpString = "NOTHING";
int count = 0;
lineCount = 1;
IDbConnection dbConn;
dbConn = (IDbConnection)new SqliteConnection (conn);
dbConn.Open (); //Open database connection
IDbCommand dbCmd = dbConn.CreateCommand();
string sqlQuery = "SELECT Line, Flags, Character, Image, Text, Color FROM Prologue";
dbCmd.CommandText = sqlQuery;
IDataReader reader = dbCmd.ExecuteReader ();
while (reader.Read ()) {
tmpInt = reader.GetInt32 (0);
tmpString = reader.GetString (1);
sceneCharacters.Add(reader.GetString (2));
tmpInt = reader.GetInt32 (3);
sceneLines.Add(reader.GetString (4));
tmpString = reader.GetString (5);
//Debug.Log (tmpString);
//Debug.Log (count);
count++;
}
reader.Close ();
reader = null;
dbCmd.Dispose ();
dbCmd = null;
dbConn.Close ();
dbConn = null;
dialogueManager = new DialogueManager(sceneCharacters, sceneLines, lineCount);
}
//These are the returnvalues that might be used, may or may not be kept depending on future use.
public string getSceneName()
{
return sceneName;
}
public int getLineCount()
{
return lineCount;
}
public bool getSave()
{
return isSave;
}
//These return the lines for displaymanager, preventing it from directly interacting with dialoguemanager
public string getNextLine()
{
return dialogueManager.getNextLine();
}
public string getNextCharacter()
{
return dialogueManager.getNextCharacter();
}
//This function sets up visibility and is only accessed to properly display the screen after the scene has been started.
public void startScene ()
{
GameManager.instance.screenDisplay.changeVisible(true);
}
void Update()
{
if (Input.GetKeyDown ("space") & isActive) {
dialogueManager.incrementCurrentLine ();
GameManager.instance.screenDisplay.changeText(dialogueManager.getNextLine ());
GameManager.instance.screenDisplay.changeCharacter(dialogueManager.getNextCharacter ());
}
if (Input.GetKeyDown ("escape")) {
if (!PauseMenu.instance.getActive () && !SaveMenu.instance.getActive ())
{
PauseMenu.instance.toggleMenu ();
}
else if (SaveMenu.instance.getActive())
{
SaveMenu.instance.toggleMenu (true);
PauseMenu.instance.toggleMenu ();
}
else if (PauseMenu.instance.getActive())
{
PauseMenu.instance.toggleMenu ();
}
}
}
public void initialScreen()
{
SceneManager.sceneLoaded += OnLevelFinishedLoading;
}
void OnDisable()
{
SceneManager.sceneLoaded -= OnLevelFinishedLoading;
}
void OnLevelFinishedLoading (Scene scene, LoadSceneMode mode)
{
GameManager.instance.screenDisplay.initialScreen(dialogueManager.getNextLine(), dialogueManager.getNextCharacter(), null, null,
null, null, null, null);
}
public PlayerType returnPlayer()
{
return currentPlayer;
}
}
, хотя я здесь, это тоже мой GameManager, хотяЯ не испортил это тонну.В основном, используя его как DontDestroyOnLoad, чтобы удерживать все остальное на этом этапе.
public class GameManager : MonoBehaviour{
public static GameManager instance;
public DisplayScreen screenDisplay;
public SceneManagement managerScene;
public SaveLoad saveStorage;
public PlayerType currentPlayer;
//leave out until load data is setup
//PlayerType currentPlayer;
void Awake()
{
instance = this;
DontDestroyOnLoad (transform.gameObject);
managerScene = gameObject.AddComponent(typeof(SceneManagement)) as SceneManagement;
screenDisplay = gameObject.AddComponent (typeof(DisplayScreen)) as DisplayScreen;
saveStorage = gameObject.AddComponent (typeof(SaveLoad)) as SaveLoad;
//initialize player and sceneManager here, but only load through main menu options
//of new game or load game
}
void update()
{
}
}
Я продолжил устранять неполадки и довел это до особенно запутанной для меня части.Я вынул все журналы отладки и добавил 3 цикла в свою функцию загрузки, вот они.
Debug.Log("LOAD CALLED");
accessDataPath(false);
for (int i = 0; i < listSize; i++)
{
Debug.Log("First Loop " + SavedGames[i].returnName());
SavedGames[i].updateName("Updated Player " + (i + 1));
}
for (int i = 0; i < listSize; i++)
{
Debug.Log("Second Loop " + SavedGames[i].returnName());
}
foreach (PlayerType player in GameManager.instance.saveStorage.returnList())
{
Debug.Log("Third Loop " + player.returnName());
}
Итак, первый отображает проигрывателя 15, затем правильно отображает первые циклы 1-15, а затем имя временного имени снова,до сих пор не выяснил, почему это появляется, но я думаю, что это связано.Тогда второй цикл повторяет все неправильно.Буквально измененные и спина к спине петли ошибочны, единственное отличие состоит в том, что они выходят за рамки цикла for.Я запустил третий цикл, используя foreach, чтобы увидеть, изменился ли тип вызова, и это не так.
Даже изменение имени, а затем немедленный вызов цикла для проверки показывает, что значения меняются.Я думаю, что это может быть связано с тем, как я храню объекты, но я не уверен, как может возникнуть проблема.Он не обнуляется, и имена меняются, чтобы быть одинаковыми каждый раз, поэтому он не является абсолютно случайным.Я публикую это здесь сразу после того, как нашел это, надеясь, что скоро я решу это, но также надеюсь, что если я не сделаю, кто-то еще может что-то заметить.У меня есть следующие 3 часа, чтобы работать над этим, поэтому я буду пытаться все это время проверять время от времени.Заранее спасибо за всех, кто может взглянуть на это для меня.