Форум программистов, компьютерный форум, киберфорум
ООП и паттерны
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.74/23: Рейтинг темы: голосов - 23, средняя оценка - 4.74
0 / 0 / 0
Регистрация: 11.11.2015
Сообщений: 14
1

Какую архитектуру программы лучше выбрать?

11.04.2018, 15:02. Показов 4761. Ответов 12

Author24 — интернет-сервис помощи студентам
Помогите, пожалуйста, определиться с подходом для решения следующей задачи:

Реализую предметы, для какой-нибудь RPG игры, т.е. предметы, которые добавляют определённые характеристики, например:
Двуручный меч:
сила +2,
атака +4,
защита -8,
здоровье +16;


Необходимо написать класс для предметов, который будет (при надевании например) изменять характеристики. Проблема в том, что предмет "Двуручный меч", будет содержать поле "ловкость" (и не только), если модификация этой характеристики предполагается каким-либо предметом.
Двуручный меч:
сила +2,
ловкость +0,
разум +0,
атака +4,
защита -8,
здоровье +16,
мана +0;

А мне хотелось бы этого избежать.

Примерная идея такая. При создании предмета
C#
1
var item = new Item();
добавлять к нему нужные мне параметры в виде компонент, например
C#
1
item.AddComponent<Strength>(2); //добавляем компоненту "Strength" со значением 2, т.е. добавляем модификатор "сила +2" на предмет.
Т.е. класс Item наследуется ComponentContainer, а сами компоненты (классы Strength, Agility, HealthPoints и т.д.) наследуются от класса Component.

Но проблема в том, что я не знаю
1) как это реализовать
2) целесообразно ли, может быть есть подход лучше и проще.

P.S. смотрел в сторону шаблона Builder (Builder+Director), но по-моему это что-то не то. Либо я не до конца его понял.
P.S.S. в перспективе предметы будут описываться в каком-нибудь файле (xml например или типо того) и в коде преобразоваться в объекты класса Item
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
11.04.2018, 15:02
Ответы с готовыми решениями:

Как лучше построить архитектуру программы
Опытные люди, подскажите, пожалуйста. Пишу игру танки(что-то вроде танков на денди, но с большим...

С++ или Python для начинающего? Какую ветку выбрать лучше?
Всем привет! Некоторое время назад начал изучать C++, недавно купил и уже изучаю книгу...

Какую архитектуру предпочтительнее выбрать?
Всем приветов! Возник небольшой вопрос. Допустим имеется приложение, простенькая регистрация....

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

12
Модератор
Эксперт функциональных языков программирования
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,469
11.04.2018, 17:36 2
Предмет содержит список модификаций. При одевании проходите по списку и применяете модификации.
1
0 / 0 / 0
Регистрация: 11.11.2015
Сообщений: 14
12.04.2018, 09:23  [ТС] 3
Погуглил, почитал и пришел к следующему:
Сам Item наследуется от ComponentContainer который содержит в себе список компонентов и ползволяет работать с ними (если нужно добавлять/удалять и получать их).
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class Item : ComponentContainer
    {
        private string _name;
 
        public string Name { get; }
        
        private Item(ItemBuilder builder)
        {
            this._name = builder.GetName();
            this._components = builder.Components();
        }
 
        public class ItemBuilder
        {
            private string _name;
            private string _description;
            private System.Collections.Generic.List<Component> _components = 
                new System.Collections.Generic.List<Component>();
 
            public ItemBuilder Name(string setName)
            {
                this._name = setName;
                return this;
            }
 
            public ItemBuilder AddComponent<T>(T component) where T : Component
            {
                _components.Add(component);
                return this;
            }
 
            public string GetName() => _name;
            public System.Collections.Generic.List<Component> Components() => _components;
 
            public Item Build()
            {
                return new Item(this);
            }
        }
Для создания объекта используется паттерн Builder.
C#
1
2
3
4
sword = new Item.ItemBuilder()
                .Name("Simple Sword")
                .AddComponent(new Strength(2))
                .Build();
А сами компоненты реализуются отдельными классами:
C#
1
2
3
4
5
6
7
interface IStrength
    {
        int Value { get; }
        float CalculateHp { get; }
        float CalculateHpRegen { get; }
        float CalculateDamage { get; }
    }
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Strength : Component, IStrength
    {
        private int _value;
 
        public int Value => _value;
        public float CalculateHp => _value * GameParameters.STR_TO_HP;
        public float CalculateHpRegen => Value * GameParameters.STR_TO_HPREGEN;
        public float CalculateDamage => 
            GameParameters.PRIMARY_ATTRIBUTE == Attributes.Strength 
            ? Value * GameParameters.PRIMARY_ATTRIBUTE_TO_DAMAGE 
            : 0;
 
        public Strength() => _value = 0;
        public Strength(int setValue) => _value = setValue;
    }
0
Модератор
Эксперт функциональных языков программирования
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,469
12.04.2018, 11:55 4
Паттерн Строитель используется для того, чтобы отделить создание объекта от его внутреннего представления. Когда объект состоит из разных компонентов, и разные Строители строят эти компоненты по-разному. У Вас единственный строитель, поэтому использовать этот паттерн нет смысла. Более того, у Вас даже не предусмотрена возможность добавить другой Builder (нет даже интерфейса), поэтому Ваш код не является реализацией этого паттерна.

Если всё это только ради флуент АПИ, то его можно реализовать и без этого. Причём, лучше - в классе расширения, который находится в отдельном пространстве имён (чтобы не навязывать его тем, кому он не нравится).
По-моему, код
C#
1
2
sword = new Item().Name("Simple Sword")
                .AddComponent(new Strength(2));
выглядит лучше, чем
C#
1
2
3
4
sword = new Item.ItemBuilder()
                .Name("Simple Sword")
                .AddComponent(new Strength(2))
                .Build();

Зачем нужен интерфейс IStrength? Планируете в коде использовать разные реализации этого интерфейса?

Зачем в классе Strength метод CalculateDamage?
Разные атрибуты дают разные бонусы к урону. Результат зависит от порядка их применения. Скорее всего, итоговый бонус, который даёт один предмет зависит от других предметов (причём, не только из-за правил игры, но и из-за ошибок округления). У Вас же логика вычисления урона размазана по коду.
То же самое относится и к остальным методам в этом классе.

Зачем класс Strength унаследован от класса Component?
"Сила является Компонентом"... Звучит чрезчур обобщённо. Какие методы есть в этом классе?
1
0 / 0 / 0
Регистрация: 11.11.2015
Сообщений: 14
12.04.2018, 17:50  [ТС] 5
1) Да, возможно с Билдером я перемудрил. Интерфейс ему не стал делать, т.к. и предполагал, что он будет один.

2) Но все-таки Билдера я сделал скорее потому, чтобы нельзя было изменить объект класса (по крайней мере напрямую). В варианте, который вы предложили можно сделать так:
C#
1
2
3
sword = new Item().Name("Simple Sword")
                .AddComponent(new Strength(2));
sword.Name("Magic Sword");
т.е. можно спокойно изменить поле класса. А я бы хотел этого избежать.
Лучше, как я понимаю, сделать так:
C#
1
2
3
4
5
6
7
8
9
10
11
public class Item : ComponentContainer
    {
        private string _name;
 
        public string Name { get; }
        
        private Item(string setName)
        {
            this._name = setName;
        }
        //... остальной код
Но в таком случае вылезает следующая проблема: я могу добавить компоненты уже для созданного предмета (а я хочу избежать этого).
C#
1
2
3
sword = new Item().Name("Simple Sword")
                .AddComponent(new Strength(2));
sword.AddComponent(new Agility(4));
Вот не знаю как лучше сделать так, чтобы объект создавался, а потом изменить его было нельзя.

3) IStrength планирую использовать так же для персонажей. На предмет и на персонажа влияет он одинаково (даёт 3 силы например и по-сути всё, дальше идёт просто вычисление характеристик).

4) CalculateDamage я запихал туда т.к. Strength - это одна из основных характеристик (сила, ловкость, разум) и она влияет на урон персонажа, на котором одета. Но я хочу видеть как она будет влиять на атаку (например 1 силы - 1.3f атаки) во время предпросмотра (навожу на вещь - вылезает тултип с характеристиками и как они будут на тебя влиять). А когда предмет одет, он добавляет характеристику персонажу и метод на самом персонаже уже посчитает урон (в планах так).
Стоит упомянуть, что характеристики предметов - всегда int. А вот сколько они дадут характеристик персонажу (т.е. когда будут одеты) - это уже float.

5) Component у меня пустой. Всё для того, чтобы эти "компоненты" хранились в одном списке.
C#
1
protected List<Component> _components;
Компоненты могут быть примерно следующие:
Strength - сила
Agility - ловкость
AllStats - сразу все характеристики
Intellegence - интеллект
Damage - урон
Armor - броня
AttackSpeed - скорость атаки
MovementSpeed - скорость передвижения
и т.д. и т.п.
0
Модератор
Эксперт функциональных языков программирования
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,469
13.04.2018, 00:25 6
Сейчас нет времени на подробный ответ, поэтому кратко:

Цитата Сообщение от KartonArmadon Посмотреть сообщение
чтобы нельзя было изменить объект класса
Используйте свойства без сеттеров.

Цитата Сообщение от KartonArmadon Посмотреть сообщение
чтобы объект создавался, а потом изменить его было нельзя
Используйте неизменяемые коллекции.

Цитата Сообщение от KartonArmadon Посмотреть сообщение
Component у меня пустой
Название не подходит.

Цитата Сообщение от KartonArmadon Посмотреть сообщение
IStrength планирую использовать так же для персонажей
Можно обойтись без специальных классов для статов. Все статы можно хранить в одном словаре. Для имён можно использовать перечисление или константы из статического класса или сделать специальный класс с приватным конструктором, а все экземпляры (сила, ловкость и т.д.) создаются в статическом конструкторе и доступны через статические свойства.

Цитата Сообщение от KartonArmadon Посмотреть сообщение
Но я хочу видеть как она будет влиять на атаку (например 1 силы - 1.3f атаки) во время предпросмотра (навожу на вещь - вылезает тултип с характеристиками и как они будут на тебя влиять). А когда предмет одет, он добавляет характеристику персонажу и метод на самом персонаже уже посчитает урон (в планах так).
Лучше использовать одну и ту же функцию. Чтобы не приходилось менять в двух местах.
1
Модератор
Эксперт функциональных языков программирования
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,469
13.04.2018, 12:10 7
Неизменяемый объект можно сделать так:
C#
1
2
3
4
5
6
7
8
9
10
11
public class Item : ComponentContainer
{
    public string Name { get; }
    public IEnumerable<Component> Components { get; }
    
    public Item(string name, IEnumerable<Component> components)
    {
        Name = name;
        Components = new List<Component>(components);
    }
}
Если по каким-то причинам не хочется использовать IEnumerable, то можно взять что-нибудь из System.Collections.Immutable.


Статы можно хранить в словаре. Класс для использования в качестве ключей может выглядеть, например, так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
public struct Stat 
{
    private int Id { get; }
    
    private Stat(int id)
    {
        Id = id;
    }
 
    public static Stat Srength { get; } = new Stat(1);
    public static Stat Dexterity { get; } = new Stat(2);
}
При желании можно перегрузить GetHashCode() и Equals(). В отличии от enum экземпляры такого класса могут принимать только явно заданные значения. Хотя можно и enum использовать.
1
0 / 0 / 0
Регистрация: 11.11.2015
Сообщений: 14
13.04.2018, 16:54  [ТС] 8
Большое спасибо за ответы!
На выходных возможности нет попрактиковаться, так что в понедельник-вторник переосмыслю, переделаю и отпишусь с результатом и советом.
Еще раз спасибо

Добавлено через 17 минут
Цитата Сообщение от Shamil1 Посмотреть сообщение
Статы можно хранить в словаре. Класс для использования в качестве ключей может выглядеть, например, так:
C#
1
2
3
4
5
6
7
8
9
10
public struct Stat 
{
 private int Id { get; }
private Stat(int id)
 {
 Id = id;
 }
public static Stat Srength { get; } = new Stat(1);
 public static Stat Dexterity { get; } = new Stat(2);
}
При желании можно перегрузить GetHashCode() и Equals(). В отличии от enum экземпляры такого класса могут принимать только явно заданные значения. Хотя можно и enum использовать.
Я понял так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public enum Stats
    {
        Strength = 1,
        Agility = 2,
        Intellegence = 3
    };
 
    public struct Stat
    {
        private int Id { get; }
        private int Value { get; }
 
        private Stat(int id, int value)
        {
            this.Id = id;
            this.Value = value;
        }
 
        public static Stat Strength(int value) => new Stat((int)Stats.Strength, value);
    }
И опять застопорился... Я изначально сделал отдельные классы для статов потому-что каждая стата влияет на разные параметры: Strength - на ХП, хп реген, атаку, Agility - на защиту, скорость атаки и атаку, Intellegence - на манну, восстановление манны, силу заклинаний и т.д. и т.п. А в случае со структурой у меня такого разнообразия сотворить не получится.
Цитата Сообщение от Shamil1 Посмотреть сообщение
Неизменяемый объект можно сделать так:
C#
1
2
3
4
5
6
7
8
9
10
public class Item : ComponentContainer
{
 public string Name { get; }
 public IEnumerable<Component> Components { get; }
public Item(string name, IEnumerable<Component> components)
 {
 Name = name;
 Components = new List<Component>(components);
 }
}
Если по каким-то причинам не хочется использовать IEnumerable, то можно взять что-нибудь из System.Collections.Immutable.
А с этим разобрался. Не понимаю почему сразу так не сделал, слишком уж очевидно было -_- Спасибо!
0
Модератор
Эксперт функциональных языков программирования
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,469
14.04.2018, 13:44 9
Цитата Сообщение от KartonArmadon Посмотреть сообщение
Я изначально сделал отдельные классы для статов потому-что каждая стата влияет на разные параметры: Strength - на ХП, хп реген, атаку
Вы захотели засунуть влияние силы на ХП в класс Сила. А почему не в класс ХП?
Я бы создал для таких вещей отдельный класс Механика и засунул бы туда методы для влияния "всего на всё".

Цитата Сообщение от KartonArmadon Посмотреть сообщение
Я понял так:
Это не то, что я писал. Смысл другой. Для Вас Сила - это объект. Для меня Сила - это, условно, имя переменной.
Когда Вы решаете задачу по физике, у Вас не возникает желания создать класс Скорость и засунуть в него формулу для пройдённого расстояния?
То, что я написал, это всего навсего "продвинутый енум". То есть, мой вариант можно заменить на
C#
1
2
3
4
5
6
public enum Stats
    {
        Strength = 1,
        Agility = 2,
        Intellegence = 3
    };
0
0 / 0 / 0
Регистрация: 11.11.2015
Сообщений: 14
18.04.2018, 10:57  [ТС] 10
За выходные немного переосмыслил и прислушался к советам, которые вы давали.
Немного увеличил функционал:
Item, помимо компонентов, должен содержать следующие поля:
Name - Имя
Quality- Качество (обычный, редкий, мифический и т.д.)
Sellable - Продаваемый ли предмет
Ingredients - Из чего он собирается (если знаете, то механика как в Warcraft 3, берёте в инвентарь определенные предметы и они складываются).

Так же создал 2 класса UsableItem и ConsumableItem для предметов, которые можно использовать (посох огненного шара, например) и для расходуемых (зелье здоровья, например) предметов соответственно, которые наследуются от Item.

В связи с этим класс заметно раздулся.
Item.cs:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
    public class Item : ComponentContainer
    {
        public string Name { get; private set; }
        public ItemQuality Quality { get; private set; }
        public List<string> Ingridients { get; private set; }
        public bool Sellable { get; private set; }
 
        public Color NameColor { get; private set; }
 
        public Item(string setName,
                    Dictionary<StatType, Int32> setComponents,
                    ItemQuality setQuality = ItemQuality.White,
                    List<string> setIngridients = null,
                    bool setSellable = false)
        {
            this.Name = setName;
            base._components = setComponents;
            SetItemQuality(setQuality);
            this.Ingridients = setIngridients;
            this.Sellable = setSellable;
        }
 
        private void SetItemQuality(ItemQuality setQuality)
        {
            this.Quality = setQuality;
            switch (this.Quality)
            {
                case ItemQuality.White:
                    NameColor = Color.White;
                    break;
                case ItemQuality.Orange:
                    NameColor = Color.Orange;
                    break;
                case ItemQuality.SteelBlue:
                    NameColor = Color.SteelBlue;
                    break;
                case ItemQuality.Red:
                    NameColor = Color.Red;
                    break;
                case ItemQuality.Black:
                    NameColor = Color.Black;
                    break;
                case ItemQuality.Blue:
                    NameColor = Color.Blue;
                    break;
                case ItemQuality.Crafted:
                    NameColor = Color.Green;
                    break;
            }
        }
 
        public override string ToString()
        {
            return this.Name; //пока так
        }
}
ConsumeableItem.cs
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ConsumableItem : Item
    {
        public int Charges { get; private set; }
        public int Cooldown { get; private set; }
        public string Description { get; private set; }
 
        public ConsumableItem(string setName,
                    int setCharges,
                    int setCooldown,
                    string setDescription,
                    Dictionary<StatType, Int32> setComponents,
                    ItemQuality setQuality = ItemQuality.White,
                    List<string> setIngridients = null,
                    bool setSellable = false) 
                    : base(setName, setComponents, setQuality, setIngridients, setSellable)
        {
            this.Charges = setCharges;
            this.Cooldown = setCooldown;
            this.Description = setDescription;
        }
    }
и UsableItem.cs
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class UsableItem : Item
    {
        public int Cost { get; private set; }
        public int Cooldown { get; private set; }
        public string Descripion { get; private set; }
 
        public UsableItem(string setName, 
            int setCost,
            int setCooldown,
            string setDescription,
            Dictionary<StatType, int> setComponents, 
            ItemQuality setQuality = ItemQuality.White, 
            List<string> setIngridients = null,
            bool setSellable = false) 
            : base(setName, setComponents, setQuality, setIngridients, setSellable)
        {
            this.Cost = setCost;
            this.Cooldown = setCooldown;
            this.Descripion = setDescription;
        }
    }
У ConsumableItem и UsableItem похожий функционал и структура, но я решил не городить огород и полностью разделить реализацию (не знаю правильно ли это или нет).
Меня сильно беспокоит, что конструкторы стали ужасными. По-моему ими неудобно пользоваться и такого не должно быть (возможно я просто не привык оперировать такими объектами и это нормально)
Так же хотелось бы отделить "Собираемые предметы" от "Не собираемых", но проблема в том, что при создании объекта, он может быть одновременно и собираемым, и используемым.
Может быть теперь стоит использовать паттерн Builder? Если да, то нужно ли как-то поменять класс Item (и его наследников)?

Создание объекта (простого) выглядит вот так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Item sword = new Item("Simple Sword", 
                new Dictionary<StatType, int>()
                {
                    { StatType.Damage, 10 },
                    { StatType.Strength, 2 },
                    { StatType.Agility, 1 },
                    { StatType.Intellegence, -4 }
                },
                ItemQuality.White);
 
            Item windOrb = new Item("Orb of Wind", 
                new Dictionary<StatType, int>()
                {
                    { StatType.Damage, 4 },
                    { StatType.Intellegence, +8 },
                    { StatType.MovementSpeed, 10 }
                },
                ItemQuality.Orange);
 
            Item windSword = new Item("Wind Sword",
                new Dictionary<StatType, int>()
                {
                    { StatType.AllStats, 4 },
                    { StatType.Damage, 20 },
                    { StatType.MovementSpeed, 15 }
                },
                ItemQuality.Crafted,
                new List<String>()
                {
                    sword.ToString(),
                    windOrb.ToString()
                });
И на следок вопрос на другую тему:
Напомню, что делаю приложение на WinForms. Оно должно будет хранить базу данных для этих предметов (при запуске приложения все их выгружать в память скорее всего). В каком виде всё это хранить? Использовать какой-нибудь SQLite или JSON/XML?
0
Модератор
Эксперт функциональных языков программирования
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,469
18.04.2018, 12:17 11
Цитата Сообщение от KartonArmadon Посмотреть сообщение
{ get; private set; }
Если Вы не собираетесь менять это свойство, то нужно убрать сеттер. Тогда это свойство можно будет установить только в конструкторе.

Цитата Сообщение от KartonArmadon Посмотреть сообщение
base._components = setComponents;
Таким образом, у пользователя сохраняется доступ к элементам _components через переменную setComponents. Поэтому, либо использовать неизменяемые коллекции (современный, функциональный подход), либо "общаться" через IEnumerable (классический C# подход).
Это касается и других коллекций (setIngridients).

Цитата Сообщение от KartonArmadon Посмотреть сообщение
private void SetItemQuality(ItemQuality setQuality)
ИМХО эта функция не имеет отношения к классу Item. Я бы сделал где-нибудь статическую функцию Color Map(ItemQuality).

Цитата Сообщение от KartonArmadon Посмотреть сообщение
У ConsumableItem и UsableItem похожий функционал и структура, но я решил не городить огород и полностью разделить реализацию (не знаю правильно ли это или нет).
Сходу не могу ничего посоветовать.

Цитата Сообщение от KartonArmadon Посмотреть сообщение
Меня сильно беспокоит, что конструкторы стали ужасными.
Используйте F#. (Для всего кода или только для части кода).

Цитата Сообщение от KartonArmadon Посмотреть сообщение
В каком виде всё это хранить?
В любом. Главное, чтобы хранение было отделено от использования.
Для начала можно выбрать json - простой и читаемый (понятный человеку). Если нужно будет, потом поменяете (реализуете ещё один тип хранилища).
1
Модератор
Эксперт функциональных языков программирования
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,469
18.04.2018, 14:39 12
Лучший ответ Сообщение было отмечено KartonArmadon как решение

Решение

Цитата Сообщение от KartonArmadon Посмотреть сообщение
У ConsumableItem и UsableItem похожий функционал и структура, но я решил не городить огород и полностью разделить реализацию (не знаю правильно ли это или нет).
Меня сильно беспокоит, что конструкторы стали ужасными. По-моему ими неудобно пользоваться и такого не должно быть (возможно я просто не привык оперировать такими объектами и это нормально)
Так же хотелось бы отделить "Собираемые предметы" от "Не собираемых", но проблема в том, что при создании объекта, он может быть одновременно и собираемым, и используемым.
Я в Warcraft 3 не играл, поэтому отвечаю из общих соображений.

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

У ConsumableItem свойство Cooldown явно не к месту. Если банки здоровья можно пить раз в 30 секунд, то число 30 не является свойством конкретной банки, а относится к игровой механике. Счётчик "когда можно пить следующую" тем более не относится к выпитой банке (которой уже нет), это свойство персонажа.

У UsableItem свойство Cooldown, возможно, тоже лишнее. Если заклинание на посохе можно применять раз в 30 секунд, то это может быть свойством конкретной вещи, но, скорее всего, является "свойством заклинания" (одинаковое для всех вещей с таким заклинанием) и относится к игровой механике. Счётчик "когда можно опять использовать", видимо, относится к конкретному посоху, поэтому такое свойство нужно.

Если на предмете написано "+10 к силе", то это не значит, что Вы получите эти +10 к силе. Возможно, чтобы их получить, предмет нужно одеть на определённый слот. Но даже в этом случае Вы можете не получить +10 к силе. Например, если предмет требует 50 ловкости для использования, у Вас было 55 ловкости и на Вас повесили заклинание -10 ловкости.

Нужно различать Предметы и Бафы. Предмет в некоторых случаях может давать некоторые бафы. Свойства предмета зависят от правил игры. Это может быть вес, размер, список бафов, список пререквизитов, количество зарядов и так далее. Бафы могут быть временными, постоянными, периодическими и так далее. Чтобы предложить что-то конкретное, нужно знать Правила Игры.

Добавлено через 22 минуты
Я бы сделал конкретный класс Предмет. Позже, возможно, сделал отдельные классы для предметов разного типа, но только понимая, зачем это нужно. Проще потом за 2 часа отрефакторить, чем сейчас два дня думать, пытаясь учесть всё.
Так же сделал бы класс Баф. Бафы могут быть как на предметах, так и на заклинаниях. Возможно, выделил бы отдельный класс (структуру в C#) Бонус из двух полей - атрибут, величина. То есть, Баф - это список Бонусов плюс ограничения/механика их действия.
1
1003 / 1858 / 176
Регистрация: 07.05.2013
Сообщений: 3,894
Записей в блоге: 12
25.04.2018, 16:49 13
Цитата Сообщение от KartonArmadon Посмотреть сообщение
класс для предметов, который будет (при надевании например) изменять характеристики.
Дважды прошу прощения за поздний комментарий и за оффтопик. Просто тема мне близкая.

Менять характеристики игрока или моба таким образом - удобно, но весьма небезопасно. Представьте, что по какой-то причине событие "надеть предмет" плюсует характеристику, а "снять" - нет. Мгновенно возникнет лавина игроков, разной степени совестливости, которые воспользуются этим читом.

На мой взгляд, более безопасно (хотя и менее эффективно по производительности) расcчитывать характеристику в том месте, где она потребовалась. Например в функции расчета наносимого повреждения в бою вызывать метод расчета ловкости для определения точности удара.
0
25.04.2018, 16:49
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
25.04.2018, 16:49
Помогаю со студенческими работами здесь

Какую архитектуру баз данных лучше использовать?
8-)

Какую архитектуру двухколоночного макета сайта лучше использовать?
Здравствуйте! Меня интересует построение макета сайта с помощью двух колонок. В своем сайте я...

Какую клиент-серверную архитектуру лучше использовать для многопользовательской игры
Здравствуйте. Более-менее подучил C#, есть небольшой опыт написания приложений WinForms и WPF. ...

Как лучше спроектировать систему и какую архитектуру разработки приложения использовать?
Всем привет, ситуация такая: Сейчас появилось время и решил снова заняться разработкой САПР для...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru