Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Глобальный Enter Frame (http://www.flasher.ru/forum/showthread.php?t=194112)

Sintesis 08.02.2013 02:19

Глобальный Enter Frame
 
Как лучше реализовать ентерфрейм, чтоб была возможность добавлять функции в которых есть анимация. Сделал так, но мне кажется это медленно:
Код AS3:

package resources{
        import flash.events.Event;
 
        /**
        * ...
        * @author Sintesis
        */

        public class MyTween{
 
                private var _myFuncVector:Vector.<Function>;
                private var _funcCount:int = 0;
                private var _oldFuncCount:int = 0;
 
                public function MyTween(){
                        _myFuncVector = new Vector.<Function>;
                }
 
                public function startTimer():void {
                        Dispatcher._stage.addEventListener(Event.ENTER_FRAME, timerListener);
                }
 
                public function stopTimer():void {
                        Dispatcher._stage.removeEventListener(Event.ENTER_FRAME, timerListener);
                }
 
                public function setFunc(func:Function):void {
                        _myFuncVector.push(func);
                        _funcCount = _myFuncVector.length;
                    _oldFuncCount = _myFuncVector.length;
                }
 
                private function timerListener(event:Event):void {
//не нравится, что каждый кадр перебираю вектор _myFuncVector
                        while (_funcCount--) {
                                _myFuncVector[_funcCount]();
                        }
                        _funcCount = _oldFuncCount;
                }
        }
}

может есть лучшие решения?

-De- 08.02.2013 02:26

Да вроде нормально. Именно перебор сильно не улучшить. Можно for .. in попробовать, можно сделать список вместо вектора (как бонус вставка/удаление быстрее), но до 1000 длины вектора нереально разницу увидеть. Можно написать функцию удаления - это даст повод подумать над Dictionary вместо или вместе с вектором.

Sintesis 08.02.2013 02:35

Цитата:

Сообщение от -De- (Сообщение 1119677)
Именно перебор сильно не улучшить.

Печально. Но может есть какой-то другой подход добавления/удаления в анимацию, без создания таймеров или ентерфрейма каждому отдельному анимируемому объекту?

Frost47rus 08.02.2013 12:02

каждую анимацию имплементить от интерфейса с function Tick():void;, например.
создание анимации проводить в какой-нибудь AnimationSystem, которая будет получать игровой Tick от игрового мира World, скажем. Собирать анимации в Vector.<Animation>();
Код AS3:

public function Tick(dt:Number):void{
 var i:int;
 for (i=0; i< animations.length; i++){
  animations[i].Tick();
 }
}


Sintesis 08.02.2013 17:33

А вот это всё каждый фрейм происходит?
Код AS3:

public function Tick(dt:Number):void{
 var i:int;
 for (i=0; i< animations.length; i++){
  animations[i].Tick();
 }
}


expl 08.02.2013 17:49

Цитата:

//не нравится, что каждый кадр перебираю вектор _myFuncVector
Вы в каждом кадре должны вызвать все функции (так же?)
А сам перебор (сравнение i <, инкремент i++, обращение к элементу массива) - ни как не больше времени и памяти жрёт чем непосредственный вызов всех функции Tick()
Т.е. это не место для оптимизаций.

Где место для оптимизаций? Это удаление функции могло бы быть, но у Вас просто нет такого метода :)

Цитата:

while (_funcCount--) {
_myFuncVector[_funcCount]();
}
_funcCount = _oldFuncCount;
Зачем так сложно? _Если_ не предпологается удаление функций, то не нужно поля использовать (да и если бы предполагалось - можно было бы переменными обойтись):
Код AS3:

for each (var fun:Function in _myFuncVector)
{
    fun();
}


Sintesis 08.02.2013 18:45

Цитата:

Сообщение от expl (Сообщение 1119774)
Вы в каждом кадре должны вызвать все функции (так же?)

Зачем так сложно?
Код AS3:

for each (var fun:Function in _myFuncVector)
{
    fun();
}


Да! Спасибо expl, совсем забыл про for each так красивей). Удаление функций тоже есть, просто не писал сюда, оно нормально работает. Думал, может, связанные списки делать, но оказывается это не такой уж и напряг когда цикл в энтерфрейме постоянно перебирает вектор с функциями.

Добавлено через 8 минут
Интересно, что быстрей такой подход как Frost47rus написал где будут через интерфейс дёргаться методы или как у меня с передачей всего метода в ентерфрейм или это совсем не важно что так, что так?

iflamberg 08.02.2013 19:07

Разве for..in не намного медленней, чем другие циклы?

Sintesis 08.02.2013 19:52

так, нужно будет сделать класс который измеряет скорость работы отдельных кусков кода(но это уже другая история), действительно for each ведь медленее while, но используя for each в данном случае стают не нужными private var _funcCount:int = 0; private var _oldFuncCount:int = 0; и все манипуляции с ними отпадают.
В общем-то почти всё что хотел - узнал, так как по любому прийдётся перебирать вектор с анимациями каждый кадр то моё решение удовлетворяет.

expl 08.02.2013 21:11

Цитата:

Удаление функций тоже есть, просто не писал сюда, оно нормально работает
Тогда с предложенным мной наивным foreach можно огрести,
если удаление функции происходит внутри другой или той же вызываемой функции (хотя предыдущий подход тоже не спасёт ситуацию)

Цитата:

действительно for each ведь медленее while
Глупости, смотря для чего и как
Тут народ пытался определить что же лучше (с переменным успехом): http://stackoverflow.com/questions/1...ce-in-as3-flex
Цитата:

for each в данном случае стают не нужными private var _funcCount:int = 0; private var _oldFuncCount:int = 0;
Да зачем вообще здесь поля эти использовать, да ещё 2 штуки.
Пользуйтесь переменными.

Вот пример без foreach, если религия не позволяет:
Код AS3:

var length:int = _myFuncVector.length;
for (var i:int = 0; i < length; i++)
{
    _myFuncVector[i]();
}

Или так (если коллеги за читабельность по рукам не надают и можно в обратном порядке функции выполнять):
Код AS3:

for (var i:int = _myFuncVector.length; i-- > 0;)
{
    _myFuncVector[i]();
}


Sintesis 09.02.2013 00:26

ну как же? Тут бесконечно будут создаваться переменные итераторы 60 раз в секунду
Код AS3:

for each (var fun:Function in _myFuncVector)//var fun:Function
for (var i:int = 0; i < length; i++)//var i:int

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

Сообщение от expl (Сообщение 1119802)
Тогда с предложенным мной нативным foreach можно огрести,
если удаление функции происходит внутри другой или той же вызываемой функции (хотя предыдущий подход тоже не спасёт ситуацию)

А что тут отгребать? Просто убираем функцию из вектора
Код AS3:

public function removeFunc(func:Function):void {
                        var i:int = _myFuncVector.length;
                        while (i--) {
                                if (_myFuncVector[i] == func) {
                                        _myFuncVector.splice(i, 1);
                                }
                        }
                }


derhab 09.02.2013 02:17

Может так попробовать?

Код AS3:

package resources{
        import flash.events.Event;
 
        /**
        * ...
        * @author Sintesis
        */

        public class MyTween{
 
                private var _myFuncDictionary:Dictionary;
 
                public function MyTween(){
                        _myFuncDictionary = new Dictionary();
                }
 
                .....
 
                public function setFunc(func:Function):void {
                        if(!_myFuncDictionary[func]) _myFuncDictionary[func] = true;
                }
 
                public function removeFunc(func:Function):void {
                        var f:Function = _myFuncDictionary[func];
                        if(f) delete  f;
                }
 
                private function timerListener(event:Event):void {
 
                        var f:Function = _myFuncDictionary[func]
                        if(f) f();
                }
        }
}


Zebestov 09.02.2013 03:58

В свое время мне показался более простым и очевидным другой вариант. Класс таймера наследовался от EventDispatcher. Он так же имел методы start(), stop(), reset(). Сам таймер был 2-в-1: он посылал как ENTER_FRAME в каждом кадре, так и TIMER каждую секунду (ну мне секунды было достаточно). При этом таймер корректно отрабатывал незавершенную секунду при последовательном вызове методов stop() и start().
Все, кто заинтересован в кадрах или секундах, просто получали ссылку на этот глобальный таймер и вешали на него слушатель. А уже по месту решалось, что делать в обработчике, который, к примеру, уже таки мог пробежаться по сотне объектов и передвинуть их.
Ну т.е. антиглобалистский такой подход =)

expl 09.02.2013 15:20

Цитата:

ну как же? Тут бесконечно будут создаваться переменные итераторы 60 раз в секунду
Вы вызвали двойной фейспалм у меня >_<.
4 байта, на стеке, будет создаваться 60 раз в секунду. Какой ужас!
При чем место на стеке и при взятии значения поля(не переменной), если не ошибаюсь, тоже выделяется.
Завязывайте с придумыванием себе проблем. Об этих 4-х байтах даже GC не знает - они автоматом после отработки функции сносятся.

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

Вот что может создать проблемы, т.к. память выделяется на куче, с последующей сборкой GC и прочими прелестями (но не в вашем случае - 60 раз в секунду выделить память под Point - это фигня на постном масле):
Код AS3:

var point:Point = new Point(x, y);

но не это:
Код AS3:

var point:Point = _anotherPoint;

и не это:
Код AS3:

var n:int = 100;


Цитата:

А что тут отгребать? Просто убираем функцию из вектора
Код AS3:

for each (f in _myFuncVector)
{
    f()
    // а внутри f вызывается removeFunc(...),
    // а внутри removeFunc вызывается _myFuncVector.splice(i, 1);
    // а мы, вообще-то идем по этому _myFuncVector
}

Самое тупое решение - скопировать список перед итерацией и итерировать по копии
Кстати, тут и с добавлением функции внутри функции те же проблемы будут.
Это типичная проблема для всяких самописных Signal-ов и EventDispatcher-ов (в стандартном, вроде, решена)
Если Вы уверены - что внутри слушателя не будете никого подписывать/отписывать - можете забить.


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

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