Четверг, 02 Мая 2024, 07:41

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

Меню сайта
Категории каталога
Создание игр [355]
Статьи об общих понятиях связанных с созданием игр.
Программирование [82]
Гайды по программированию на разных ЯП.
Движки и Гейммейкеры [145]
Статьи о программах для создания игр, уроки и описания.
Софт [43]
Различные программы, в том числе в помощь игроделам.
2D-графика [14]
Уроки по рисованию, растр, пиксель-арт, создание спрайтов и пр.
3D-графика [16]
Уроки по моделированию, ландшафт, модели, текстурирование и пр.
Моддинг игр [5]
Модификация компьютерных игр, создание дополнений, перевод, хакинг.
Игры [161]
Статьи об играх, в том числе и сделанных на гейммейкерах.
Разное [129]
Статьи, которые не вошли в определённые разделы.
Наш опрос
Типа какой из этих игр вы предпочитаете создавать игры?
Всего ответов: 15781
Главная » Статьи » Программирование

Написание расширений для редактора Unity
В работе над любым игровым проектом наступает такой момент, когда основных средств редактора уже не хватает, или же появляется необходимость написать инструмент для редактирования/создания каких-то данных относящихся к проекту. В этой статье на примере редактора предметов для игры, я расскажу как написать свой редактор. Так же расскажу как можно просто и удобно сохранять большие объемы данных в формат 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);  }
}


Вот так будет выглядеть созданный нами XMl файл.

Код
<?xml version="1.0" encoding="windows-1251"?>
<Items xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">  <ItemSet>  <Item ItemType="Armor" ItemName="Really cool armor" ItemCost="50" />  <Item ItemType="Potion" ItemName="Health potion" ItemCost="15" />  <Item ItemType="Weapon" ItemName="Legendary sword" ItemCost="180" />  <Item ItemType="Potion" ItemName="Mana potion" ItemCost="5" />  </ItemSet>
</Items>


Как видим все достаточно просто. Но создавать предметы в коде долгое, неблагодарное и совсем неправильное решение. Поэтому теперь мы напишем небольшой редактор предметов, который позволит быстро и удобно их создавать.

Все скрипты, которые относятся к редактору, должны хранятся в папке 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 предмет, то мы его не удаляем, что бы избежать ошибок.

Код
GUILayout.BeginHorizontal();
selectedItem = EditorGUILayout.Popup("Items: ",selectedItem,_itemSet.ItemNames);
if(GUILayout.Button("Delete this item"))
{
if(_itemSet.ItemSet.Count > 1)
{
_itemSet.ItemSet.RemoveAt(selectedItem);
_itemSet.GenerateNameList();
selectedItem = 0;
infoString = "Item deleted";
}
else
{
infoString = "Can't delete last item in list";
}
}
GUILayout.EndHorizontal();


Следующий блок позволяет нам изменить имя предмета

Код
GUILayout.BeginHorizontal();
_itemSet.ItemSet[selectedItem].itemName = EditorGUILayout.TextField
("Item name: ",_itemSet.ItemSet[selectedItem].itemName);
GUILayout.EndHorizontal();


Далее, в этом блоке мы делаем выпадающий список в котором мы можем выбрать тип предмета.

Код
GUILayout.BeginHorizontal();
_itemSet.ItemSet[selectedItem].itemType = (ItemType) EditorGUILayout.EnumPopup(_itemSet.ItemSet[selectedItem].itemType);
GUILayout.EndHorizontal();


Следующий блок обычное интовое поле для изменения поля Cost предмета

Код
GUILayout.BeginHorizontal();
_itemSet.ItemSet[selectedItem].itemCost = EditorGUILayout.IntField("Item cost: ",_itemSet.ItemSet[selectedItem].itemCost);
GUILayout.EndHorizontal();
Две кнопки, загрузка файла и его сохранение.
GUILayout.BeginHorizontal();
if(GUILayout.Button("Reload XML file"))
{
LoadFile();
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
if(GUILayout.Button("Save XML file"))
{
SaveFile();
_itemSet.GenerateNameList();
}
GUILayout.EndHorizontal();


И в конце блок с хелпбоксом, в который мы просто выводим текстовую информацию о последнем совершенном действии.

Код
GUILayout.BeginHorizontal();
EditorGUILayout.HelpBox(infoString,MessageType.Info);
GUILayout.EndHorizontal();


Здесь приведен полный текст класса редактора.

Вот так будет выглядеть само окно редактора:



Вот собственно и все. В следующий раз я расскажу как сделать расширение редактора для скрипта который находится на игровом объекте/префабе для более удобного редактирования. Если у вас есть вопросы, задавайте их ниже в комментариях.
Категория: Программирование | Добавил: RoBot (29 Января 2021) | Автор: driftmaniak
Просмотров: 1435 | Рейтинг: 3.7/3 |
Теги: U3D, XML, Расширения для редактора, Unity3D, editor, кодинг, программирование, Расширения, редактор, Unity, код, Пример кода, Написание расширений
Дополнительные опции:
Также если вы считаете, что данный материал мог быть интересен и полезен кому-то из ваших друзей, то вы бы могли посоветовать его, отправив сообщение на e-mail друга:

Игровые объявления и предложения:
Если вас заинтересовал материал «Написание расширений для редактора Unity», и вы бы хотели прочесть что-то на эту же тему, то вы можете воспользоваться списком схожих материалов ниже. Данный список сформирован автоматически по тематическим меткам раздела. Предлагаются такие схожие материалы: Если вы ведёте свой блог, микроблог, либо участвуете в какой-то популярной социальной сети, то вы можете быстро поделиться данной заметкой со своими друзьями и посетителями.

Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Поиск по сайту
10 случ. движков
  • ADRIFT
  • Eclipse Wold
  • DzQ
  • Flame
  • Oddity Engine
  • INSTEAD
  • Sonic Maker
  • Arrow
  • Chocolate Doom
  • Andorra 2D
  • Друзья сайта
    Игровой форум GFAQ.ru Перевод консольных игр
    Все права сохранены. GcUp.ru © 2008-2024 Рейтинг