Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   проверьте, пожалуйста, пул (http://www.flasher.ru/forum/showthread.php?t=212578)

a7s1h1 17.03.2016 11:01

проверьте, пожалуйста, пул
 
Здравствуйте!
Я наконец-то созрел для применения объектного пула. Проверьте, пожалуйста, пул ли у меня получился вообще и если да, правильно ли всё сделал?

Итак, есть объект "блок", вот его класс:
Код AS3:

package Objects  {
        import animation.AntActor;
        import flash.display.Sprite;
        import flash.events.Event;
        import rc.MyMath;
        import rc.TF;
        //@author 7_11
 
        public class Block extends Sprite {
 
                private var _img:AntActor
                private var _tree:AntActor;
                private var _text:TF;
 
                public var type:uint; // тип блока
 
                // CONSTRUCTOR
                public function Block() {
                        _img = new AntActor(); // картинка блока
                        _img.addAnimFromCache('Block_s') // присваивает изображение
                        addChild(_img) //добавляем картинку
                        // текстовое поле
                        _text = new TF(40, 40, '' + type, 12 + type * 3, 'center', 0xffffff);
                        addChild(_text);
 
                        // ни объект, ни его дети не взаимодействуют с мышью
                        mouseEnabled = false;
                        mouseChildren = false;
 
                        addEventListener(Event.ADDED_TO_STAGE, init); // инициализация
                        addEventListener(Event.REMOVED_FROM_STAGE, reset); // обнуление параметров при удалении со сцены
                };
 
                //INIT
                private function init(e:Event): void {
                        // c вероятностью 15% создаём деревце
                        if (MyMath.randomRange(0, 100) < 15) {
                                _tree = new AntActor();
                                _tree.addAnimFromCache('Tree_s');
                                _tree.x = 40;
                                addChild(_tree)
                        }
                        // обновляем текст, т.к. мог измениться тип блока (присваивается родителем, поэтому переменная type публичная)
                        _text.update( '' + type);
                }
 
                // ОБНУЛЯЕМ ПАРАМЕТРЫ (при удалении со сцены)
                private function reset(e:Event): void {       
                        // обнуляем параметры
                        type = 0; // тип по умолчанию 0
                        // если есть деревце - удаляем его
                        if (_tree) {
                                _tree.free();
                                //removeChild(_tree); // удалять дерево как ребёнка не нужно, метод free() заставил его удалиться само
                                _tree=null;
                        }
                };
 
                //CLEANUP (окончательная чистка при удалении со сцены родителя)
                public function cleanup(): void {
                        // чистим слушателей
                        removeEventListener(Event.ADDED_TO_STAGE, init);
                        removeEventListener(Event.REMOVED_FROM_STAGE, reset);
                      // чистим акторов
                        _img.free();
                        _tree.free();
                        // удаляем детей
                        removeChildren();
                        // обнуляем ссылки
                        _img = null;
                        _tree = null;
                        _text = null;
                }
        };
};

В классе "world", который является родителем для всего, что находится и происходит в мире игры, есть два массива: с блоками, которые на сцене, и с пулом:
Код AS3:

private var _blocks:Vector.<Block>;         // массив с блоками
private var _blocksPool:Vector.<Block>; // пул с блоками

При инициализации "мира" эти массивы создаются:
Код AS3:

_blocks = new Vector.<Block>();                 // создаём массив блоков
_blocksPool = new Vector.<Block>();        // создаём пул блоков

в кадре проверяются все блоки на сцене и удаляются (переносятся в пул) те, которые оказались за краем. Вот кусок кода с удалением блока:
Код AS3:

...
put_block(b); // суём блок в пул
removeChild(b); // удаляем блок со сцены (при этом срабатывает внутренний метод блока reset() для обнуления параметров, но тех своих детей, которые нужны блоку всегда, он не удаляет)
_blocks.splice(i, 1); // удаляем блок
...

А это кусок кода с добавлением блока из пула на сцену:
Код AS3:

...
var block:Block = get_block();                //берём последний блок из пула (в пуле его удаляем)
// присваиваем блоку координаты и тип
block.x = sx + BlockW * (b + 1);
block.y = GL;
block.type = _waves[wl][b];
// добавляем новый блок в масcив и на сцену
_blocks.push(addChild(block));
...

А это сами методы пула, которые я позаимствовал у Zebestov из вот этой темы:

Код AS3:

// Берём блок из пула
private function get_block():Block {
        // если в пуле есть блоки - берём их оттуда, если нет - создаём
        return (_blocksPool.length) ? (_blocksPool.pop()) : (new Block());
}
 
// Кладём блок в пул
        private function put_block(block:Block):void {
_blocksPool[_blocksPool.length] = block;
}

Ну и наконец, чистка вектора и пула блоков при удалении со сцены класса "мира":
Код AS3:

// чистим массивы
var bl:int = _blocks.length;
for (var bi:uint = 0; bi < bl; bi++ ) { _blocks[bi].cleanup() };
_blocks.splice(0, _blocks.length);
var bpl:int = _blocksPool.length;
for (var bpi:uint = 0; bpi < bpl; bpi++ ) { _blocksPool[bpi].cleanup() };
_blocksPool.splice(0, _blocksPool.length);
_blocks = null;
_blocksPool = null;

Подскажите, пожалуйста, верно ли я понял принцип пула и насколько удачно его реализовал? (на глаз работает так же, как при создании-удалении экземпляров).

КорДум 17.03.2016 14:12

А зачем плодить темы? Писали бы в той своей, так как эта имеет к первой непосредственное отношение.

1. пул должен быть выделен в отдельный класс, его методы должны быть инкапсулированы. Это отдельная логика, она должна выставлять наружу только методы управления собой, такие как "взять", "удалить" и еще что-то по вкусу.

2. вызов метода reset я бы сделал руками в логике пула и убрал подписку на removeFromStage. Равно как и init. В текущей реализации хендлер addedToStage вообще не нужен, его можно сделать публичным и дернуть в нужный момент (но это нужно смотреть по общей архитектуре и логике приложения)

3. почитайте про конвенции именования методов (get_block не является правильным именем).

4. посмотрите на свои комментарии, они бессмысленны. Комментарий не должен отвечать на вопрос "что?", он должен отвечать на вопрос "почему?" в большинстве случаев.

Цитата:

return (_blocksPool.length) ? (_blocksPool.pop()) : (new Block());
Все скобки вокруг операндов лишние.

a7s1h1 17.03.2016 16:34

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

Цитата:

Сообщение от КорДум (Сообщение 1192713)
посмотрите на свои комментарии, они бессмысленны.

Позвольте с вами не согласиться. Полагаю, что бессмысленными они кажутся вам из-за того, что ваш уровень владения AS3.0 делает их очевидными. Я же, находясь в процессе созидательного обучения, леплю комментарии где только можно, чтобы лучше запомнить, где что находится и как всё работает.

Цитата:

Сообщение от КорДум (Сообщение 1192713)
Все скобки вокруг операндов лишние.

Это как-то влияет на процесс выполнения кода или просто эстетический момент? Просто так ведь проще группировать условия. Например, если у нас два условия (простых, которые незачем расписывать через if-else), то можно написать
Код AS3:

var a:uint = (b > 3)?((b > 6)?(2):(1)):(0)

, а как это будет выглядеть без скобок, я даже представить не могу.

Wolsh 17.03.2016 17:53

От того, что всё в скобках, легче не становится. Оставьте одни, если так Вам проще.
Код AS3:

var a:uint = b > 3 ? (b > 6 ? 2 : 1) : 0;


undefined 17.03.2016 18:23

имхо ифом будет много понятнее.

a7s1h1 17.03.2016 18:34

Простите, скобочки, мы с вами так долго были вместе, но теперь придётся расстаться. Ничего личного, просто без вас реально лучше. Постараюсь поскорее от вас отвыкнуть:bye:

Добавлено через 2 минуты
Цитата:

Сообщение от undefined (Сообщение 1192731)
имхо ифом будет много понятнее.

разумеется

Zebestov 17.03.2016 19:23

Цитата:

Сообщение от КорДум (Сообщение 1192713)
пул должен быть выделен в отдельный класс, его методы должны быть инкапсулированы

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

КорДум 17.03.2016 20:23

Бестыч, я ничего против ленивого пула не имею :)
Хочется показать новичку, что пул — обособленная логическая связующая сущность, ее нужно выделить в отдельный класс и пользоваться экземпляром. Так будет меньше кода в основном классе, плюс уйдут в инкапсуляцию "лишние" ссылки на массивы.

Да, скобочки несут только эстетическую пользу в данном случае.

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

Цитата:

var a:uint = b > 3 ? (b > 6 ? 2 : 1) : 0;
Даже в этом облегченном от скобок варианте я не могу в течение первой-двух секунд понять логическую нагрузку этого кода.

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

И еще заметил только сейчас:
Цитата:

for (var bpi:uint = 0; bpi < bpl; bpi++ ) { _blocksPool[bpi].cleanup() };
Вновь неоправданная экономия строк. И ни о чем не говорящие переменные с именами bpi и bpl. Да, я могу вернуться по коду выше и посмотреть, что вроде как они переводятся block panel index и length соответственно. Но я должен возвращаться обратно для этого. И любой другой, посмотрев этот код, начнет его изучение с рефакторинга таких мест. Чтобы в дальнейшем, если он вернется к этому куску кода, больше не чесал репу и не разберался, что за bpi.
А и да, эта конструкция заменятся на for-each цикл.

dimarik 17.03.2016 20:29

Из явно зацепивших мой взгляд могу выделить пару моментов.
Я бы не стал делать того, что происходит в
Код AS3:

// ОБНУЛЯЕМ ПАРАМЕТРЫ (при удалении со сцены)
function reset(e:Event){}

Мне так кажется, что процедура удаления и добавления на сцену никак не связана с помещением в пул или извлечением этого объекта из него соответственно. Операции с дисплейлистом часто требуют добавления или удаление одного и того же объекта, ожидая, что с ним ничего не случится при этих операциях. Однако, вы заставляете себя писать код, который фактически заново должен будет проинициализировать ваше дите, единожды уже побывавшее в дисплейлисте. Ваш type исчезает после удаления экземпляра Block со сцены. Вот если бы кто-то решал, что этот экземпляр действительно не нужен, то можно как раз применить метод clean (его именуют dispose обычно) и отправлять объект в пул.
Пул для одного типа объектов считаю рациональным объявлять в самом классе объекта.

a7s1h1 17.03.2016 21:32

большое спасибо всем! Что смог - исправил сразу по вашим советам, над остальным работаю)


Часовой пояс GMT +4, время: 01:02.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.