0 / 0 / 0
Регистрация: 11.11.2015
Сообщений: 14
|
|||||||||||
1 | |||||||||||
Какую архитектуру программы лучше выбрать?11.04.2018, 15:02. Показов 4761. Ответов 12
Помогите, пожалуйста, определиться с подходом для решения следующей задачи:
Реализую предметы, для какой-нибудь RPG игры, т.е. предметы, которые добавляют определённые характеристики, например: Двуручный меч: сила +2, атака +4, защита -8, здоровье +16; Необходимо написать класс для предметов, который будет (при надевании например) изменять характеристики. Проблема в том, что предмет "Двуручный меч", будет содержать поле "ловкость" (и не только), если модификация этой характеристики предполагается каким-либо предметом. Двуручный меч: сила +2, ловкость +0, разум +0, атака +4, защита -8, здоровье +16, мана +0; А мне хотелось бы этого избежать. Примерная идея такая. При создании предмета
Но проблема в том, что я не знаю 1) как это реализовать 2) целесообразно ли, может быть есть подход лучше и проще. P.S. смотрел в сторону шаблона Builder (Builder+Director), но по-моему это что-то не то. Либо я не до конца его понял. P.S.S. в перспективе предметы будут описываться в каком-нибудь файле (xml например или типо того) и в коде преобразоваться в объекты класса Item
0
|
11.04.2018, 15:02 | |
Ответы с готовыми решениями:
12
Как лучше построить архитектуру программы С++ или Python для начинающего? Какую ветку выбрать лучше? Какую архитектуру предпочтительнее выбрать? Какую архитектуру баз данных лучше использовать |
Модератор
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 который содержит в себе список компонентов и ползволяет работать с ними (если нужно добавлять/удалять и получать их).
0
|
Модератор
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,469
|
|||||||||||
12.04.2018, 11:55 | 4 | ||||||||||
Паттерн Строитель используется для того, чтобы отделить создание объекта от его внутреннего представления. Когда объект состоит из разных компонентов, и разные Строители строят эти компоненты по-разному. У Вас единственный строитель, поэтому использовать этот паттерн нет смысла. Более того, у Вас даже не предусмотрена возможность добавить другой Builder (нет даже интерфейса), поэтому Ваш код не является реализацией этого паттерна.
Если всё это только ради флуент АПИ, то его можно реализовать и без этого. Причём, лучше - в классе расширения, который находится в отдельном пространстве имён (чтобы не навязывать его тем, кому он не нравится). По-моему, код
Зачем нужен интерфейс IStrength? Планируете в коде использовать разные реализации этого интерфейса? Зачем в классе Strength метод CalculateDamage? Разные атрибуты дают разные бонусы к урону. Результат зависит от порядка их применения. Скорее всего, итоговый бонус, который даёт один предмет зависит от других предметов (причём, не только из-за правил игры, но и из-за ошибок округления). У Вас же логика вычисления урона размазана по коду. То же самое относится и к остальным методам в этом классе. Зачем класс Strength унаследован от класса Component? "Сила является Компонентом"... Звучит чрезчур обобщённо. Какие методы есть в этом классе?
1
|
0 / 0 / 0
Регистрация: 11.11.2015
Сообщений: 14
|
|||||||||||||||||||||
12.04.2018, 17:50 [ТС] | 5 | ||||||||||||||||||||
1) Да, возможно с Билдером я перемудрил. Интерфейс ему не стал делать, т.к. и предполагал, что он будет один.
2) Но все-таки Билдера я сделал скорее потому, чтобы нельзя было изменить объект класса (по крайней мере напрямую). В варианте, который вы предложили можно сделать так:
Лучше, как я понимаю, сделать так:
3) IStrength планирую использовать так же для персонажей. На предмет и на персонажа влияет он одинаково (даёт 3 силы например и по-сути всё, дальше идёт просто вычисление характеристик). 4) CalculateDamage я запихал туда т.к. Strength - это одна из основных характеристик (сила, ловкость, разум) и она влияет на урон персонажа, на котором одета. Но я хочу видеть как она будет влиять на атаку (например 1 силы - 1.3f атаки) во время предпросмотра (навожу на вещь - вылезает тултип с характеристиками и как они будут на тебя влиять). А когда предмет одет, он добавляет характеристику персонажу и метод на самом персонаже уже посчитает урон (в планах так). Стоит упомянуть, что характеристики предметов - всегда int. А вот сколько они дадут характеристик персонажу (т.е. когда будут одеты) - это уже float. 5) Component у меня пустой. Всё для того, чтобы эти "компоненты" хранились в одном списке.
Strength - сила Agility - ловкость AllStats - сразу все характеристики Intellegence - интеллект Damage - урон Armor - броня AttackSpeed - скорость атаки MovementSpeed - скорость передвижения и т.д. и т.п.
0
|
Модератор
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,469
|
|
13.04.2018, 00:25 | 6 |
Сейчас нет времени на подробный ответ, поэтому кратко:
Используйте свойства без сеттеров. Используйте неизменяемые коллекции. Название не подходит. Можно обойтись без специальных классов для статов. Все статы можно хранить в одном словаре. Для имён можно использовать перечисление или константы из статического класса или сделать специальный класс с приватным конструктором, а все экземпляры (сила, ловкость и т.д.) создаются в статическом конструкторе и доступны через статические свойства. Лучше использовать одну и ту же функцию. Чтобы не приходилось менять в двух местах.
1
|
Модератор
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,469
|
|||||||||||
13.04.2018, 12:10 | 7 | ||||||||||
Неизменяемый объект можно сделать так:
Статы можно хранить в словаре. Класс для использования в качестве ключей может выглядеть, например, так:
1
|
0 / 0 / 0
Регистрация: 11.11.2015
Сообщений: 14
|
||||||
13.04.2018, 16:54 [ТС] | 8 | |||||
Большое спасибо за ответы!
На выходных возможности нет попрактиковаться, так что в понедельник-вторник переосмыслю, переделаю и отпишусь с результатом и советом. Еще раз спасибо Добавлено через 17 минут Я понял так:
0
|
Модератор
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,469
|
||||||
14.04.2018, 13:44 | 9 | |||||
Вы захотели засунуть влияние силы на ХП в класс Сила. А почему не в класс ХП?
Я бы создал для таких вещей отдельный класс Механика и засунул бы туда методы для влияния "всего на всё". Это не то, что я писал. Смысл другой. Для Вас Сила - это объект. Для меня Сила - это, условно, имя переменной. Когда Вы решаете задачу по физике, у Вас не возникает желания создать класс Скорость и засунуть в него формулу для пройдённого расстояния? То, что я написал, это всего навсего "продвинутый енум". То есть, мой вариант можно заменить на
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:
Меня сильно беспокоит, что конструкторы стали ужасными. По-моему ими неудобно пользоваться и такого не должно быть (возможно я просто не привык оперировать такими объектами и это нормально) Так же хотелось бы отделить "Собираемые предметы" от "Не собираемых", но проблема в том, что при создании объекта, он может быть одновременно и собираемым, и используемым. Может быть теперь стоит использовать паттерн Builder? Если да, то нужно ли как-то поменять класс Item (и его наследников)? Создание объекта (простого) выглядит вот так:
Напомню, что делаю приложение на WinForms. Оно должно будет хранить базу данных для этих предметов (при запуске приложения все их выгружать в память скорее всего). В каком виде всё это хранить? Использовать какой-нибудь SQLite или JSON/XML?
0
|
Модератор
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,469
|
|
18.04.2018, 12:17 | 11 |
Если Вы не собираетесь менять это свойство, то нужно убрать сеттер. Тогда это свойство можно будет установить только в конструкторе.
Таким образом, у пользователя сохраняется доступ к элементам _components через переменную setComponents. Поэтому, либо использовать неизменяемые коллекции (современный, функциональный подход), либо "общаться" через IEnumerable (классический C# подход). Это касается и других коллекций (setIngridients). ИМХО эта функция не имеет отношения к классу Item. Я бы сделал где-нибудь статическую функцию Color Map(ItemQuality). Сходу не могу ничего посоветовать. Используйте F#. (Для всего кода или только для части кода). В любом. Главное, чтобы хранение было отделено от использования. Для начала можно выбрать json - простой и читаемый (понятный человеку). Если нужно будет, потом поменяете (реализуете ещё один тип хранилища).
1
|
Модератор
3051 / 2193 / 459
Регистрация: 26.03.2015
Сообщений: 8,469
|
|
18.04.2018, 14:39 | 12 |
Сообщение было отмечено KartonArmadon как решение
Решение
Я в Warcraft 3 не играл, поэтому отвечаю из общих соображений.
Предметы могут иметь разные свойства. Вы хотите разбить их на классы по значениям некоторых из этих свойств. Я не вижу в этом смысла. Придётся писать лишний код, а взамен получаем только возможность вместо проверки значения свойства проверять тип объекта. У ConsumableItem свойство Cooldown явно не к месту. Если банки здоровья можно пить раз в 30 секунд, то число 30 не является свойством конкретной банки, а относится к игровой механике. Счётчик "когда можно пить следующую" тем более не относится к выпитой банке (которой уже нет), это свойство персонажа. У UsableItem свойство Cooldown, возможно, тоже лишнее. Если заклинание на посохе можно применять раз в 30 секунд, то это может быть свойством конкретной вещи, но, скорее всего, является "свойством заклинания" (одинаковое для всех вещей с таким заклинанием) и относится к игровой механике. Счётчик "когда можно опять использовать", видимо, относится к конкретному посоху, поэтому такое свойство нужно. Если на предмете написано "+10 к силе", то это не значит, что Вы получите эти +10 к силе. Возможно, чтобы их получить, предмет нужно одеть на определённый слот. Но даже в этом случае Вы можете не получить +10 к силе. Например, если предмет требует 50 ловкости для использования, у Вас было 55 ловкости и на Вас повесили заклинание -10 ловкости. Нужно различать Предметы и Бафы. Предмет в некоторых случаях может давать некоторые бафы. Свойства предмета зависят от правил игры. Это может быть вес, размер, список бафов, список пререквизитов, количество зарядов и так далее. Бафы могут быть временными, постоянными, периодическими и так далее. Чтобы предложить что-то конкретное, нужно знать Правила Игры. Добавлено через 22 минуты Я бы сделал конкретный класс Предмет. Позже, возможно, сделал отдельные классы для предметов разного типа, но только понимая, зачем это нужно. Проще потом за 2 часа отрефакторить, чем сейчас два дня думать, пытаясь учесть всё. Так же сделал бы класс Баф. Бафы могут быть как на предметах, так и на заклинаниях. Возможно, выделил бы отдельный класс (структуру в C#) Бонус из двух полей - атрибут, величина. То есть, Баф - это список Бонусов плюс ограничения/механика их действия.
1
|
25.04.2018, 16:49 | 13 |
Дважды прошу прощения за поздний комментарий и за оффтопик. Просто тема мне близкая.
Менять характеристики игрока или моба таким образом - удобно, но весьма небезопасно. Представьте, что по какой-то причине событие "надеть предмет" плюсует характеристику, а "снять" - нет. Мгновенно возникнет лавина игроков, разной степени совестливости, которые воспользуются этим читом. На мой взгляд, более безопасно (хотя и менее эффективно по производительности) расcчитывать характеристику в том месте, где она потребовалась. Например в функции расчета наносимого повреждения в бою вызывать метод расчета ловкости для определения точности удара.
0
|
25.04.2018, 16:49 | |
25.04.2018, 16:49 | |
Помогаю со студенческими работами здесь
13
Какую архитектуру баз данных лучше использовать? Какую архитектуру двухколоночного макета сайта лучше использовать? Какую клиент-серверную архитектуру лучше использовать для многопользовательской игры Как лучше спроектировать систему и какую архитектуру разработки приложения использовать? Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |