Пятница, 29 Марта 2024, 13:19

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 1
  • 1
Форум игроделов » Движки для разработки игр и сложные системы разработки » Unity » Сохранение игровых данных через XML
Сохранение игровых данных через 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 ресепкт вааще smile
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
был не раз
Сейчас нет на сайте
А куда вешать скрипт? и что делать чтоб его запстить в игре? surprised

Добавлено (23.12.2013, 09:46)
---------------------------------------------
как загружать



Сайт проекта
Форум игроделов » Движки для разработки игр и сложные системы разработки » Unity » Сохранение игровых данных через XML
  • Страница 1 из 1
  • 1
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг