PDA

Просмотр полной версии : Разработка модели "куклы" персонажа и влияющего на его характеристики "шмота"


PlutDem
29.03.2012, 19:28
Здравствуйте, есть персонаж с различными характеристиками и у него есть слоты под предметы, при добавлении которых(предметов) меняются характеристики персонажа (По сути то, что есть почти в каждой RPG).
Как это грамотно реализовать? Мне пришло на ум, только добавить в объект предмета все характеристики какие могут быть и прибавлять их значение к параметрам персонажа
class Person {

public var str = 10;
public var dex = 7;
public var con = 0;
...

function addItem(item):void {
str += item.str;
dex += item.dex;
con += item.con;
...
}
}
Но такой способ очень накладный по памяти, особенно если использовать его в огромном живом мире где таких объектов будет не одна тысяча.

TanaTiX
29.03.2012, 19:48
Свойства не публичные, а геттеры.
При добавлении/снятии объекта (не забываем про типизацию) пересчитываем только актуальные свойства и только при добавлении/снятии. За результирующие свойства отвечают отдельные переменные.

Эта 1000 будет находится на сцене одновременно?

PlutDem
29.03.2012, 20:09
пересчитываем только актуальные свойства
Вроде этого?
function addItem(item):void {

if(item.str)
str += item.str;
if(item.dex)
dex += item.dex;
if(item.con)
con += item.con;
...
}
Эта 1000 будет находится на сцене одновременно?
Угу, причем возможно не одна, а раз эдак в 8 больше. Потому то и хранить в предмете данные о всех характеристиках не хочется.

alatar
29.03.2012, 20:21
Вроде этого?
Вроде этого (http://www.youtube.com/watch?v=17XTOODeWQE&feature=player_embedded).

warsem
29.03.2012, 20:27
я когда то так делал, но это был не АС :)


class Person {
// базовые статы
var basa_str:int = 10;
var basa_dex:int = 15;

// текущие параметры
var str:int;
var dex:int;

// функция, вызваетца каждый раз, как что-то сняли/одели/т.п.
function recheckStats():void {
str = basa_str;
if (одета шапка) { str+=шапка.str; }
if (одеты труселя) { str+=труселя.str; }
...
}


}

TanaTiX
29.03.2012, 21:17
Угу, причем возможно не одна, а раз эдак в 8 больше.
Мне уже страшно.
Вроде этого?
Нет, вроде того, что предложил alatar.

PlutDem
29.03.2012, 21:55
Декоратор, штука, конечно, хорошая, но проблему с хранением лишних свойств(бонусов) в предмете не решает.str = 10;
dex = 0;
con = 0;
...
Зачем хранить dex,con и т.п. если бонус только к str ? На каждый предмет отдельный декоратор не создать, не говоря уже о том. что постоянное использование декоратора на объекте в конечном итоге приведет к снижению производительности.

TanaTiX
29.03.2012, 22:23
Это не проблема лишних свойств. Они (свойства) сидят себе в объектах и кушать не просят. Это проблема архитектуры.

PlutDem
29.03.2012, 22:27
Это не проблема лишних свойств. Они (свойства) сидят себе в объектах и кушать не просят. Это проблема архитектуры.
Как же? Тысячи объектов(предметов), в них еще штук 20 объектов-свойств(характеристик). Все это отхватит приличный кусок памяти.

anmelegov
29.03.2012, 23:01
я думаю не играбельно будет даже если принебречь производительностью (фпс скорее всего будет меньше единицы)

Wolsh
29.03.2012, 23:09
PlutDem, тысячи экземпляров или тысячи классов? Разница существенна.

PlutDem
29.03.2012, 23:42
Wolsh
Экземпляров, естественно.

Вроде нашел кое какое решение:class Bonus {

public var type:String;
public var ammount:int;

public function Bonus(newType:String,newAmmount:int) {
type = newType;
ammount = newAmmount;
}
}class ItemSword {

public var bonuses:Array = new Array();

public function ItemSword() {
bonuses.push(new Bonus("str", 10));
bonuses.push(new Bonus("con",5))
}
}class Person {

public var str:int=0;
public var dex:int=0;
public var con :int = 0;

public function addItem(item:ItemSword):void {
for (var i:int = 0; i < item.bonuses.lenght; i++) {
// проходим по массиву с бонусами и в зависимости от типа бонуса прибавляем его к нужной характеристике
this[item.bonuses[i].type] += item.bonuses[i].ammount;
}
}
}

Wolsh
30.03.2012, 00:00
Ну так. То есть все разновидности шапок могут иметь вес 0.5, который хранится в статической константе класса Hat, так? И занимать память для веса трех миллиардов шапок будет только единственное свойство класса Hat.

Добавлено через 8 минут
"Ну так" не относилось к дописанному вами позже коду, ОК?))
Вам надо почитать про геттеры и сеттеры. Нехорошо, что Вы переписываете характеристики персонажа. Надо только отдавать комплексные характеристики, расчитывая их при отдаче в геттере. Хранить надо только реальные (базовые) характеристики персонажа; характеристики оружия и брони прекрасно хранятся в оружии и броне. Незачем занимать память, дублируя эти простые типы.

PlutDem
30.03.2012, 00:11
Wolsh
Дело в том, что параметры вещей будут случайно генерироваться и давать различные бонусы(Одна шапка дает +5 к силе, другая может дать -7 к чему нибудь и т.д.) Нужно при надевании вещи прибавлять эти бонусы к персонажу.

Wolsh
30.03.2012, 00:12
Массив это уловка, костыль чтобы избежать типизации. Если Вы задумали делать RPG, избегая типизации, она начнет глючить уже при готовности 0.0001%.

Добавлено через 12 минут
параметры вещей будут случайно генерироватьсяНу а что Вас тогда смущает? Количество предметов с бонусами будет таким образом ограничено, например размером инвентаря. О каких тысячах речь? Будет 50, ну пусть сто предметов в инвентаре. Или Вы хотите дать персонажу "склад", где он будет коллекционировать удачные находки? Тогда конечно будут проблемы, они есть и в "обычных" играх, в том же Обливион периодически лут из хранилищ пропадает)))

PlutDem
30.03.2012, 00:36
Массив это уловка, костыль чтобы избежать типизации.
Избежать типизации чего? Приведенный выше код нужен был что бы узнать какие бонусы есть у вещи, и применить их к персонажу.
Нехорошо, что Вы переписываете характеристики персонажа. Надо только отдавать комплексные характеристики, расчитывая их при отдаче в геттере. Хранить надо только реальные (базовые) характеристики персонажа; характеристики оружия и брони прекрасно хранятся в оружии и броне. Незачем занимать память, дублируя эти простые типы.
Вот тут, честно, ничего не понял. Что подразумевается под комплексными характеристиками? Ну хранятся характеристики персонажа и вещей отдельно, а как их объединить то?
Можно, скажем, при расчете урона, наносимого персонажу, пройтись по всем слотам под вещи и проверить есть ли у вещей бонусы на защиту, если есть, то использовать их при расчете урона. Но этот способ очень ресурсоемок.
Ну а что Вас тогда смущает? Количество предметов с бонусами будет таким образом ограничено, например размером инвентаря. О каких тысячах речь? Будет 50, ну пусть сто предметов в инвентаре. Или Вы хотите дать персонажу "склад", где он будет коллекционировать удачные находки?
Немного не так, предположим, в живом мире шатается тыща персонажей и на каждого напялено по 5 вещей.

Wolsh
30.03.2012, 00:52
И ваш персонаж сразу со всей этой тыщей взаимодействует? Или таки можно сгенерировать детали врага и его лут только когда он попадает в область взаимодействия (принцип LOD)? Или Вы на реальный "живой мир" замахиваетесь?)) В котором тыща персонажей не просто где-то есть, а еще и живет своей жизнью, охотится, сражается друг с другом, обменивается лутом? Тогда другую платформу выбирайте. Ни в одной игре такого нет, даже в Сталкере используется LOD "живого" мира. А если речь о MMORPG, то это заботы сервера, а не флэш.

PlutDem
30.03.2012, 01:02
В котором тыща персонажей не просто где-то есть, а еще и живет своей жизнью, охотится, сражается друг с другом, обменивается лутом? Тогда другую платформу выбирайте. Ни в одной игре такого нет, даже в Сталкере используется LOD "живого" мира.
Ближайший аналог - Космические Рейнджеры 1/2. Живой мир, в космосе летает около 200 кораблей с 12 слотами, в которых установлено уникальное по своим характеристикам оборудование+ планеты в магазинах которых продается оборудование. Всего одновременно в мире находится около 3500 уникальных вещей.

Wolsh
30.03.2012, 01:10
Да не находятся они в мире. Хранятся себе в сейве и считываются оттуда когда на экран попадают.

PlutDem
30.03.2012, 01:20
Хранятся себе в сейве и считываются оттуда когда на экран попадают.
Вы о чем? Никак не могу увязать вместе сейв и попадание на экран.
Да не находятся они в мире.
Поверьте человеку который в это играл:) Летают по системам, торгуют, сражаются.

TanaTiX
30.03.2012, 01:28
"Ты видишь суслика? Нет. А он есть." (с)
Так и тут. Wolsh все правильно объясняет, не сопротивляйся, а прислушайся.
Нет смысла одновременно обрабатывать 8000 объектов.

PlutDem
30.03.2012, 01:34
TanaTiX Так про одновременную обработку объектов ни кто и не говорит! Вся проблема в занимаемой ими памяти.

TanaTiX
30.03.2012, 01:49
Я более чем уверен, что если и возникнут проблемы, то они не будут связаны с набором свойств ряда классов.

Wolsh
30.03.2012, 02:07
Настоятельно рекомендую разобраться, что такое LOD. В википедии однобоко написано, применительно только к графике/детализации структур. События игрового мира точно так же подчиняются этому принципу.
Например может быть реализована система, которая просчитывает траектории этих 200 кораблей. Но ей не нужны их свойства, кроме скорости. Допустим происходит событие пересечения траекторий, то есть встреча двух кораблей/армад (неважно). Никому не нужна детализация до уровня убойки и количества патронов каждого типа для каждого орудия каждого корабля. Исход боя может решаться вообще сравнением всего двух характеристик.Вся проблема в занимаемой ими памяти.Еще раз говорю. Они занимают память на жестком диске. Нафига им быть в оперативке, если их никто не обрабатывает? Когда их характеристики становятся нужны, они извлекаются из сейва.
Я надеюсь мы говорим о синглплеере вообще?

PlutDem
30.03.2012, 03:47
Wolsh
Вы предлагаете держать все характеристики предмета в файле, а при необходимости вытаскивать их? Разве доступ к файлу не очень-очень медленная операция?

artcraft
30.03.2012, 05:20
возьмём в качестве примера wow на каждом сервере играет несколько тысяч человек,
у каждого при этом есть сотри предметов,
всего в игре сотни тысяч разных предметов, способностей, бафов, дебафов, мобов
однако ничего не виснет

дело в том что пока игрок не попал в поле зрения - информации о нём нету
как только попал, в память загружается информация которая необходима для отображения
если выделить игрока и осмотреть, то загружается еще больше информации,
ну и само собой всё ненужное выгружается

PlutDem
30.03.2012, 12:05
artcraft
А если пример с синглплеером? Не, я понимаю что не стоит хранить в памяти все текстуры какие есть на случай если они вдруг понадобятся, но информация о характеристиках предмета все же будет использоваться довольно часто. Ладно еще если просто считывать значения, так, а если скажем, предмет удалят, то придется перезаписывать файл с инфой по предметам, то есть по сути осуществлять сохранение каждую 2-5 сек (Даже не важно как часто, сохранение штука медленная и у игрока будут время от времени фризы, что уже плохо).

strangedk
30.03.2012, 12:44
PlutDem, у меня банальная 2D игра есть, вид сбоку.

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

Один "кусок" представляет собой MovieClip с графикой, сенсорами для Box2D, и еще многими данными.

По началу очень даже ничего, когда этих кусков было ну 10-20, а когда заказчик захотел уровень длиной в 160 "кусков" то сразу на голову свалились проблемы, ибо хранить сразу 160 instance в памяти оказалось просто нереально, и для спрайта, и для Box2D.

В итоге было принято решение подгружать уровень динамически.

Прикрепляю тестовую флешку, которую я делал, разрабатывая этот алгоритм.
http://megaswf.com/serve/2310911

Добавлено через 4 минуты
если кому нужны исходники, стучитесь в личку

Wolsh
30.03.2012, 14:33
PlutDem, далеко не все (есть подозрение что никто) из здесь присутствующих играли в этих рейнджеров. Может Вы потрудитесь описать Ваш проект. Хорошо бы также поподробней объяснить, то за тысячи предметов/персонажей Вы собираетесь обрабатывать/хранить в памяти. Без этих объяснений Ваши представления (как они сейчас озвучены) выглядят крайне наивно и советовать что-то на их фоне бессмысленное занятие. Тем более что советов Вы не слушаете, с уровнями детализации даже не пытались разобраться и упрямо представляете игру как огромную вселенную с постоянной и равномерной плотностью объектов и событий. Разговор тупо топчется на месте. Начните двигаться. Выпейте кофе и перечитайте топик.

strangedk
30.03.2012, 15:40
Автор вопроса: Вот не хочется же минусы вам ставить, но такое чувство, что вы вопрос задали только для того, чтобы подтвердить свою точку зрения.

Изголяешься тут, ссылки прикрепляешь, пишешь, советуешь, проекты старые поднимаешь, чтобы помочь вам. А благодарности ноль, одни оспаривания.
Хоть бы прислушались к чему-то

Я понимаю что фактически копирую предыдущее сообщение, но не мог не выразить личные мысли

Wolsh
30.03.2012, 17:58
Можно, скажем, при расчете урона, наносимого персонажу, пройтись по всем слотам под вещи и проверить есть ли у вещей бонусы на защиту, если есть, то использовать их при расчете урона. Но этот способ очень ресурсоемок.Для пяти слотов-то? Не, не страшно. Не страшнее ваших тысяч персонажей.
Потом, я не знаю как Вы представляете себе бой. Это может быть состояние, управляемое неким классом Fight. Ничто не мешает отдать ему один раз все бортовые параметры участников, и пусть он считает бафы, демэджи и резисты на протяжении боя, не дергая каждый раз непосредственно экземпляры участников.

maxkar
30.03.2012, 20:21
Всего одновременно в мире находится около 3500 уникальных вещей.
Ну и? Пусть у каждой вещи 10 характеристик типа int. Это все займет (3500 * 10 * 4) = (150 000). Это 150 килобайт всего. Это как раз без изобретения отдельных "свойств", с отдельными "свойствами" памяти будет больше потребляться. Как будто 150Кб - это много. У вас несколько распакованных картинок столько памяти займут...

И это при том, что инвентарь чужой можно и не хранить. LOD здесь прекрасно действует. При попадании рейнджера в область видимости на основании его рассы/класса/уровня ему можно примерно сгенерировать инвентарь. И вы никак не отличите сегнерированный инвентать от "наторгованного". А уж магазины на планетах точно генерируют инвентарь при посещении (возможно - при посещении звездной системы).

Den_root
31.03.2012, 17:37
"Вы ему про Фому,а он вам про Ерёму! Топикстартер видимо хочет реальный живой мир где характеристики сущностей случайно не генерируются когда попадают в зону влияния, а вы ему LOD предлагаете. В тех же КР2 корабли случайно генерируются на планетах вместе с оборудованием и дальше уже летают по вселенной и наличие поблизости игрока на них никак не влияет. Кстати оборудование в магазинах генерируется случайно, но не во время посещения игроком планеты, а каждый игровой цикл и реально присутствует на планете.

Кстати, господин Wolsh дал очень точное определение:
...представляете игру как огромную вселенную с постоянной и равномерной плотностью объектов и событий. ...
В КР2 на другом конце галактики, на планете появляется случайно сгенерированный пират, вылетает и сбивает торговца, летящего продавать купленный в соседней системе товар. Пират может заменить свое оборудование на оборудование торговца если оно выпало во время его уничтожения, может собрать товар и продать его на планете и т.п. В этом и была вся фишка, игрок живет по тем же законам, что и все в этом мире и если игрока убрать мир продолжит существовать.

PlutDem
В КР2 была очень простая механика и никакой физики, да к тому же пошаговая. Если Ваш проект с физикой и в реальном времени, то придется удаленный бой просчитывать приблизительно т.е.:
Исход боя может решаться вообще сравнением всего двух характеристик.
Это практикуется в космосиме серии X3:Reunion, правда там эти приблизительные расчеты часто врут и из за этого не так интересно как в КР2.
Но в любом случае тысячи кораблей AS3 не потянет, можно конечно сделать несколько сотен и в случае если проект выстрелит портировать уже на другую платформу.

Wolsh
31.03.2012, 21:49
Топикстартер видимо хочет реальный живой мир где характеристики сущностей случайно не генерируются когда попадают в зону влиянияА мы вот все о том, что это абсолютно бессмысленно, занимать память нестреляющими ружьями.
Я ни одной игры кроме пятнашек и паззла в жизни не написал, так что все что я говорю можно смело делить на 16. Я обычной логикой оперирую.
Если нет суслика, пофиг сколько у него зубов и какого оттенка шкурка.
Как я вижу процесс:
При запуске игры с жесткого диска считывается последнее сохранение и создается временный (возможно, "распакованный", сейв, с которым игра общается пока юзер не выберет в меню "сохранить" (старыйй сейв естественно не подлежит модификации в процессе игры, он для истории): в случае этих ваших КР берем из сейва координаты и векторы кораблей, включаем жизнь, полетели. Никакие ништяки в слотах кораблей нас не интересуют в это время, и считывать их из сейва нет никакой необходимости.
Событие – два корабля встретились. Берем из сейва их характеристики. Если корабли дружественные, запускаем процесс торговли, если враждебные – процесс битвы. Торговля это передача от одного корабля другому случайной части ништяков на сумму не больше 75% от количества денег второй стороны. Можно усложнять интеллект как угодно в разумных пределах, делать списки приоритетов из необходимостей (скажем если у одного мало топлива то он обязательно покупает топливо, и немного зубного порошка прицепом) – я не думаю что такие события будут происходить по 10 штук на кадр, иначе самым расхожим товаром будет краска для обшивки кораблей.
Поторговали, записали новые состояния слотов в сейв, очистили от них память и полетели дальше.
Аналогично с битвой. Никто же не требует от интеллекта игры реального сражения (если конечно ГГ не является его свидетелем). Сравнили боевую мощь, разбавили случайностью, сгенерировали списки повреждений и затрат боеприпасов, записали в сейв и разлетелись; либо поверженный корабль захвачен, часть груза в соответствии с приоритетами и грузоподъемностью судна победителей отобрана у побежденных, записали слоты в сейв и разлетелись.
И как уже несколько раз сказали, все эти слоты, о которых был изначальный вопрос – ничто по ресурсам в сравнении с графикой и логикой. Но вам всеравно придется делать LOD для графики, таскать картинки кораблей, которые никто не видит – это же жесть вообще. А они ведь такие же свойства. Вам придется разграничивать свойства, необходимые для простого интеллекта "оно где-то там летает", от свойств "о боже, оно летит прямо на меня!"

PlutDem
01.04.2012, 00:08
При запуске игры с жесткого диска считывается последнее сохранение и создается временный (возможно, "распакованный", сейв, с которым игра общается Вот отсюда можно поподробнее? Что из себя представляет сейв? Shared Object? Что имеется в виду под "распакованный"?

Wolsh
01.04.2012, 00:29
Shared Object конечно, ФП другого не умеет.
"Распакованный" значит, что сохранение на жестком диске может храниться в сжатом виде, а для общения в процессе игры можно создать развернутую структурированную копию, более удобную для доступа к частям сейва. Можно создать полсотни отдельных SO "по темам". По окончании игры их можно просто удалить. При нормальном новом сохранении игры (от юзера) на их основе создается новый сейв, сжимается и сохраняется в один SO, имя и дата которого регистрируются в "самом главном SO" – списке всех сейвов. Когда игра запускается и игрок выбирает "загрузить", игра обращается к этому главному списку и предоставляет игроку список сейвов с именами, датами, может еще какими данными, хоть картинками)) Игрок выбирает, какое сохранение он хочет загрузить, игра обращается к этому сейву по имени из списка, распаковывает его во временные SO и формирует мир.

Добавлено через 9 минут
вот как-то выдумывал (https://docs.google.com/drawings/d/1J7jKIAmu22sZHfGuILD5obObw5gH9lI_NRRO2LrOBBc/edit)

PlutDem
09.04.2012, 22:35
Кажется, я все таки нашел способ снизить потребляемую предметами память! В базовом классе Item прописываем геттеры на все возможные характеристики, а через декоратор добавляем нужные бонусы и храним их значения в свойствах. Таким образом предмет хранит в себе только те свойства характеристик к которым есть бонус, а на все остальное возвращает ноль. К сожалению, не знаю как измерить занимаемую всей этой конструкцией память, но наверняка это лучше чем 25 элементный массив.
public class Main extends Sprite {

public function Main():void {

var person:Person= new Person(0,10,5)

var hat:IItem = new Item("Magic hat");
hat = new StrenghtUpgrade(hat, 58);
hat = new DexterityUpgrade(hat, 15);

person.wearItem(hat);

}

}public class Person extends Sprite{

public var strength:int;
public var dexterity:int;
public var stamina:int;

public function Person(strength:int,dexterity:int,stamina:int) {

this.strength = strength;
this.dexterity = dexterity;
this.stamina = stamina;
}
public function wearItem(item:IItem):void {
this.strength+=item.strength;
this.dexterity+=item.dexterity;
this.stamina+=item.stamina;
}
}public interface ISkills {

function get strength():int;
function get dexterity():int;
function get stamina():int;

}public interface IItem extends ISkills{

function get name():String;
}public class Item implements IItem{

protected var _name:String;

public function Item(name:String){
this._name = name;
}

public function get strength():int {
return 0;
}
public function get dexterity():int {
return 0;
}
public function get stamina():int {
return 0;
}
public function get name():String {
return _name;
}
}public class ItemDecorator implements IItem{

protected var _item:IItem;

public function ItemDecorator(item:IItem){

this._item = item;
}

public function get strength():int {

return _item.strength;
}

public function get dexterity():int {

return _item.dexterity;
}

public function get stamina():int {

return _item.stamina;
}

public function get name():String {

return _item.name;
}
}public class StrenghtUpgrade extends ItemDecorator{

protected var _strength:int;

public function StrenghtUpgrade(item:IItem,value:int) {
super(item);
this._strength = value;
}
override public function get strength():int {
return super.strength + this._strength;
}
}
Правда если захотеть 2 раза проапгрейдить вещь на один и тот же бонус, то в результате будут храниться два свойства на каждый апгрейд, но думаю это можно как нибудь решить.

alatar
09.04.2012, 23:11
getSize (http://help.adobe.com/ru_RU/FlashPlatform/reference/actionscript/3/flash/sampler/package.html#getSize()).

PlutDem
09.04.2012, 23:26
alatar
getSize измерит сам объект но, проигнорирует свойства имеющие ссылки на другие объекты, т.е. скажем, getSize измерит размер массива, но не учтет содержимое его ячеек. Хотелось бы что то более надежное и комплексное. Вроде можно измерить с помощью Sampler, но в справке как то все мутно расписано.

Wolsh
09.04.2012, 23:42
Мне вот до сих пор непонятна одна тема в Декораторе. Стыдно, да, но почему-то все описания паттерна молчат об этом.
Вот декорировал ты себя шапкой +50 к мане.
А как теперь эту шапку снять? Особенно если потом еще сапоги нацепил.
А еще круче – хлебнул ты Зелье Силы и стамина подскочила на 75 децелов. Но действует только 1 минуту. И что делать с этим декоратором через минуту? Как от него избавиться?
Поясните кто-нибудь пожалуйста.

PlutDem
09.04.2012, 23:50
Wolsh

(персонаж)
( (персонаж) +50 стамины )// надел шапку
( ( (персонаж) +50 стамины ) -50 стамины)// снял шапку
:) Тоже этот вопрос интересует.
P.S. Если это камень в мой эээ... код, то у меня декоратор используется только для создания шмота.

Wolsh
09.04.2012, 23:55
Не не, по Вашему коду персонаж то не декорируется, он именно "применяет шапку", а не "становится шапкой".
По Вашему коду мой вопрос скорее касается самой шапки. Как с нее "снять" зачарование, убрать один из декораторов.

но думаю это можно как нибудь решить.
override public function get strength():int {
return item.strength + this._strength;
}
? ;)

Добавлено через 19 минут
Если хотите камней, то их есть у меня.
Шапка hat это экземпляр Item, так?
У Item есть свойства strength, stamina и т.д.?
Вопрос – чем ваше декорирование лучше прямой установки?
var hat:IItem = new Item("Magic hat");
hat.stamina += 50;

alatar
10.04.2012, 00:26
Но действует только 1 минуту. И что делать с этим декоратором через минуту? Как от него избавиться?
Ну как нацепил так и снял. Декоратор не должен менять свойства объекта, он просто возвращает базовое
значение + бонус.
PlutDem, возьмите уже наконец любой профайлер и посмотрите сколько ресурсов потребляет ваше приложение.

Wolsh
10.04.2012, 00:36
Вот мне и непонятно. Технически.
Нацепил-то я вот так
var hat:IItem = new Item("Magic hat");
hat = new StrenghtUpgrade(hat, 58);
hat = new DexterityUpgrade(hat, 15);
Как теперь "снять" например StrenghtUpgrade и оставить DexterityUpgrade?

PlutDem
10.04.2012, 00:43
По Вашему коду мой вопрос скорее касается самой шапки. Как с нее "снять" зачарование, убрать один из декораторов.

Я могу предложить только быдло-способ, загасить эффект ненужного декоратора другим декоратором либо создать новый объект с текущими декораторами кроме ненужного.
override public function get strength():int {
return item.strength + this._strength;
}
? ;)

Посмотрите внимательнее на декоратор. У каждого из них есть свойство для хранения значения прибавляемого бонуса. Т. е. если применить к вещи 2 декоратора силы +5 и +10, то в памяти будут хранится эти два свойства со значениями 5 и 10. Если увлечься такими апгрейдами, то в конце концов объект вещи разжиреет.

Если хотите камней, то их есть у меня.
Шапка hat это экземпляр Item, так?
У Item есть свойства strength, stamina и т.д.?
Вопрос – чем ваше декорирование лучше прямой установки?
var hat:IItem = new Item("Magic hat");
hat.stamina += 50;
У Item нет свойств, только геттеры. Свойство для хранения значения бонуса добавляет декоратор, в этом то вся и фишка. Если правильно понимаю, то во эта конструкция будет существовать в единственном экземпляре для всех объектов класса.public function get armor():int {
return 12;
}
P.S. Вопрос про измерение памяти все еще в силе, если эта белиберда сэкономит 5% памяти, то ну его нафиг.:)

Wolsh
10.04.2012, 01:09
(да, проглядел, что Вы возвращаете константы, не храня их в переменных)
Если увлечься такими апгрейдами, то в конце концов объект вещи разжиреет.
в этом то вся и фишка.15 наслоений полного комплекта углубляющихся геттеров легче одной переменной?
Ведь для изменения одного (не побоюсь этого слова) свойства декоратором Вам надо нагрузить предмет полным комплектом всех геттеров, цепляющихся к прошлым геттерам.
Вы так рассчитываете сэкономить память и увеличить быстродействие?
Вопрос "чем ваше декорирование лучше прямой установки?" всё ещё в силе. Ответа не было.

PlutDem
10.04.2012, 02:02
15 наслоений полного комплекта углубляющихся геттеров легче одной переменной?
Ведь для изменения одного (не побоюсь этого слова) свойства декоратором Вам надо нагрузить предмет полным комплектом всех геттеров, цепляющихся к прошлым геттерам.
Вы так рассчитываете сэкономить память и увеличить быстродействие?
Вопрос "чем ваше декорирование лучше прямой установки?" всё ещё в силе. Ответа не было.
У большинства вещей по 2-3 бонуса к характеристикам. Держать в объекте 2-3 свойства лучше чем все 25. В среднем около 3-5 наслоений.

В любом случае, метод себя оправдал на жалких 10%:)
Проще держать в вещи все возможные свойства. К тому же от их количества зависит далеко не многое.
public class Main extends Sprite {

public function Main():void {

var items:Array = new Array();
for (var i:int = 0; i < 200000; i++) {
items[i] = new TestItem;
}

}

}public class TestItem {

public var testSkills:TestSkils = new TestSkils();
public function TestItem() {

}

}public class TestSkils {

public var ar_1:int =2;
public var ar_2:int =2;
public var ar_3:int =2;
public var ar_4:int =2;
public var ar_5:int =2;
public var ar_6:int =2;
public var ar_7:int =2;
public var ar_8:int =2;
public var ar_9:int =2;
public var ar_10:int =2;
public var ar_11:int =2;
public var ar_12:int =2;
public var ar_13:int =2;
public var ar_14:int =2;
public var ar_15:int =2;
public var ar_16:int =2;
public var ar_17:int =2;
public var ar_18:int =2;
public var ar_19:int =2;
public var ar_20:int =2;
public var ar_21:int =2;
public var ar_22:int =2;
public var ar_23:int =2;
public var ar_24:int =2;

public function TestSkils() {
}

}
Всего потребляемой памяти: 9 256 Kb.
Если в TestSkils убрать все свойства кроме 3, то всего потребляемой памяти будет 8 776 Kb.
А если сделать так, то всего потребляемой памяти будет 4 624 Kb.public class Main extends Sprite {

public function Main():void {

var items:Array = new Array();
for (var i:int = 0; i < 200000; i++) {
items[i] = 12;
}

}

}
В общем, занимаюсь экономией на спичках:D

Wolsh
10.04.2012, 03:18
)) Вам это всю тему твердят. Рад что нашли способ убедиться.

alatar
10.04.2012, 12:04
Вот мне и непонятно. Технически.
Нацепил-то я вот так
var hat:IItem = new Item("Magic hat");
hat = new StrenghtUpgrade(hat, 58);
hat = new DexterityUpgrade(hat, 15);
Как теперь "снять" например StrenghtUpgrade и оставить DexterityUpgrade?
Это как удалить элемент в однонаправленном списке. В видео декораторы используются для апгрейдов, они в принципе не снимаемые. Нужна реализация с доступом к декорируемому объекту.

Wolsh
10.04.2012, 12:24
Ага, но не о видео речь. Я не нашел (может проглядел) этого ни у GOF, ни в книге по паттернам в AS3.0
И мне всегда это казалось странным. Как в данной ситуации – ну нацеплять декораторов на шапку навсегда еще куда ни шло. Но если декорировать перса, то нужен этот самый доступ к списку декораторов, что ли, чтобы вытаскивать экземпляр "до" и навешивать на него заново все что "после" удаляемого декоратора. То есть сама по себе красивая идея превращается в кошмар программиста. Ну, программиста моего уровня по крайней мере))))
А насчет чем мне видео помогло – в нем показан декоратор на интерфейсах. А в книге по паттернам AS3 рассматривается декоратор на наследовании, и меня всегда ужасало, что каждый декоратор вынужден наследовать фактически декорируемый класс)))) Только после видео я въехал, что речь о "пустом" абстрактном суперклассе. И всеравно на интерфейсах мне как-то комфортней и понятней. За это прозрение и спасибо))

alatar
10.04.2012, 12:37
Да нет там никакого кошмара, одна функция (рекурсивная или с циклом) в которой ищется объект (A) у которого есть ссылка на удаляемый объект (B). У удаляемого объекта берем ссылку на объект (C) который он декорирует. Потом у B зануляем ссылку на C и вставляем ссылку на C в A. Все.

gloomyBrain
10.04.2012, 12:58
Что-то мне кажется что вариант с декоратором - не вариант. Я бы сделал что-то на подобие фильтров. Принципиальная разница в том, что не вот так:

var hero:IHero = new Hero();
hero = new Hat(hero);
hero = new Sword(hero);


а вот так:

var hero:Hero = new Hero();
hero.addBonus("hat boost", new Hat(10));
hero.addBonus("sword boost", new Sword(-3));

...

hero.removeBonus("sword boost")

Во втором варианте не нужен поиск при удалении.

Хотя, сделать ссылки у самих фильтров типа next-prev тоже можно, если результат применения фильтров зависит от порядка.
Короче да, кроме оптимизации поиска нужного декоратора я к предложению alatar'а ничего не могу добавить =)

Wolsh
11.04.2012, 13:10
Да нет там никакого кошмара, одна функция (рекурсивная или с циклом) в которой ищется объект (A) у которого есть ссылка на удаляемый объект (B). У удаляемого объекта берем ссылку на объект (C) который он декорирует. Потом у B зануляем ссылку на C и вставляем ссылку на C в A. Все.Спасибо, получилось)))
Единственно, напрягает необходимость реализации в классе самого итема (который должен поддерживать тот же интерфейс, что и декоратор) геттера и сеттера item))
Декоратору то они нужны для реализации цепочки, но самим шапкам и штанам, пока их не декорировали, они ж совсем без надобности, и вносят некоторую сумятицу.

alatar
11.04.2012, 13:14
Можно вынести в отдельный интерфейс для декораторов. Тогда шапки и штаны останутся чистенькими :)

Wolsh
11.04.2012, 13:25
gloomyBrain, сделать-то конечно можно по-разному. Автор в начале темы тоже вполне рабочий вариант предлагал. Но меня интересовал скорее теоретический вопрос про сферический Декоратор в вакууме, а не применительно к данной задаче. Но получилось что и к данной задаче он вполне подходит. Хотя я по-прежнему считаю что сэкономить память он не поможет. Как бы цели слегка не те у паттернов. Они же для облегчения разработки, а не веса экземпляров)). Ну да, когда система отлажена, создание самих декораторов элегантно и прозрачно. Не совсем понятно, стоит ли разворачивать такую систему для трех-четырех бонусов. А если их будет 40, то и с каждым новым декоратором будет наслаиваться 40 новых геттеров-ретрансляторов ради изменения одного свойства((.

Добавлено через 2 часа 6 минут
Можно вынести в отдельный интерфейс для декораторов. Тогда шапки и штаны останутся чистенькими :)Блин, я тупица! Я так и пытался, но не в ту сторону делал наследование интерфейсов)) Теперь все получилось идеально: только декоратор реализует IDecoratorsChain (который наследует IEnchantable, а не наоборот))), и его сеттер и геттер item имеет тип IDecoratorsChain. Шапкам и штанам оно действительно не потребовалось))
Большое спасибо, alatar!

Wolsh
13.04.2012, 00:29
Решил выложить пример, вдруг кому пригодится.
Также, если будут замечания и поправки, прошу поделиться.

Опирался на концепцию The Elder Scrolls IV : Oblivion.
Одежда (и доспехи) может быть зачарована на бонусы к
1) статам (например кол-во магии, выносливости или здоровья),
2) навыкам (например, уровень владения мечом или определенной школой магии)
3) резистам (например, сопротивление огню),
а также на особые постоянные способности, не выражаемые числами (например, дыхание под водой или ночное зрение).
В отличие от одежды, оружие может быть зачаровано только на бонусы к атаке, а точнее только заклинаниями, действующими "на цель".
Таким образом хотя и оружие и одежда являются наследниками класса Предмет и могут быть зачарованы, сами виды бонусов-зачарований совершенно разные, и требуют отдельных линеек декораторов. В примере показан только декоратор для одежды. Оружие должно реализовывать другой интерфейс и подключать другой класс декораторов.