Сохранение игровых данных через XML
|
|
pixeye | Дата: Понедельник, 16 Апреля 2012, 16:40 | Сообщение # 1 |
Red Winter Software
Сейчас нет на сайте
| Чуть ли не каждый день слышу "как сделать сохранение". Показываю простой пример в учебных целях. Для сохранения используем xml документ. Для начала очень краткий экскурс для тех кто видит xml в первый раз.
Xml документ состоит из : - корневого элемента,
- элементов,
- атрибутов элементов.
Пример:
<Level> <player position_x="4" position_y="5" position_z = "10" > </player> <monster position_x="4" position_y="5" position_z = "10" > </monster> </Level>
Где красным выделен корневой элемент, зеленым элементы, а синим атрибуты. Можно предположить что в этом документе прописаны координаты игрока и некоего монстра.
Все скрипты я буду писать на C#, перевод на US если и будет то не сейчас, однако ничего сложного нет, поэтому просто обязаны справиться;-) Итак создаем скрипт.
Назовем его SaveController.cs
Добавляем using System.Text; using System.Xml; using System.IO;
Code public class SaveController : MonoBehaviour {
Transform playerTransform;
void Awake(){ playerTransform = GameObject.Find("player").transform; //добавили трансформ игрока; }
void SaveGame(){
string filepath = "data.xml"; XmlDocument xmlDoc = new XmlDocument (); XmlNode rootNode = null; if (!File.Exists(filepath)) { rootNode = xmlDoc.CreateElement ("level"); xmlDoc.AppendChild (rootNode); } else { xmlDoc.Load(filepath); rootNode = xmlDoc.DocumentElement; } rootNode.RemoveAll (); XmlElement elmNew = xmlDoc.CreateElement ("player"); XmlAttribute position_X = xmlDoc.CreateAttribute ("position_x"); position_X.Value = playerTransform.position.x.ToString(); XmlAttribute position_Y = xmlDoc.CreateAttribute ("position_y"); position_Y.Value = playerTransform.position.y.ToString (); elmNew.SetAttributeNode (position_X); elmNew.SetAttributeNode (position_Y); rootNode.AppendChild (elmNew); xmlDoc.Save (filepath);
}
void Update(){ if (Input.GetKeyDown (KeyCode.S)) { SaveGame(); } } }
Теперь по порядку. - string filepath = "data.xml"; - путь к файлу, в данномслучае файл находится в папке с проектом. Не очень хорошо, однако ничего не мешает вампрописать другой путь.
- XmlDocument xmlDoc = new XmlDocument (); - создаем новый xml документ.
- XmlNode rootNode = null; - корневой элемент
Code if (!File.Exists(filepath)) { rootNode = xmlDoc.CreateElement ("level"); xmlDoc.AppendChild (rootNode); } else { xmlDoc.Load(filepath); rootNode = xmlDoc.DocumentElement; }
Если файла не существует, то создать новый корневой элемент "уровень" В другом случае загрузить xml и присвоить корневой элемент оттуда.
- xmlDoc.AppendChild (rootNode) - добавить элемент.
- xmlDoc.Load(filepath); - загрузить xml док
- rootNode = xmlDoc.DocumentElement; - взять корневой элемент.
- rootNode.RemoveAll (); - удалить все что находится внутри корневого элемента ( нужно для перезаписи )
Code XmlElement elmNew = xmlDoc.CreateElement ("player"); XmlAttribute position_X = xmlDoc.CreateAttribute ("position_x"); position_X.Value = playerTransform.position.x.ToString(); XmlAttribute position_Y = xmlDoc.CreateAttribute ("position_y"); position_Y.Value = playerTransform.position.y.ToString (); elmNew.SetAttributeNode (position_X); elmNew.SetAttributeNode (position_Y); rootNode.AppendChild (elmNew); xmlDoc.Save (filepath);
- XmlElement elmNew = xmlDoc.CreateElement ("player"); - создаем элемент игрока
- XmlAttribute position_X = xmlDoc.CreateAttribute ("position_x"); - создаем атрибут позиции по X;
- position_X.Value = playerTransform.position.x.ToString(); - присваиваеи атрибуту position_X значение позиции игрока по X - обязательно переведите значение в текст ( .ToString() )
- elmNew.SetAttributeNode (position_X); - присваиваем атрибут position_X элементу игрока
- rootNode.AppendChild (elmNew); - вкладывает элемент игрока в корневой элемент "level"
- xmlDoc.Save (filepath); - сохраняем наш xml документ по нашему пути.
Вот впринципе и все, могут быть ошибки так как довольно трудно писать коды в сообщение без подсветки;-) Если что поправлю.
Если все сделано правильно то вы сможете 1) Создавать xml файл 2) Прописывать туда данные 3) Вписывать данные в уже созданный xml файл
Все значения будут каждый раз перезаписаны.
Если пригодилось/пригодится - добавлю еще пару уроков по сохранению.
Ответ на вопрос как сохранять за раз несколько объектов На самом деле все просто.
Для начала создадим некий абстрактный класс который будет хранить в себе переменные объекта.
Code public class myObjects : MonoBehaviour { public enum TYPEOF{ player,monster,npc } public TYPEOF typeOf; public Transform selfTransform;
void Awake(){ selfTransform = transform; } }
Это у нас рыба.
Вернемся к сейтКонтроллеру ( SaveController ) Добавляем using System.Collections.Generic;
Code //К переменным List<myObjects> objs = new List<myObjects>();
Где непосредственно запись в документ переписываем
Code for (int i=0;i<objs.Count;i++){ XmlElement elmNew = xmlDoc.CreateElement (objs[i].typeOf.ToString()); XmlAttribute position_X = xmlDoc.CreateAttribute ("position_x"); position_X.Value = objs[i].selfTransform.position.x.ToString(); XmlAttribute position_Y = xmlDoc.CreateAttribute ("position_y"); position_Y.Value = objs[i].selfTransform.position.y.ToString (); elmNew.SetAttributeNode (position_X); elmNew.SetAttributeNode (position_Y); rootNode.AppendChild (elmNew); }
Все - теперь циклом для каждого игрового объекта objs создастся в xml строчка c атрибутами. Название элемента будет objs[i].typeOf.ToString(); Это наш enum в objs (player,monster,npc)
Если допустим для monster - нужны отличные от всех остальных атрибуты, то просто в цикле пишем
if (objs[i].typeOf == myObjects.TYPEOF.monster){ Ваш код }
ACTORS - мой фреймворк на Unity Until We Die - игра над которой работаю
Сообщение отредактировал pixeye - Понедельник, 16 Апреля 2012, 18:49 |
|
| |
Nekit_Aut | Дата: Понедельник, 16 Апреля 2012, 17:14 | Сообщение # 2 |
The Dizziness - Man
Сейчас нет на сайте
| pixeye, Хмм... Спасибо) Но вот есть один вопросик... А если объектов на карте очень много, то их всех и прописывать в xml вручную? А можно как-нибудь искать их по тегу или по чему ещё?..
|
|
| |
pixeye | Дата: Понедельник, 16 Апреля 2012, 17:18 | Сообщение # 3 |
Red Winter Software
Сейчас нет на сайте
| Quote (Nekit_Aut) pixeye, Хмм... Спасибо) Но вот есть один вопросик... А если объектов на карте очень много, то их всех и прописывать в xml вручную? А можно как-нибудь искать их по тегу или по чему ещё?..
Отвечу чуть позже;-) конечно можно
ACTORS - мой фреймворк на Unity Until We Die - игра над которой работаю
|
|
| |
_LeVoID_ | Дата: Понедельник, 16 Апреля 2012, 17:20 | Сообщение # 4 |
VoID
Сейчас нет на сайте
| pixeye, полезный урок! Спасибо!
QLines v1.3 Forest Owl
|
|
| |
pixeye | Дата: Понедельник, 16 Апреля 2012, 18:51 | Сообщение # 5 |
Red Winter Software
Сейчас нет на сайте
| Ответ на вопрос как сохранять за раз несколько объектов На самом деле все просто.
Для начала создадим некий абстрактный класс который будет хранить в себе переменные объекта.
Code public class myObjects : MonoBehaviour { public enum TYPEOF{ player,monster,npc } public TYPEOF typeOf; public Transform selfTransform;
void Awake(){ selfTransform = transform; } }
Это у нас рыба.
Вернемся к сейтКонтроллеру ( SaveController ) Добавляем using System.Collections.Generic;
Code //К переменным List<myObjects> objs = new List<myObjects>();
Где непосредственно запись в документ переписываем
Code for (int i=0;i<objs.Count;i++){ XmlElement elmNew = xmlDoc.CreateElement (objs[i].typeOf.ToString()); XmlAttribute position_X = xmlDoc.CreateAttribute ("position_x"); position_X.Value = objs[i].selfTransform.position.x.ToString(); XmlAttribute position_Y = xmlDoc.CreateAttribute ("position_y"); position_Y.Value = objs[i].selfTransform.position.y.ToString (); elmNew.SetAttributeNode (position_X); elmNew.SetAttributeNode (position_Y); rootNode.AppendChild (elmNew); }
Все - теперь циклом для каждого игрового объекта objs создастся в xml строчка c атрибутами. Название элемента будет objs[i].typeOf.ToString(); Это наш enum в objs (player,monster,npc)
Если допустим для monster - нужны отличные от всех остальных атрибуты, то просто в цикле пишем
if (objs[i].typeOf == myObjects.TYPEOF.monster){ Ваш код }
ACTORS - мой фреймворк на Unity Until We Die - игра над которой работаю
Сообщение отредактировал pixeye - Понедельник, 16 Апреля 2012, 18:51 |
|
| |
Самоделкин | Дата: Четверг, 19 Апреля 2012, 19:58 | Сообщение # 6 |
участник
Сейчас нет на сайте
| Прикрепите потом в шапку уроки про загрузку/сохранение через xml ! Актуально для всех новичков. Простая и понтяная основа от которой можно дальше плясать. Не только в плане сохранения прогресса игры, но и вообще чтения записи любых данных. А если что-то подзабылось то можно заглянуть. Такое вообще всем нужно, это не узкопрофильный вопрос. А не прикрепите - буду апать пока есть силы чтоб не потерять!
pixeye ресепкт вааще Quote (pixeye) string filepath = "data.xml"; - путь к файлу, в данном случае файл находится в папке с проектом. Не очень хорошо, однако ничего не мешает вампрописать другой путь. То есть лучше сохраняться куда-то вообще в посторонюю папку вне проекта (для windows), или все-таки в папку с проектом, но не в корневую, а например Code string filepath = "/PlayerProfile/Saves/data.xml" ?
И еще : 1)под андроидом все те же манипуляции с xml актуальны или там свои нюансы и так не принято?
2)В одном из скриптов прикрепленных к объекту у меня процедурно создается меш. А данные (положение вершин и т.д.) - будут загонятся (пока все еще загоняются)) в массив. В том же скрипте. Для меня пока трудновато обращаться к этим данным массива из других скриптов. Из другой сцены темпаче. Если этот массив в xml держать и записывать/ считывать по ходу игры из xml-файла. Это совсем неприемлемые и медленные костыли? Просто так нагляднее как-то для понимая происходящего)
|
|
| |
pixeye | Дата: Четверг, 19 Апреля 2012, 20:28 | Сообщение # 7 |
Red Winter Software
Сейчас нет на сайте
| Quote (Самоделкин) И еще : 1)под андроидом все те же манипуляции с xml актуальны или там свои нюансы и так не принято? Такие манипуляции допустимы;-) проверено на своем thrower'e 2 который бодро себя чувствует на андроиде;-)
Quote (Самоделкин) То есть лучше сохраняться куда-то вообще в посторонюю папку вне проекта (для windows), или все-таки в папку с проектом, но не в корневую, а например
Можно прописать путь как Application.persistentDataPath + "/myData/blablabla" ; На PC Application.persistentDataPath кажись ведет к моим документам. Вообще файлы сохранений и настроек хранить лучше вне игры ( покрайней мере на компах ). На IOS Application.persistentDataPath - ведет в папку документов приложения. Это единственное место куда позволено производить прямую запись из приложения.
Quote (Самоделкин) Если этот массив в xml держать и записывать/ считывать по ходу игры из xml-файла. Это совсем неприемлемые и медленные костыли?
Откровенно говоря я не работал так много с xml чтобы соверешенно точно ответить, в твоем случае лучше будет сохранять с помощью сериализации данных Сериализация C#
Но это отдельная тема для разговоров.
ACTORS - мой фреймворк на Unity Until We Die - игра над которой работаю
|
|
| |
Max-Osovsky | Дата: Понедельник, 07 Мая 2012, 12:44 | Сообщение # 8 |
частый гость
Сейчас нет на сайте
| pixeye, а не подскажите,можно ли прочитать данные из XML в JS??? Я просто с С# не оч дружу....)
|
|
| |
Medvedkoo | Дата: Четверг, 10 Мая 2012, 23:34 | Сообщение # 9 |
был не раз
Сейчас нет на сайте
| Интересно, почему никто не сказал, ведь вначале cs файла, если используем MonoBehaviour пишем: using UnityEngine; Добавлено (10.05.2012, 23:34) --------------------------------------------- Такой вопрос, когда я создаю класс, и вешаю на GO, в скрипте SaveController, значение myObjects.Count, и соответственно всего myObjects остается null'евым. В чем дело?
Заранее спасибо.
|
|
| |
seaman | Дата: Пятница, 11 Мая 2012, 00:23 | Сообщение # 10 |
старожил
Сейчас нет на сайте
| myObjects - это класс. У него нет никакого Count.
|
|
| |
Medvedkoo | Дата: Пятница, 11 Мая 2012, 07:40 | Сообщение # 11 |
был не раз
Сейчас нет на сайте
| Прошу прощения.
Имеется:
Code List<myObjects> objs = new List<myObjects>();
void Awake(){ print(objs.Count); }
Выводит 0, хотя 3 объекта в классе myObjects
Сообщение отредактировал Medvedkoo - Пятница, 11 Мая 2012, 07:41 |
|
| |
seaman | Дата: Пятница, 11 Мая 2012, 11:19 | Сообщение # 12 |
старожил
Сейчас нет на сайте
| Quote Выводит 0, хотя 3 объекта в классе myObjects Еще раз. myObjects - класс - нет в нем никаких объектов. В классе могут быть вообще только статические объекты. В списке objs тоже нет объектов во время Awake. Где Вы туда что-то поместили?- не вижу.
|
|
| |
lipis | Дата: Понедельник, 11 Июня 2012, 22:19 | Сообщение # 13 |
частый гость
Сейчас нет на сайте
| У меня unity выдает ошибку в MoniBehaviour Добавлено (11.06.2012, 22:19) --------------------------------------------- В MonoBehaviour
|
|
| |
simagin | Дата: Вторник, 03 Декабря 2013, 12:04 | Сообщение # 14 |
был не раз
Сейчас нет на сайте
| Здравствуйте! А вот такой вопрос, почему после компиляций проекта, все то что связано с xml не работает ?
..... Crazy developer || Old school .....
|
|
| |
allods | Дата: Вторник, 03 Декабря 2013, 16:39 | Сообщение # 15 |
почти ветеран
Сейчас нет на сайте
| а xml нельзя потом просто в ручную в блокноте изменить? ну типа взломать
|
|
| |
pixeye | Дата: Вторник, 03 Декабря 2013, 16:55 | Сообщение # 16 |
Red Winter Software
Сейчас нет на сайте
| Цитата allods ( ) а xml нельзя потом просто в ручную в блокноте изменить? ну типа взломать
NO!
ACTORS - мой фреймворк на Unity Until We Die - игра над которой работаю
|
|
| |
AntifreeZZe | Дата: Понедельник, 23 Декабря 2013, 09:46 | Сообщение # 17 |
был не раз
Сейчас нет на сайте
| А куда вешать скрипт? и что делать чтоб его запстить в игре? Добавлено (23.12.2013, 09:46) --------------------------------------------- как загружать
Сайт проекта
|
|
| |