В работе над любым игровым проектом наступает такой момент, когда основных средств редактора уже не хватает, или же появляется необходимость написать инструмент для редактирования/создания каких-то данных относящихся к проекту. В этой статье на примере редактора предметов для игры, я расскажу как написать свой редактор. Так же расскажу как можно просто и удобно сохранять большие объемы данных в формат XML с помощью сериализации/десериализации. Итак, поехали!
Для начала подготовим структуру наших предметов, что бы их легко можно было сохранять в формат XML.
Код
using System.Collections; using System.Collections.Generic; using System.Xml; using System.Xml.Serialization; //Здесь указываем название корневого эелемента [XmlRoot("Items")] public class ItemSetSerialized { //Здесь указываем что у нас будет массив из элементов, типа ItemSerialized [XmlArray("ItemSet"), XmlArrayItem("Item",typeof(ItemSerialized))] //Массив для хранения наших данных, в данном случае List<> public List<ItemSerialized> ItemSet; [XmlIgnore] public string[] ItemNames; //Конструктор нашего класса. public ItemSetSerialized() { //В конструкторе создаем новый список. ItemSet = new List<ItemSerialized>(); } //С помощью этого метода генерируем список имен всех предметов из файла, что бы затем использовать его в редакторе. public void GenerateNameList() { List<string> temp = new List<string>(); foreach(ItemSerialized item in ItemSet) { temp.Add(item.itemName); } ItemNames = temp.ToArray(); } } //Описание структуры данных для предмета, эта структура в XML будет представлена в виде элемента. public class ItemSerialized { // [XmlAttribute("ItemType")] - здесь мы задаем название атрибута нашего элемента и тип данных которые он будет хранить. [XmlAttribute("ItemType")] public ItemType itemType; [XmlAttribute("ItemName")] public string itemName; [XmlAttribute("ItemCost")] public int itemCost; } public enum ItemType { Weapon = 0, Armor = 1, Potion = 2 }
Итак, у нас есть структура данных, которая описывает наш предмет. Теперь давайте посмотрим как можно сделать новые предметы и потом эти данные сохранить в файл.
Код
using UnityEngine; using System.Collections; using System.Collections.Generic; using System.Xml; using System.Xml.Serialization; using System.IO; public class ItemCreator : MonoBehaviour { private XmlDocument _doc; private string _xmlName = "ItemData.xml"; private string _fileName = "ItemData"; private ItemSetSerialized _itemSet; private void Start() { //Для примера, создадим два предмета, добавим их в наш класс, который мы будем сереализовать и сохраним данные в файл. //Создаем новый экземпляр нашего класса, который будет хранить все наши предметы. _itemSet = new ItemSetSerialized(); //Создаем новый экземпляр класса, который описывает сам предмет. ItemSerialized itemOne = new ItemSerialized(); //Первый предмет itemOne.itemType = ItemType.Armor; itemOne.itemName = "Really cool armor"; itemOne.itemCost = 50; //И второй ItemSerialized itemTwo = new ItemSerialized(); itemTwo.itemType = ItemType.Potion; itemTwo.itemName = "Health potion"; itemTwo.itemCost = 15; //Добавляем наши предметы в список. _itemSet.ItemSet.Add(itemOne); _itemSet.ItemSet.Add(itemTwo); //Сохрянем файл. SaveFile(); } //Сохраняем наши данные в файл private void SaveFile() { //Создаем новый экземпляр класса XmlSerializer с указанием нашего класса с данными, ItemSetSerialized, которые необходимо сериализовать. XmlSerializer serializer = new XmlSerializer(typeof(ItemSetSerialized)); //С помощью класса FileStream записываем наши данные в файл. FileStream stream = new FileStream(Application.dataPath + @"/Resources/ItemData.xml", FileMode.Create); //Сериализуем данные в поток записи нового файла. serializer.Serialize(stream, _itemSet); //Заканчиваем запись нового файла. stream.Close(); } //Загрузка и десериализация существующего XML файла private void LoadXmlData() { //Создаем новый Xml документ _doc = new XmlDocument(); //В TextAsset считываем наш сохраненный файл TextAsset text = new TextAsset(); text = (TextAsset)Resources.Load(_fileName, typeof(TextAsset)); //Загружаем и преобразуем текст в наш XMl документ _doc.LoadXml(text.text); //Указываем наш класс с данными которыеS нужно десериализовать, в нашем случае это ItemSetSerialized. XmlSerializer serializer = new XmlSerializer(typeof(ItemSetSerialized)); XmlReader reader = new XmlNodeReader(_doc.ChildNodes[1]); //Здесь рпоходит сама десериализация, в результате мы получаем новый экземпляр класса ItemSetSerialized, в который загрузятся все данные. _itemSet = (ItemSetSerialized)serializer.Deserialize(reader); } }
Как видим все достаточно просто. Но создавать предметы в коде долгое, неблагодарное и совсем неправильное решение. Поэтому теперь мы напишем небольшой редактор предметов, который позволит быстро и удобно их создавать.
Все скрипты, которые относятся к редактору, должны хранятся в папке Editor, желательно эту папку располагать в корне проекта, так же не забывайте, что извне этой папки доступ к находящимся там скриптам вы не получите.
Код редактора я разобью на блоки с пояснением.
Для начала нам необходимо создать и проинициализировать само окно редактора. Так же объявим все необходимые переменные.
Код
static ItemSetSerialized _itemSet; static XmlDocument _doc; static string _xmlName = "ItemData.xml"; static string _fileName = "ItemData"; //Переменная в которой будем хранить номер выбранного в данный момент предмета. private int selectedItem; //Переменная для текстовой информации хелпбокса private string infoString = "Info box"; static ItemEditor window; //Строка ниже добавляет ссылку на наш редактор в верхнее меню. Функция Init() инициализирует и создает наше окно. [MenuItem("Custom Editor/Item Editor")] static void Init() { //Создаем новое окно редактора window = (ItemEditor)EditorWindow.GetWindow(typeof(ItemEditor)); window.title = "Item Editor"; window.autoRepaintOnSceneChange = true; }
Далее при открытии окна загрузим уже существующий файл.
Код
//Эта функция вызывается когда окно редактора становится активным, в ней загрузим существующий файл. private void OnEnable() { LoadFile(); } //Загрузка и десериализация существующего XML файла private void LoadFile() { //Создаем новый Xml документ _doc = new XmlDocument(); //В TextAsset считываем наш сохраненный файл TextAsset text = new TextAsset(); text = (TextAsset)Resources.Load(_fileName, typeof(TextAsset)); //Загружаем и преобразуем текст в наш XMl документ _doc.LoadXml(text.text); //Указываем наш класс с данными которыеS нужно десериализовать, в нашем случае это ItemSetSerialized. XmlSerializer serializer = new XmlSerializer(typeof(ItemSetSerialized)); XmlReader reader = new XmlNodeReader(_doc.ChildNodes[1]); //Здесь рпоходит сама десериализация, в результате мы получаем новый экземпляр класса ItemSetSerialized, в который загрузятся все данные. _itemSet = (ItemSetSerialized)serializer.Deserialize(reader); _itemSet.GenerateNameList(); infoString = "File loaded"; }
Теперь в функции OnGUI() займемся интерфейсом самого редактора. Большую часть элементов я буду располагать отдельно в горизонтальных блоках. Каждый такой блок обозначается 2мя строками GUILayout.BeginHorizontal(); и GUILayout.EndHorizontal();
Первый блок – кнопка, нажатие на которую создает новый предмет и сразу помещает его в список.
Код
GUILayout.BeginHorizontal(); if(GUILayout.Button("Add new item")) { //Создаем предмет ItemSerialized newItem = new ItemSerialized(); newItem.itemName = "new_item"; newItem.itemType = ItemType.Armor; newItem.itemCost = 0; //Добавляем его в общий список _itemSet.ItemSet.Add(newItem); //Генерируем новый список имен _itemSet.GenerateNameList(); infoString = "Added new item"; } GUILayout.EndHorizontal();
В этом блоке у нас будет два элемента, которые будут располагаться на одной линии, первый элемент, выпадающий список со всеми предметами которые у нас есть, здесь нам и пригодится генерация списка имен, которую мы написали заранее. Второй элемент это кнопка, которая удаляет текущий выбранный предмет. Если у нас в списке остается 1 предмет, то мы его не удаляем, что бы избежать ошибок.
Вот собственно и все. В следующий раз я расскажу как сделать расширение редактора для скрипта который находится на игровом объекте/префабе для более удобного редактирования. Если у вас есть вопросы, задавайте их ниже в комментариях.
Также если вы считаете, что данный материал мог быть интересен и полезен кому-то из ваших друзей, то вы бы могли посоветовать его, отправив сообщение на e-mail друга:
Игровые объявления и предложения:
Если вас заинтересовал материал «Написание расширений для редактора Unity», и вы бы хотели прочесть что-то на эту же тему, то вы можете воспользоваться списком схожих материалов ниже. Данный список сформирован автоматически по тематическим меткам раздела.
Предлагаются такие схожие материалы:
Если вы ведёте свой блог, микроблог, либо участвуете в какой-то популярной социальной сети, то вы можете быстро поделиться данной заметкой со своими друзьями и посетителями.
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи. [ Регистрация | Вход ]