Страница 1 из 1

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

СообщениеДобавлено: 09 ноя 2016, 22:03
mastersmit
Вопрос довольно обширный.
Вот в размышлениях. Есть уже наполовину готовая написанная система, но по мне она выглядит в коде убого..
Все сводится к тому, что в ресурсах есть такого плана код:
Синтаксис:
Используется 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() (рефлексия?).. единственно удобство что придется обращаться к одному списку, а не к нескольким..

Тоже самое и с самим инвентарем игрока. Если сделаем в виде одного списка, то опять определение типа и прочее, прочее.. Или я под утро уже совсем куда-то побрел не туда или и правда не хватает мысли.. Хожу, блин, все вокруг, да около.. Или в любом случае придется описывать методы в инвентаре, которые будут получать то или иное через кучу Свитчей/Ифов?

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

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

Обычно такая проблема подсказывает, что возможно будет уместен шаблон Стратегия.

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

СообщениеДобавлено: 10 ноя 2016, 02:02
getAlex
Для инвентаря: стратегия и компоновщик(композиция)

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

СообщениеДобавлено: 10 ноя 2016, 10:26
Tolking
Используй интерфейсы.

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

СообщениеДобавлено: 10 ноя 2016, 11:01
Cr0c
mastersmit писал(а):через GetType() (рефлексия?)

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

Можно же вот так, без рефлексии. Можно динамическую типизацию ещё. Это как в Lua. Файлы конфигураций оружия в Crysis так написаны и в Far Cry.

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

СообщениеДобавлено: 10 ноя 2016, 13:49
getAlex
Основная концепция вещей должна быть "что я умею?", а не "кто я такой?".

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

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

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

Slots должны работать по тому же принципу, что и компонеты в GameObject на сцене, но только это твои компоненты, не наследуемые от монобехевер. Кстати, персонаж тоже состоит из слотов(только уже слотов из items), в которые ты можешь одеть вещи.

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

СообщениеДобавлено: 10 ноя 2016, 15:20
Cr0c
getAlex писал(а):К примеру, в тип "шлем" нельзя будет вставить "наносит %%x урона стихией %%y"

Это спорно. Может нанести при получении урона, например, или при каком-то ещё условии (допустим, способность "удар головой" или вроде того).

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

СообщениеДобавлено: 14 ноя 2016, 09:06
mastersmit
Ну, в целом пока определился с построением общих списков всех предметов
Синтаксис:
Используется 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;
    }
 

Но чет эта упаковка/распаковка совсем не нравится.. Есть еще обобщенные классы, правда пока не совсем до конца понял их принцип, но там для каждой операции так же надо указывать тип, зато минуя упаковку/распаковку..
Можно ли еще каким-то образом сделать универсальную переменную, которая вернет необходимый тип?

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

СообщениеДобавлено: 14 ноя 2016, 11:50
Cr0c
mastersmit писал(а):Но чет эта упаковка/распаковка совсем не нравится

Так наследование же. Либо так, либо отказаться от наследования и динамически типизировать данные.

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

СообщениеДобавлено: 14 ноя 2016, 13:05
Tolking
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...

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

СообщениеДобавлено: 14 ноя 2016, 14:36
ilka
Не правильный бутерброд...

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

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

Главное: предметы управляют игроком а не он ими(в плане эффектов и изменения свойств).

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

СообщениеДобавлено: 14 ноя 2016, 22:22
getAlex
ilka писал(а):предмет влияет на игрока а не наоборот

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

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

СообщениеДобавлено: 15 ноя 2016, 13:58
Cr0c
getAlex писал(а):если игрок хочет перезачаровать какой-то стат предмета, или увеличить число префиксов, или генерация случайного предмет со случайными префиксами и статами

Это же действие, а не влияние - другой тип интерактива.

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

СообщениеДобавлено: 15 ноя 2016, 14:37
ilka
Можно проще себе это представить если сравнить получение предмета с заражением вирусом человека.

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

На счет того что игрок управляет предметом также, так здесь нужно четко определять именно позиции "Предмет" и "Эффект". Ведь в первом случае игрок может удалять, приобретать и тд предмет, а вот эффект работает уже самостоятельно и не поддается изменению со стороны игрока.

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

СообщениеДобавлено: 10 фев 2017, 11:21
GRESHNIK512
Вывод персонаж должен иметь оболочку чтобы в нее запихнуть оружие и им пользоваться.