Принцип построения Инвентаря

Программирование на Юнити.

Принцип построения Инвентаря

Сообщение mastersmit 09 ноя 2016, 22:03

Вопрос довольно обширный.
Вот в размышлениях. Есть уже наполовину готовая написанная система, но по мне она выглядит в коде убого..
Все сводится к тому, что в ресурсах есть такого плана код:
Синтаксис:
Используется csharp
public class Items : MonoBehaviour {

    public Weapon[] weapons;
    public Armor[] armors;
    public Help[] helps;
    public Ammo[] ammos;
    public Misc[] miscs;
       
}

[System.Serializable]
public class Weapon
{
    public string name;
    public int id;
    public ItemMiscs.WeaponType type;
    public GameObject prefab, prefabForHands;
    [TextArea(2, 5)]
    public string description;
    public int damage;
    public float weight;
    public int state;
    public int cost;
    public int count, maxCount;
    public WeaponEffect[] effects;
}

[System.Serializable]
public class Armor
{
    public string name;
    public int id;
    public ItemMiscs.ArmorType type;
    public GameObject prefab;
    [TextArea(2, 5)]
    public string description;
    public int resist;
    public float weight;
    public int state;
    public int cost;
    public WeaponEffect[] effects;
}

[System.Serializable]
public class Help
{
    public string name;
    public int id;
    public GameObject prefab;
    [TextArea(2, 5)]
    public string description;
    public int weight;
    public int state;
    public int cost;
    public HelpEffect[] effects;
}
// и т.д.


Сам инвентарь игрока такого вида:
Синтаксис:
Используется csharp
public class Backpack
{
    public int caps { get; set; } // деньги игрока
    public List<Item> weapons; // оружие игрока
    public List<Item> armors; // броня игрока
    public List<Item> helps; // помощь игрока (различные абилки, хилки и прочее)
    public List<Item> ammos; // боеприпасы игрока
    public List<Item> miscs; // хлам игрока
}
public class Item
    {
        public enum ItemType { Weapon, Armor, Help, Ammo, Misc }
        public ItemType itemType;
        public int id;
        public int state;
        public int count;

        public Item (int id, int state, int count)
        {
            this.id = id;
            this.state = state;
            this.count = count;
        }
    }
 

В котором по сути просто описываю тип предмета, ид (тип и ид для получения данных из Items), состояние предмета (для износа/ремонта) и количество этого предмета.
Исходя из этого весь код из за switch'ей и if'ов растянулся на хз сколько строк..Для ввода нового или незначительного изменения существующего приходится переписывать кучу кода.. Это все надоело и стал искать иные способы..

Дальнейшие размышления списку всех предметов по - есть некий базовый класс Item, у которого находятся общие черты предмета (название, ид, вес и прочее). И производные от него классы по типу предмета. Вот так:
Синтаксис:
Используется csharp
public class ItemsNew : MonoBehaviour {

    public List<ItemWeapon> weapons;
    public List<ItemArmor> armors;
    public List<ItemHelp> helps;
    public List<ItemAmmo> ammos;
    public List<ItemMisc> miscs;
}

// Базовый класс предмета
[System.Serializable]
public class Item
{
    public string name; // название предмета
    public int id; // ID предмета
    public float weight; // вес предмета
    public string description; // описание предмета
    public int cost; // стоимость предмета (в случае оружия/брони - при 100% состоянии)
    public string prefab; // название префаба (из папки Resources), для мира
}

// Класс предмета раздела Оружие
[System.Serializable]
sealed public class ItemWeapon : Item
{
    public bool legendary; // такое оружие можно встретить только один раз
    public enum WeaponType { Light, Hard, Energy, Explosing, Melee, Handed } // Легкое, Тяжелое, Энерго, Взрывчатка, Холодное, Ближний бой
    public WeaponType weaponType; // тип оружия
    public int damage; // урон оружия
    public int state; // состояние оружия (полностью целого)
    public int count; // количество в обойме (если это ближний бой, холодное или взрывчатка, то 0 (или 1))
    public string prefabHand; // название префаба (из папки Resources), для рук
}

// Класс предмета раздела Броня
[System.Serializable]
sealed public class ItemArmor : Item
{
    public bool legendary; // такую броню можно встретить только один раз
    public enum ArmorType { Light, Medium, Hard, Energy } // Легкая, Средняя, Тяжелая, Энерго
    public ArmorType armorType; // тип брони
    public int resist; // защита брони
    public int state; // состояние брони (полностью целой)
}

// Класс предмета раздела Помощь
[System.Serializable]
sealed public class ItemHelp : Item
{
    public enum HelpType { Drug, Book } // Препарат, Книга/Журнал
    public HelpType helpType; // тип помощи
    public enum EffectType { Strength, Perception, Endurance, Charisma, Intellect, Agility, Lucky, LightWeapon, HardWeapon, EnergyWeapon, ExplosingWeapon, MeleeWeapon, HandedWeapon, Repair, Medicine, Science, Theft, Break, Secrecy, Oratory, Barter, Critical, AntiRadiaton, AntiPoison, AntiHabit, RadiationAway, PoisonAway, HabitAway, Health, MaxHealth, MaxWeight }
    public EffectType type; // тип получаемого эффекта
    public int actionTime; // время действия эффекта в секундах (по истечении этого времени эффект пропадает), если -1, то перманентное действие (просто добавляет на постоянку)
    public bool percent; // если true, то эффект добавляет процент к определенному показателю
    public int effectValue; // значение эффекта
}

// Класс предмета раздела Боеприпасы
[System.Serializable]
sealed public class ItemAmmo : Item
{
    // добавить тип боеприпасов
}

// Класс предмета раздела Разное
[System.Serializable]
sealed public class ItemMisc : Item
{
    // дополнительные поля для разного пока не нужны
}


Но в таком случае все опять же сводится к тому, что придется делать кучу Свитчей и Ифов, для определения типа предмета и от этого плясать дальше. Шило на мыло..

Можно заменить на один описывающий список:
Синтаксис:
Используется csharp
public class ItemsNew : MonoBehaviour {

    public List<Item> items; // тут будем хранить все ItemWeapon, ItemArmor и прочее, доступные в игре
}

Но опять же получится, что придется определять тип производного класса через базовый, но уже через GetType() (рефлексия?).. единственно удобство что придется обращаться к одному списку, а не к нескольким..

Тоже самое и с самим инвентарем игрока. Если сделаем в виде одного списка, то опять определение типа и прочее, прочее.. Или я под утро уже совсем куда-то побрел не туда или и правда не хватает мысли.. Хожу, блин, все вокруг, да около.. Или в любом случае придется описывать методы в инвентаре, которые будут получать то или иное через кучу Свитчей/Ифов?
Аватара пользователя
mastersmit
Старожил
 
Сообщения: 558
Зарегистрирован: 12 май 2014, 14:05
Откуда: Приморский край

Re: Принцип построения Инвентаря

Сообщение samana 09 ноя 2016, 22:31

mastersmit писал(а):Или в любом случае придется описывать методы в инвентаре, которые будут получать то или иное через кучу Свитчей/Ифов?

Обычно такая проблема подсказывает, что возможно будет уместен шаблон Стратегия.
Аватара пользователя
samana
Адепт
 
Сообщения: 4738
Зарегистрирован: 21 фев 2015, 13:00
Откуда: Днепропетровск

Re: Принцип построения Инвентаря

Сообщение getAlex 10 ноя 2016, 02:02

Для инвентаря: стратегия и компоновщик(композиция)
getAlex
Адепт
 
Сообщения: 1775
Зарегистрирован: 10 авг 2013, 18:30

Re: Принцип построения Инвентаря

Сообщение Tolking 10 ноя 2016, 10:26

Используй интерфейсы.
Ковчег построил любитель, профессионалы построили Титаник.
Аватара пользователя
Tolking
Адепт
 
Сообщения: 2714
Зарегистрирован: 08 июн 2009, 18:22
Откуда: Тула

Re: Принцип построения Инвентаря

Сообщение Cr0c 10 ноя 2016, 11:01

mastersmit писал(а):через GetType() (рефлексия?)

Синтаксис:
Используется csharp
if (item is MyWeaponClass) {}

Можно же вот так, без рефлексии. Можно динамическую типизацию ещё. Это как в Lua. Файлы конфигураций оружия в Crysis так написаны и в Far Cry.
Аватара пользователя
Cr0c
Адепт
 
Сообщения: 3035
Зарегистрирован: 19 июн 2015, 13:50
Skype: cr0c81

Re: Принцип построения Инвентаря

Сообщение getAlex 10 ноя 2016, 13:49

Основная концепция вещей должна быть "что я умею?", а не "кто я такой?".

Основными сущностями при построении items должны быть те компоненты, которыми ты их наполняешь. Иными словами, ты должен уметь программно наполнить пустые оболочки. Типы вещей( шлем, оружие) отличаются лишь доступными слотами для наполнения их компонентами. Сами же эти сущности ничего не умеют. К примеру, в тип "шлем" нельзя будет вставить "наносит %%x урона стихией %%y", а вот в меч или щит ты можешь вставить, потому что ты задал им нужные слоты. Впрочем, даже доступные слоты можно назначать программно.

Так что оставь все эти swith, if, is, рефлексию(в данном случае) и прочие проверки/переключатели, для манки кодеров.

Item
{
name
lvl
List<Slots>
AddSlot()
RemoveSlot()
}

Slots должны работать по тому же принципу, что и компонеты в GameObject на сцене, но только это твои компоненты, не наследуемые от монобехевер. Кстати, персонаж тоже состоит из слотов(только уже слотов из items), в которые ты можешь одеть вещи.
getAlex
Адепт
 
Сообщения: 1775
Зарегистрирован: 10 авг 2013, 18:30

Re: Принцип построения Инвентаря

Сообщение Cr0c 10 ноя 2016, 15:20

getAlex писал(а):К примеру, в тип "шлем" нельзя будет вставить "наносит %%x урона стихией %%y"

Это спорно. Может нанести при получении урона, например, или при каком-то ещё условии (допустим, способность "удар головой" или вроде того).
Аватара пользователя
Cr0c
Адепт
 
Сообщения: 3035
Зарегистрирован: 19 июн 2015, 13:50
Skype: cr0c81

Re: Принцип построения Инвентаря

Сообщение mastersmit 14 ноя 2016, 09:06

Ну, в целом пока определился с построением общих списков всех предметов
Синтаксис:
Используется csharp
public class Items : MonoBehaviour {
    public List<ItemWeapon> weapons;
    public List<ItemArmor> armors;
    public List<ItemHelp> helps;
    public List<ItemAmmo> ammos;
    public List<ItemMisc> miscs;
}

public class Item { }

public class ItemWeapon : Items { }

public class ItemArmor : Items { }

public class ItemHelp : Item { }

public class ItemAmmo : Item { }

public class ItemMisc : Item { }
 

и общего списка предметов, которые есть у игрока.
Синтаксис:
Используется csharp
public class Backpack {

public List<Item> items;

public Backpack ()
    {
        items = new List<Item>();
    }

public void Clear()
    {
        items.Clear();
    }

public void Other()
    {
        // do other
    }

public class Item
    {
        public enum ItemType { Weapon, Armor, Help, Ammo, Misc }
        public ItemType itemType;
        public int id;
        public int state;
        public int count;
        public bool inUse;

        public Item(ItemType type, int id, int state, int count)
        {
            this.itemType = type;
            this.id = id;
            this.state = state;
            this.count = count;
            this.inUse = false;
        }
    }
}
 

Столкнулся с тем, что хочется с помощью одного универсального конструктора получать тот или иной параметр, такого плана:
Синтаксис:
Используется csharp
public object GetParam(Items it, Item.ItemType type, int id, int paramId = 0)
    {
        object result = null;
        switch (type)
        {
            case Item.ItemType.Weapon:
                if (paramId == 0)
                    result = it.weapons[id].damage; // int
                else if (paramId == 1)
                    result = it.weapons[id].weaponType; // enum
                else if (paramId == 2)
                    result = it.weapons[id].weight; // float
                break;
            case Item.ItemType.Armor:
                    // и т.д.
                break;
            case Item.ItemType.Help:

                break;
            case Item.ItemType.Ammo:

                break;
            case Item.ItemType.Misc:

                break;
        }
        return result;
    }
 

Но чет эта упаковка/распаковка совсем не нравится.. Есть еще обобщенные классы, правда пока не совсем до конца понял их принцип, но там для каждой операции так же надо указывать тип, зато минуя упаковку/распаковку..
Можно ли еще каким-то образом сделать универсальную переменную, которая вернет необходимый тип?
Аватара пользователя
mastersmit
Старожил
 
Сообщения: 558
Зарегистрирован: 12 май 2014, 14:05
Откуда: Приморский край

Re: Принцип построения Инвентаря

Сообщение Cr0c 14 ноя 2016, 11:50

mastersmit писал(а):Но чет эта упаковка/распаковка совсем не нравится

Так наследование же. Либо так, либо отказаться от наследования и динамически типизировать данные.
Аватара пользователя
Cr0c
Адепт
 
Сообщения: 3035
Зарегистрирован: 19 июн 2015, 13:50
Skype: cr0c81

Re: Принцип построения Инвентаря

Сообщение Tolking 14 ноя 2016, 13:05

GetParam(Items it, Item.ItemType type, int id, int paramId = 0)

Не правильный бутерброд...

В item я передам ItemWeapon, a в type ItemType.Armor... Да и приведение к нужному типу еще...

Собственнo нужен GetArmor(Id),GetWeapon(Id) и т.д. a параметр через точку возьмешь...

P.S. Но все таки, ИМХО, удобнее иметь параметры в Dictionary...
Ковчег построил любитель, профессионалы построили Титаник.
Аватара пользователя
Tolking
Адепт
 
Сообщения: 2714
Зарегистрирован: 08 июн 2009, 18:22
Откуда: Тула

Re: Принцип построения Инвентаря

Сообщение ilka 14 ноя 2016, 14:36

Не правильный бутерброд...

Сам подход к системе не верный.

Игрок не должен знать каждый параметр предмета, предмет влияет на игрока а не наоборот. Когда я делал систему способностей там был абстрактный объект который работал сам независимо. Тогда и не было необходимости брать не типизированный данные как в вашем случае выходит когда не знаешь какой тип данных нужно получить. У вас мысль не в том направлении - частая ошибка начинающих, сам через это прошел.

Главное: предметы управляют игроком а не он ими(в плане эффектов и изменения свойств).
ilka
UNIверсал
 
Сообщения: 478
Зарегистрирован: 21 авг 2015, 19:32

Re: Принцип построения Инвентаря

Сообщение getAlex 14 ноя 2016, 22:22

ilka писал(а):предмет влияет на игрока а не наоборот

И наоборот тоже должно работать. Предмет мало чем отличается от персонажа: персонаж экипирует предметы, а предметы экипируют свои префиксы(статы, умения и прочее). К примеру, если игрок хочет перезачаровать какой-то стат предмета, или увеличить число префиксов, или генерация случайного предмет со случайными префиксами и статами, как в Diablo-3 или PoE.
getAlex
Адепт
 
Сообщения: 1775
Зарегистрирован: 10 авг 2013, 18:30

Re: Принцип построения Инвентаря

Сообщение Cr0c 15 ноя 2016, 13:58

getAlex писал(а):если игрок хочет перезачаровать какой-то стат предмета, или увеличить число префиксов, или генерация случайного предмет со случайными префиксами и статами

Это же действие, а не влияние - другой тип интерактива.
Аватара пользователя
Cr0c
Адепт
 
Сообщения: 3035
Зарегистрирован: 19 июн 2015, 13:50
Skype: cr0c81

Re: Принцип построения Инвентаря

Сообщение ilka 15 ноя 2016, 14:37

Можно проще себе это представить если сравнить получение предмета с заражением вирусом человека.

Когда вирус заражает человека, то он работает автономно, вирус сам выбирает какие свойства в человеке ему менять, а не человек разбирает свойства вируса чтобы изменить свои же характеристики. Так же и предмет он изменяет свойства игрока без участия самого игрока. Отсюда и нет необходимости определять что это за предмет и знать каждый его параметр - это делает сам предмет. Надеюсь так лучше объяснил.

На счет того что игрок управляет предметом также, так здесь нужно четко определять именно позиции "Предмет" и "Эффект". Ведь в первом случае игрок может удалять, приобретать и тд предмет, а вот эффект работает уже самостоятельно и не поддается изменению со стороны игрока.
ilka
UNIверсал
 
Сообщения: 478
Зарегистрирован: 21 авг 2015, 19:32

Re: Принцип построения Инвентаря

Сообщение GRESHNIK512 10 фев 2017, 11:21

Вывод персонаж должен иметь оболочку чтобы в нее запихнуть оружие и им пользоваться.
GRESHNIK512
UNец
 
Сообщения: 33
Зарегистрирован: 19 янв 2017, 18:03
Откуда: Глазов


Вернуться в Скрипты

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 7