Вторник, 19 Марта 2024, 10:30

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

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

Создание drag&drop инвентаря в Unity с использованием UI(C#). Часть 2
4. Создание слотов
Теперь вернемся немного назад, туда где мы создавали слоты. Помните я говорил, что не следует заморачиваться с расположением слотов ? Создаем скрипт InventoryButtonCreate и вешаем его на Canvas. Ничего в нем изменять не будем, он нам нужен для создания Custom Editor. Далее создаем папку Editor(обратите внимание на название папки, с другим названием не пойдет).
Примечание: Editor - зарезервированное наименование директории, предназначенной для доступа сценариев к Unity Editor Scripting API. Если Ваш скрипт использует какие либо классы или функции пространства имен UnityEditor, тогда для корректной работы он должен быть помещен в данную директорию.
Создаем в папке Editor скрипт InventoryEditor. Пишим код:
Код

using UnityEngine;
using System.Collections.Generic;
using UnityEditor;

[CustomEditor(typeof(InventoryButtonCreate))]
[CanEditMultipleObjects]
public class InventoryEditor : Editor{

  public GameObject go;
  public GameObject InventoryObj;

  public int ColumnCount;
  public int RowCount;
  public int SlotSize;

  void Init()
  {
   
  }

  public override void OnInspectorGUI()
  {  
  SlotSize = EditorGUILayout.IntField("Размер ячейки: ", SlotSize);//размер ячеек

  ColumnCount = EditorGUILayout.IntField("Количество колонок: ", ColumnCount);//количество колонок

  RowCount = EditorGUILayout.IntField("Количество строк: ", RowCount);

  go = EditorGUILayout.ObjectField("Слот ячейки", go, typeof(GameObject), true) as GameObject;

  InventoryObj = EditorGUILayout.ObjectField("Инвентарь: ", InventoryObj, typeof(GameObject), true) as GameObject;

  //создаем ячейки
  if (GUILayout.Button("Добавить ячейки"))
  {
  for (int k = 0; k < RowCount; k++)
  {
  for (int i = 0; i < ColumnCount; i++)
  {
  GameObject slot = Instantiate(go) as GameObject;

  SetSize(go.GetComponent<RectTransform>(), new Vector2(SlotSize, SlotSize));

  slot.GetComponent<RectTransform>().localPosition = new Vector2((slot.GetComponent<RectTransform>().rect.xMin + 50f) + (i * SlotSize), (slot.GetComponent<RectTransform>().rect.yMax - 30f) - (k * SlotSize));

  slot.transform.parent = InventoryObj.transform;
  }
  }  
  }
  }
   
   
  public void SetSize(this RectTransform trans, Vector2 newSize)
  {
  Vector2 oldSize = trans.rect.size;
  Vector2 deltaSize = newSize - oldSize;
  trans.offsetMin = trans.offsetMin - new Vector2(deltaSize.x * trans.pivot.x, deltaSize.y * trans.pivot.y);
  trans.offsetMax = trans.offsetMax + new Vector2(deltaSize.x * (1f - trans.pivot.x), deltaSize.y * (1f - trans.pivot.y));
  }
   

  void OnInspectorUpdate()
  {
  this.Repaint();
  }
   
}


Теперь смотрим в инспектор и у нас появились новые поля.
Первое поле - размер ячейки
Второе - кол-во колонок
Третье - кол-во столбцов
Четвертое - родитесльский обьект
Пятое - обьект слота
Указываем нужный размер ячейки(я поставил 40), кол-во колонок(я поставил 5) и столбцов(я поставил 7), в качестве родителя указываем панель Inventory, в поле слота перетаскиваем префаб слота. Нажимаем кнопку "Добавить ячейки". Ячейки создались


Выделяем их все и перетаскиваем на панель.


5. Сундук с лутом
Теперь переходим к созданию сундука с лутом. Перетаскиваем префаб нашего слота на сцену изменяем его название на "ChestSlot" создаем из него новый префаб, удалив тот, что мы раньше перетащили на сцену. Создаем тег "ChestSlot" и присваиваем этот тег новому префабу. Далее вещаем скрипт LootChest на Canvas (если вы не сделали этого раньше). Открываем скрипт. Создаем константу типаstring в которой храним путь к изображению пустой ячейки. Так же вводим словарь, в котором будет храниться предмет с которым мы будет работать. Список ChestSlotsObj, где хранятся слоты инвентаря сундука.
Код

  public const string DEFAULT_ICON = "slot";

  public Dictionary<int , ItemDataBase> useItem = new Dictionary<int , ItemDataBase>();//вспомогательный словарь, где храним предмет инвентаря, над  
  //которым производим действия (смотрим LootChestSlotEvent)
  public List<GameObject> ChestSlotsObj = new List<GameObject>(); //список хранящий в себе все слоты  

  public GameObject ChestPanel;//панель


Далее на сцене создаем два куба (это будут наши сундуки "_"). После создаем скрипт с именем LootChestCreate. Открываем...
Создаем делегат принимающий параметр Dictionary<int , ItemDataBase>. Дальше создаем событие ClickChestevent c типом делегата ClickOnChest. Еще нам необходим словарь в котором будем хранить обьекты и приватная переменная типаbool.
Код

  public delegate void ClickOnChest(Dictionary<int , ItemDataBase> item);

  public static event ClickOnChest ClickChestevent;//события нажатия  

  private bool used;

  private Dictionary<int , ItemDataBase> LootItem = new Dictionary<int , ItemDataBase>();//в словарь в котором храним добавленые предметы


Далее переходим обратно в скрипт LootChest. В нем создаем метод отвечающий за отображения свойств предмета. Подписываемся на этот метод
Код

using UnityEngine;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEditor;

public class LootChest : MonoBehaviour
{

  public const string DEFAULT_ICON = "slot";

  public Dictionary<int , ItemDataBase> useItem = new Dictionary<int , ItemDataBase>();//вспомогательный словарь, где храним предмет инвентаря, над  
  //которым производим действия (смотрим LootChestSlotEvent)
  public List<GameObject> ChestSlotsObj = new List<GameObject>(); //список хранящий в себе все слоты  

  public GameObject ChestPanel;//панель

  void Awake()
  {
  LootChestCreate.ClickChestevent += ChestSlotsCondition;//подписываемся на событие

  }

  void Update()
  {
  }

  /// <summary>
  /// Показываем изображение, если там есть обьект инвентаря
  /// </summary>
  /// <param name="item">обьект</param>
  public void ChestSlotsCondition(Dictionary<int , ItemDataBase> item)
  {
  useItem = item;

  ChestPanel.SetActive(true);

  for (int i = 0 ; i < ChestSlotsObj.Count ; i++)
  {
  if (item.ContainsKey((i)))
  {
  ChestSlotsObj[(i)].GetComponent<Image>().sprite = Resources.Load<Sprite>(item[(i)].IconPatch);
  }
  else
  {
  ChestSlotsObj[(i)].GetComponent<Image>().sprite = Resources.Load<Sprite>(DEFAULT_ICON);
  }
  }
  }
}


Возвращаемся в скрипт LootChestCreate и в методе OnMouseDown() (который срабатывает при нажатии мышкой на обьект) создаем предметы для инвентаря сундука
Код

using UnityEngine;
using System.Collections.Generic;

/*
  * Скрипт активирующий окно сундука с лутом (вешать на обьект сундука)
  */

public class LootChestCreate : MonoBehaviour
{

  public delegate void ClickOnChest(Dictionary<int , ItemDataBase> item);

  public static event ClickOnChest ClickChestevent;//события нажатия  

  private bool used;

  private Dictionary<int , ItemDataBase> LootItem = new Dictionary<int , ItemDataBase>();//в словарь в котором храним добавленые предметы

  void OnMouseDown()
  {
  if (!used)
  {
  //добавляем предметы в сундук (для теста)
  LootItem.Add(0 , ItemGenerator._ItemGenerator.ItemGen(Random.Range(0 , ItemGenerator._ItemGenerator.ItemList.Count)));
  LootItem.Add(6 , ItemGenerator._ItemGenerator.ItemGen(Random.Range(0 , ItemGenerator._ItemGenerator.ItemList.Count)));

  used = true;
  }
  //запускаем событие
  if (ClickChestevent != null)
  ClickChestevent.Invoke(LootItem);
  else
  Debug.LogError("События создания интерфейса сундука с лутоп ПУСТОЕ");
  }
}


Теперь вешаем скрипт LootChestCreate на наши кубы-сундуки.

Создаем скрипт с именем LootChestSlotEvent и вешаем его на префаб ChestSlot. И пишем код.
Код

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;

/*
  * Скрипт реализующий перемещение предметов  
  * внутри сундука с лутом(вешать на обьект ячейки)
  */

public class LootChestSlotEvent : MonoBehaviour , IPointerClickHandler , IDragHandler ,
  IPointerEnterHandler , IPointerExitHandler ,
  IEndDragHandler , IDropHandler
{
  public int SlotNumber;//номер ячейки
  private bool click;

  private Inventory inventory;
  private LootChest chest;

  //Нажатие мышки по ячейке
  public void OnPointerClick(PointerEventData eventData)
  {
  if (GameObject.FindGameObjectWithTag("Canvas").GetComponent<LootChest>().useItem.ContainsKey(SlotNumber))
  Debug.Log(GameObject.FindGameObjectWithTag("Canvas").GetComponent<LootChest>().useItem[SlotNumber].Name);

  }

  //Начало перемещения ячейки (движение при зажатой ЛКМ)
  public void OnDrag(PointerEventData eventData)
  {
  if (GameObject.FindGameObjectWithTag("Canvas").GetComponent<LootChest>().useItem.ContainsKey(SlotNumber))
  {
  inventory.DragObject(GameObject.FindGameObjectWithTag("Canvas").GetComponent<LootChest>().useItem[SlotNumber]);
  GameObject.FindGameObjectWithTag("Canvas").GetComponent<LootChest>().useItem.Remove(SlotNumber);
  inventory.ConditionSlots(SlotNumber , true , "chest");
  }
  }

  //Курсор над ячейкоц
  public void OnPointerEnter(PointerEventData eventData)
  {
  if (!PlayerGeneralSetting._Inventory.ContainsKey(SlotNumber))
  {
  click = true;
  }
  }

  //Курсор НЕ над ячейкой
  public void OnPointerExit(PointerEventData eventData)
  {
  if (!PlayerGeneralSetting._Inventory.ContainsKey(SlotNumber))
  {
  click = false;
  }
  }

  //Конец перемещения ячейки
  public void OnEndDrag(PointerEventData eventData)
  {
  if (!GameObject.FindGameObjectWithTag("Canvas").GetComponent<LootChest>().useItem.ContainsKey(SlotNumber) && inventory.DragItem && click)
  {
  GameObject.FindGameObjectWithTag("Canvas").GetComponent<LootChest>().useItem.Add(SlotNumber , inventory.DraggedObject);
  inventory.ConditionSlots(SlotNumber , false , "chest");
  }
  }

  //Отпуская ЛКМ
  public void OnDrop(PointerEventData eventData)
  {
  if (!GameObject.FindGameObjectWithTag("Canvas").GetComponent<LootChest>().useItem.ContainsKey(SlotNumber) && inventory.DragItem && click)
  {
  GameObject.FindGameObjectWithTag("Canvas").GetComponent<LootChest>().useItem.Add(SlotNumber , inventory.DraggedObject);
  inventory.ConditionSlots(SlotNumber , false , "chest");
  }
  }

  void Awake()
  {
  chest = GameObject.FindGameObjectWithTag("Canvas").GetComponentInParent<LootChest>();
  inventory = GameObject.FindGameObjectWithTag("Inventory").GetComponent<Inventory>();
  }

  void Update()
  {

  }
}

Как видите код практически идентичен коду в скрипте SlotEvent.

Теперь необходимо создать панель с инвентарем сундука и слоты. Создаем Panel и называем ее Chest. Слоты создаем точно так же, как и слоты для инвентаря. В скрипте InventoryButtonCreate указываем размер ячеек, количество ячеек, в поле "Слот ячейки" перетаскиваем префаб ChestSlot, в поле "Инвентарь" помещаем панель Chest, нажимаем кнопку "Создать ячейки".

Возвращаемся в скрипт LootChest и дописываем код. В испекторе перетаскиваем в поле ChestPanel нашу панель Chest. А в поле - список ChestSlotsObj наши слоты сундука.
Код

using UnityEngine;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEditor;

/*
  * Создание сундука с предметами
  * (Внешний вид)
  */

public class LootChest : MonoBehaviour
{

  public const string DEFAULT_ICON = "slot";

  public Dictionary<int , ItemDataBase> useItem = new Dictionary<int , ItemDataBase>();//вспомогательный словарь, где храним предмет инвентаря, над  
  //которым производим действия (смотрим LootChestSlotEvent)
  public List<GameObject> ChestSlotsObj = new List<GameObject>(); //список хранящий в себе все слоты  

  public GameObject ChestPanel;//панель

  void Awake()
  {
  LootChestCreate.ClickChestevent += ChestSlotsCondition;//подписываемся на событие

  int a = 0;//вспомогательная переменная

  for (int i = 0 ; i < ChestSlotsObj.Count ; i++)
  {
  ChestSlotsObj[i].GetComponentInChildren<Text>().text = i.ToString();//нумирация слотов

  ChestSlotsObj[i].GetComponent<LootChestSlotEvent>().SlotNumber = a;//пердаем номер слота скрипту LootChestSlotEvent

  a++;
  }

  ChestPanel.SetActive(false);//выключаем окно
  }

  void Update()
  {
  }

  /// <summary>
  /// Показываем изображение, если там есть обьект инвентаря
  /// </summary>
  /// <param name="item">обьект</param>
  public void ChestSlotsCondition(Dictionary<int , ItemDataBase> item)
  {
  useItem = item;

  ChestPanel.SetActive(true);

  for (int i = 0 ; i < ChestSlotsObj.Count ; i++)
  {
  if (item.ContainsKey((i)))
  {
  ChestSlotsObj[(i)].GetComponent<Image>().sprite = Resources.Load<Sprite>(item[(i)].IconPatch);
  }
  else
  {
  ChestSlotsObj[(i)].GetComponent<Image>().sprite = Resources.Load<Sprite>(DEFAULT_ICON);
  }
  }
  }

  //Очищаем инвентарь сундука
  public void СlearInventory()
  {
  ChestPanel.SetActive(false);
  }

  /// <summary>
  /// Изменяем изображение иконки ячейки при добавление предмета в нее
  /// </summary>
  /// <param name="key">номер ячейки</param>
  public void ChangeSlotIcon(int key)
  {
  if (useItem.ContainsKey((key)))
  {
  ChestSlotsObj[(key)].GetComponent<Image>().sprite = Resources.Load<Sprite>(useItem[(key)].IconPatch);
  }
  else
  {
  ChestSlotsObj[(key)].GetComponent<Image>().sprite = Resources.Load<Sprite>(DEFAULT_ICON);
  }
  }

}


На этом собственно все. Как я уже писал выше статья большая и возможно я мог где то оишбиться в коде или последовательности действий, поэтому смотрим исходник
Исходник тык
Все скрипты тык
Первая часть статьи
Категория: Создание игр | Добавил: beril (03 Января 2015) | Автор: Шевченко Денис
Просмотров: 16488 | Комментарии: 3 | Рейтинг: 3.8/11 |
Теги: Unity, Урок, юнити уроки, инвентарь, Разработка игр, UI, Drag&Drop, RPG, юнити, C#
Дополнительные опции:
Также если вы считаете, что данный материал мог быть интересен и полезен кому-то из ваших друзей, то вы бы могли посоветовать его, отправив сообщение на e-mail друга:

Игровые объявления и предложения:
Если вас заинтересовал материал «Создание drag&drop инвентаря в Unity с использованием UI(C#). Часть 2», и вы бы хотели прочесть что-то на эту же тему, то вы можете воспользоваться списком схожих материалов ниже. Данный список сформирован автоматически по тематическим меткам раздела. Предлагаются такие схожие материалы: Если вы ведёте свой блог, микроблог, либо участвуете в какой-то популярной социальной сети, то вы можете быстро поделиться данной заметкой со своими друзьями и посетителями.

Всего комментариев: 3
+0-
3 dromgarn   (24 Апреля 2020 17:47) [Материал]
1 листинг ошибка в функции так правильнее будет) : public void SetSize(RectTransform trans, Vector2 newSize)

+0-
2 uslucifer   (18 Июня 2017 16:55) [Материал]
usluciferперезалей исходники

+0-
1 sword2001   (21 Сентября 2016 21:36) [Материал]
Обнови ссылку Исходника ПЖ!

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Поиск по сайту
10 случ. движков
  • Doom Legacy
  • Quest
  • Arcade Game Studio
  • Realm Crafter
  • GLEngine2D
  • lifeEngine
  • RPG Tools
  • Phaser
  • ReMooD
  • J.U.R.P.E.
  • Друзья сайта
    Игровой форум GFAQ.ru Перевод консольных игр
    Все права сохранены. GcUp.ru © 2008-2024 Рейтинг