Войти
UnityФорумПрограммирование

Инвентарь

#0
10:31, 25 янв 2023

Всем привет.

Регулярно начинаю писать систему предметов для синглплеерной игры с сохранениями и всегда получается херня.

Предметы стакаются и имеют список примитивных свойств (string, int)

Есть несколько контекстов:
- база данных ( обычно ScriptableObject, данные о предметах, их названия, иконки, id, фабрика для создания дефолтного предмета )
- сохранения ( предмет включает id  и список примитивных свойств, опционально guid и позицию на сцене)
- сцена ( непосредственно пикапы предметов, контейнеры с предметами на сцене, инвентари, магазины)
- ui ( инвентарь, перекладывание в контейнер, покупка в магазине, экипировка предметов в руки персонажей)

Может у кого-то есть под рукой хороший пример реализации такой системы из выпущенной игры?

туторы или готовые фреймворки - не предлагайте. Они многие аспекты или отбрасывают или перегружают.

Есть 3 ключевые проблемы:
1.когда реализую добавление предметов в контейнер, учитывая существующие стаки, мне кажется, что я что-то делаю не так. Эта функция возвращает остаток предметов, и если он 0, то исходный объект предмета ( пикап или объект в другом контейнере) уничтожится, если больше 0, то поменяется количество. А в самой функции он должен попытаться, предварительно добавить в каждый существующий стак такого предмета, и вычетать из исходного количества. Какие еще варианты реализаций вы знаете?

2. Как совместить данные о стаке и свойства предмета? Получается что у каждого предмета в стаке могут быть те же свойства. Единственное что я придумал более менее адекватное - массив свойств для каждого предмета в стаке, но только если свойства не default

3. Как связать контексты, не создав спагетти?

#1
(Правка: 11:48) 11:41, 25 янв 2023

mitay-walle
> Какие еще варианты реализаций вы знаете?
Minecraft
Инвентарь https://github.com/Bukkit/Bukkit/blob/master/src/main/java/org/bu… nventory.java
ItemStack https://github.com/Bukkit/Bukkit/blob/master/src/main/java/org/bu… temStack.java
Проще говоря, есть Item, все предметы наследуются от него. Блоки, оружие, любой предмет который вообще может существовать.
Когда ты добавляешь в инвентарь он перебирает каждый слот и смотрит есть ли вообще такой ItemStack с предметом. ищет ближайшего. Нашел - отдал. Ты его заполняешь, твой stack как то изменяется или полностью исчезает. Если осталось мы ищем дальше стак с предметом, не нашли, ищем полностью свободную ячейку (cell, это не stack). Свободные ячейки или их порядковый номер можно хранить отдельной коллекции.
В отличии от Item, именно ItemStack хранит информацию о разрушении предмета (или его использовании. Фонарик с аккумулятором например тратиться только когда включен).
Был у нас например аккумуляторов пачка (стак), пустые. Мы заряжаем какой то из пачки и он становится отдельным ItemStack, при чём таким, что его уже нельзя сложить в пачку. За это отвечает флаг isStackable в стаке.

Item - это структура
ItemStack это структура (то есть он не изменен по определению и чтобы внести изменения надо создать другой ItemStack). Но можно сделать и в виде Class, главное чтобы за событиями об его изменении кто то следил.
Inventory - класс

Можно сделать вариант с ECS, тут всё зависит от опыта и свободного времени. Он будет ещё гибче, но можно будет заблудиться если прийти на проект без TDD.

#2
12:15, 25 янв 2023

Salamandr
> Minecraft
> Инвентарь https://github.com/Bukkit/Bukkit/blob/master/src/main/java/org/bu…
> nventory.java
> ItemStack https://github.com/Bukkit/Bukkit/blob/master/src/main/java/org/bu…
> temStack.java
Спасибо, буду смотреть

#3
14:27, 25 янв 2023

А что такое стаки у тебя?
В моем понимании это укладывание однотипных предметов в один слот инвентаря. Например деньги, камни. А предметы с разными свойствами никак не могут быть в одном слоте. Только если слот сам содержит не предмет, а  массив в котором лежат уже конкретные предметы

#4
1:03, 26 янв 2023

DemiosFantasimo
> А что такое стаки у тебя?
ну как раз об этой проблеме и речь. Как сделать это адекватно. В стаке могут быть предметы, которые имеют собственные свойства. Например еда, которую можно есть кусками. Или батарейки частично севшие

#5
(Правка: 7:44) 7:43, 26 янв 2023

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

class Item
{
  public enum Propertie{damage, resist, value}//Свойства предметов
  public enum TypeItem{sword, armor, food}//Типы предметов
  public enum TypeStack{noStack, Stack}//Тип определяющий стакается предмет или не стакается

  public TypeItem type;
  public TypeStack typeStack;
  public IDictionary<Propertie,int> properties;
  public string image;
}

class Inventory
{
  List<Item> Inventory;
  
  public AddItem(Item item)
  {
    //Вилка по типу стакания
    switch(item.typeStack)
    {
      //Если предмет не стакается то просто добавляется в инвентарь
      case TypeStack.noStack:
      inventory.Add(item);
      break;
      
      //если предмет стакается
      case TypeStack.Stack:
      //Ищем тип предмета к которуму пристакаем новое
      int index=-1;
      for(int i=0; i<=inventory.Count-1; i++)
      {
        if(inventory[i].type==item.type)
        {
          index=i;
          break;
        }
      }
      
      //Если не был найден однотипный предмет к которому можно пристакать то просто текущий добавляем в инвентарь
      if(index<0)
      {
        inventory.Add(item);
      }
      else //Если найден однотипный предмет к которому можно пристакать, то просто прибавляем значение к свойству value
      {
        inventory[index].properties[Propertie.value]+=item.properties[Propertie.value];
      }
      break;
    }
  }
}
Inventory inventory=new Inventory();

Item item;
//Создаем меч
item=new Item();
item.type=TypeItem.sword;
item.typeStack=noStack;
item.properties=new Dictionary()
{
  {Propertie.damage,10},  
};
item.image="bubs.png"
inventory.AddItem(item);

//Создаем еду
item=new Item();
item.type=TypeItem.food;
item.typeStack=Stack;
item.properties=new Dictionary()
{
  {Propertie.value,3},  
};
item.image="tort.png"
inventory.AddItem(item);
#6
9:17, 26 янв 2023

DemiosFantasimo
> Ну типо такого
Спасибо, что уделили время, но я просил именно варианты из релизнувшихся игр. Таких примеров много в интернете, и они не учитывают все упомянутые контексты

#7
10:01, 26 янв 2023

mitay-walle
> но я просил именно варианты из релизнувшихся игр. Таких примеров много в
> интернете, и они не учитывают все упомянутые контексты
Ну удачи в поиске)))

#8
13:59, 26 янв 2023

DemiosFantasimo
> Ну удачи в поиске
Спасибо, Salamandr уже скинул из Minecraft'а

#9
(Правка: 23:37) 23:34, 26 янв 2023

Я делал инвентарь через серилизованные структуры. C# жи, ведь.
Инвертор получается очень лёгким и максимально гибким. В одной структуре можно описать тысячу полей свойств, можно вложить структуру структуру сделать в них списки и так далее. В целом это почти как конструктор но только структуру можно сохранить без танцев и бубнов.

То есть архитектура заключает в себе только одну структуру со свойствами, которая является ячейкой инвентаря и списком этих структур которые и будет являться инвентарем.
А далее просто собираем ui, по нажатию кнопки и всё. Если надо внести изменения в уже собранный ui то просто пересобираем его.

#10
6:23, 27 янв 2023

sledo
Он с программированием (судя по проблемам описаным в nil- посте) видимо не очень, по этому и ищет готовый вариант

#11
(Правка: 9:32) 9:20, 27 янв 2023

sledo
> Я делал инвентарь через серилизованные структуры
Я тоже пробовал этот вариант, но я не понимаю - какой в этом смысл, по следующим причинам
- Проблема 16 байт
https://stackoverflow.com/questions/1082311/why-should-a-net-stru… than-16-bytes
https://mdfarragher.medium.com/whats-faster-in-c-a-struct-or-a-cl… -99e4761a7b76
- массив - ссылочный тип, так что при дублировании структуры с массивом вы либо таскаете один и тот же массив по ссылке, либо создаете мусор

#12
(Правка: 9:40) 9:34, 27 янв 2023

DemiosFantasimo
> ищет готовый вариант
Я ищу real-world examples, а не очередной тутор ради просмотров или попытку навариться через Asset Store. Ваш код вообще не соответствует тому, что я описывал в посте и не решает проблему взаимодействия контекстов (save, ui, database, scene)

Вы не желаете мне помочь и скатываетесь в оскорбления - давайте закончим на этом.

Искренне успехов вам в ваших проектах (: очень вас прошу, не пишите

Спасибо еще раз Salamandr за корректный ответ

#13
11:15, 27 янв 2023

mitay-walle
> Вы не желаете мне помочь и скатываетесь в оскорбления
Где  я оскорблял?

Если ты сам на что-то оскорбился, то это проблема твоего слабого характера, а я тебя не оскорблял.Адиос!

#14
17:14, 27 янв 2023

mitay-walle
> - Проблема 16 байт
В первый раз вижу в этом проблему. Хотя конечно если создавать как в ссылке миллион экземпляров, то наверное да, тут любое решение будет проблемой. Даже бд.

mitay-walle
> - массив - ссылочный тип
Это что ещё за чушь?
И?!! Да, в шарпе массивы это списки и что? Вы теперь их вообще использовать не будете? А что тогда? Создадите стопитьсот переменных имитируя структуру массива? Причём без строк, так как это тоже ссылки.
Классы, делегаты, интерфейсы - все в топку?
Можете тогда закрыть движок, так как все объекты на сцене, это тоже ссылки.
Более того, это ещё и массив ссылок.

DemiosFantasimo
> Он с программированием (судя по проблемам описаным в nil- посте) видимо не
> очень, по этому и ищет готовый вариант
Судя по всему, он о программировании только наслышан.

UnityФорумПрограммирование

Тема закрыта.