![]() |
|
||||||||||
|
|||||
|
Регистрация: Sep 2001
Адрес: Минск, РБ
Сообщений: 106
|
Уважаемый All, я надеюсь, что предлагаемый материал поможет КАЖДОМУ
(т.е. не иолько новичкам) лучше ПОНИМАТЬ Flash и других флешеров. Особенно если у него сложилось впечатление, что Flash это совсем просто. Часть 2 Реализованная во Flash концепция timelines и events при всей внешней простоте и очевидности таит в себе ряд сюрпризов натяжного и нажимного действия. Для тех кому это не сильно интересно или не приходится реализовывать сложные переходы между фреймами просто привожу код как можно реализовать паузу мувика несколько отличный от канонического: там где нужно организовать задержку 1c в каком-то мувике в любом месте пишем: _level0.startPause = getTimer() _level0.pauseDelay = 1000 Если нужно чтобы затормозился конкретный кадр (frameNum) то добавляем gotoAndStop(frameNum) а в самом мувике в его ObjectActions пишнм следующее onClipEvent(enterFrame) { if (_level0.startPause != null) { if ((getTimer() - _level0.startPause) > _level0.pauseDelay) { startPause = null this.play() } else { this.stop() } } } Это работает, но вот обьяснить почему именно так, а не по другому, к сожалению, очень кратко не получится. Придется кое-что понять мягко говоря не совсем вытекающее из документации от Macromedia, и честно говоря могущие постамить в тупик не только новичка в програмировании. Попробую рассказать и проиллюстрировать с чем приходится сталкиваться при организации сложных переходов по таймлайну. Начнем как обычно: открываем Flash, создаем новый мувик с названием grabli2 и создаем новый символ типа мувиклип. В этом мувиклипе создаем три кейфрейма и записываем в них следующие скрипты (соответственно) 1-й фрейм: trace("frame1: _currentframe: " + this._currentframe) 2-й фрейм: trace("frame2: _currentframe: " + this._currentframe) 3-й фрейм: trace("frame2: _currentframe: " + this._currentframe) Графику в мувик добавлять вначале не надо может только отвлечь - все самое интересное будет в окне trace. Размещаем мувик на сцене и в его ObjectActions пишем: onClipEvent(enterFrame) { trace("loadMC: _currentframe: " + this._currentframe) } onClipEvent(enterFrame) { trace("enterF: _currentframe: " + this._currentframe) } запускаем тестирование - в окне trace видим: loadMC: _currentframe: 1 frame1: _currentframe: 1 enterF: _currentframe: 2 frame2: _currentframe: 2 enterF: _currentframe: 3 frame3: _currentframe: 3 enterF: _currentframe: 1 frame1: _currentframe: 1 enterF: _currentframe: 2 frame2: _currentframe: 2 enterF: _currentframe: 3 frame3: _currentframe: 3 enterF: _currentframe: 1 frame1: _currentframe: 1 ......... Все вроде как и должно быть, в каждом фрейме сначала исполняется код на событие enterFrame, а затем код фрейма. В самом первом фрейме вместо события enterFrame происходит событие load. Все в точном соответствии с докуменнтацией. Обычно после такого эксперимента приобретаешь уверенность, что все понятно, и чтобы рганизовать паузу достаточно дать команду gotoAndPlay(myMovic._currentframe) А вот так ли это сейчас и проверим - добавим в обработчик события enterFrame сразу за сообщением trace команду gotoAndPlay(this._currentframe) и что мы видим: loadMC: _currentframe: 1 frame1: _currentframe: 1 enterF: _currentframe: 2 frame2: _currentframe: 2 enterF: _currentframe: 3 frame3: _currentframe: 3 enterF: _currentframe: 1 frame1: _currentframe: 1 enterF: _currentframe: 2 frame2: _currentframe: 2 enterF: _currentframe: 3 frame3: _currentframe: 3 enterF: _currentframe: 1 frame1: _currentframe: 1 .................... Нда, однако не получилось. И не понятно почему. Подозрение падает на команду gotoAndPlay(this._currentframe) которая, почему-то не исполняется. До вчерашнего дня я так и считал, что из текущего кадра просто нельзя сделать переход к нему самому. Но все оказалось намного хуже. Нельзя то нельзя, но по такой причине, что этот глюк показался совсем уж пустяковой мелочью. Еще немного подправим обработчик события enterFrame следующим образом onClipEvent(enterFrame) { trace("enterF: _currentframe: " + this._currentframe) gotoAndPlay(this._currentframe - 1) trace("afterG: _currentframe: " + this._currentframe) } т.е. раз не получилось перейти к текущему кадру, попробуем откатиться назад (честно говоря я предполагал что после этого весь мувик будет прокручиваться назад) и еще раз выведем переменную _currentFrame - хоть это и бессмысленно на первый взгляд, но поверьте оно стоит того. итак снова запускаем тест: loadMC: _currentframe: 1 frame1: _currentframe: 1 enterF: _currentframe: 2 afterG: _currentframe: 1 frame2: _currentframe: 1 frame1: _currentframe: 1 enterF: _currentframe: 2 afterG: _currentframe: 1 frame2: _currentframe: 1 frame1: _currentframe: 1 enterF: _currentframe: 2 afterG: _currentframe: 1 frame2: _currentframe: 1 frame1: _currentframe: 1 enterF: _currentframe: 2 afterG: _currentframe: 1 frame2: _currentframe: 1 frame1: _currentframe: 1 ........................ Ничего себе. Вам все понятно? А вот мне потребовалось приличный кусок времени, чтобы осознать на какой "букет" удалось напороться. Тем счаствливчикам которым все стало понятно с первого взгляда я искренне завидую, а остальным предлагаю разобраться последовательно: loadMC: _currentframe: 1 - ну это понятно - загрузка мувика frame1: _currentframe: 1 - исполнение первого кадра после загрузки enterF: _currentframe: 2 - тоже понятно - обработка события enterFrame afterG: _currentframe: 1 - !СТОП. Не понял. _currentFrame изменился - так какой же сейчас дествительно фрейм после команды gotoAndPlay. frame2: _currentframe: 1 - !!!ЧТО??? Фрейм остался прежний (второй) а _currentFrame показывает какую-то чучу. Нет наверное не чучу, а что-то что изменяется командой gotoAndPlay. Странно как-то. frame1: _currentframe: 1 - !!!СТОП. Фрейм сменился (куда заказывали) - а ГДЕ!!! обработка события enterFrame? enterF: _currentframe: 2 - А сейчас есть обработка. afterG: _currentframe: 1 frame2: _currentframe: 1 frame1: _currentframe: 1 - А здесь снова нет! enterF: _currentframe: 2 afterG: _currentframe: 1 frame2: _currentframe: 1 frame1: _currentframe: 1 - Может быть событие enterFrame не срабатывает после команды gotoAndPlay enterF: _currentframe: 2 afterG: _currentframe: 1 frame2: _currentframe: 1 frame1: _currentframe: 1 - ??? ----------------------------- Нннда, мало того что вместо паузы или прокрутки в обратном направлении получили дергающийся мувик так еще и кучу сомнений зародили. Самое серьезное сомнение в том насколько надежно срабатывает событие enterFrame, второе - насколько можно доверять переменной _currentframe - как-то мне приходилось видеть достаточно сложные алгоритмы анимации в которых эта переменная активно используется. Как наверно приятно обнаружить, что если слоем выше или даже просто чуть раньше выполнилась команда gotoAnd... то изумительный алгоритм вычислит полную ахинею. А вот еще код, автор которого безуспешно пытался понять, почему он не работает, Есть кнопка, общая для всех кадров и на ней код on(release) { if(_currentframe = 2) { gotoAndStop(5) } if(_currentframe = 5) { gotoAndStop(2) } .......... } В пятом кадре она сработает, а вот во втором - фигу, и все вроде правильно. Приятный сюрприз - грабли да и только. Продолжение см. далее |
|
|||||
|
Регистрация: Sep 2001
Адрес: Минск, РБ
Сообщений: 106
|
А с enterFrame надо разбираться дальше - слишком я уважаю концепцию событий.
Открываем для редактирования наш мувик и добавляем во FrameActions следущее: 1-й фрейм: gotoAndPlay(2) 2-й фрейм: gotoAndPlay(3) 3-й фрейм: gotoAndPlay(1) Запускаем тест и ... повисаем. Правда ненадолго - на 20 секунд. И окошко trace заполняется: loadMC: _currentframe: 1 frame1: _currentframe: 1 frame2: _currentframe: 2 frame3: _currentframe: 3 frame1: _currentframe: 1 frame2: _currentframe: 2 frame3: _currentframe: 3 frame1: _currentframe: 1 frame2: _currentframe: 2 frame3: _currentframe: 3 frame1: _currentframe: 1 ....................... Точно - команда gotoAndPlay() срабатывание обработчика события enterFrame НЕ ВЫЗЫВАЕТ, но самое приятное в этом тесте оказывается именно ПОВИСАНИЕ. Честно-честно, я уже сталкивался с таким зависанием и уже знаю что это означает. Означает это только одно, что команда gotoAndPlay несмотря на то, выполняется после всех скриптов фрейма, цепочку команд при этом не разрывает, а обеспечивает непосредственный переход к выполнению команд указанного фрейма. Т.е. скрипты в разных фреймах выполняются как одним кускок без разрывов для исполнения команд в других мувиках. Для кого-то последний абзац может показаться либо тривиальным, либо сильно заумным, но это действительно ВАЖНО. Во Flash реализована концепция многопоточного псевдопараллельного исполнения процессов, где каждый процесс это мувик, точнее таймлайн. И если не понимать КАК это реализовано, какие есть ограничения в этой реализации, можно угробить любую, самую производительную машину. Что мы только что и сделали. И еще один момент, требующий уточнения. Как видно из лога скрипты по команде gotoAndPlay исполняются, а что происходит с изображением, графикой и т.п. Для этого еще раз подредактируем мувик. В каждый кадр добавим по изображению позволяющее четко идентифицировать кадр, например квадраты разного цвета. И еще раз завесим машину. Теперь четко видно, что хотя скрипты во всех вреймах исполняются, изображение остается неизменным. Вот так - фрейм фрейму оказывается рознь. И если даже покадрово анимация выполнена прекрасно, переходами с помощью gotoAndPlay можно не только потерять несколько кадров, но и вообще всю анимацию. И все таки остается вопрос когда же собственно срабатывает enterFrame. Если заменить во FrameActions gotoAndPlay() на gotoAndStop() картинка трассировки не изменяется (лог не привожу - придется поверить на слово) А вот если в первом фрейме оставить gotoAndPlay(2), а во втором фрейме совсем убрать gotoAnd... то картинка становится уже лучше. Напомню что на событии enterFrame выполняется команда gotoAndPlay(this._currentframe - 1) И получаем вот такой лог: loadMC: _currentframe: 1 frame1: _currentframe: 1 frame2: _currentframe: 2 enterF: _currentframe: 2 afterG: _currentframe: 1 frame1: _currentframe: 1 frame2: _currentframe: 2 enterF: _currentframe: 2 afterG: _currentframe: 1 frame1: _currentframe: 1 frame2: _currentframe: 2 enterF: _currentframe: 2 afterG: _currentframe: 1 frame1: _currentframe: 1 ........................ Четко видно по типу графики что отображается второй фрейм, а почти похож на один из предыдущих вариантов, НО за маленьким исключением последовательность выполнения FrameActions для кадра 2 и обработчика события для enterFrame стала противоположной - а я все никак понять не мог почему в разной документации относительно этого момента встречаются разночтения. Одни утверждают, что сначала срабатывает обработчик событий, а затем скрипт фрейма, другие, что все как раз наоборот. Оказывается, что все правы, важны условия. Не знаю надо ли кому-то писать код так, чтобы от этой последовательности зависел результат, но советую быть в этом случае по-внимательней. Но куда более существенный момент в том, что при этом тестировании выявилось различие между тем что мы ВИДИМ и тем что на самом деле ПРОИСХОДИТ. Видим мы только второй фрейм, а выполняются скрипты и первом и во втором. Если бы не трассировка всех кадров мы могли обэтом даже не узнать. Сдедовательно если организовывать паузу через gotoAndPlay(this._currentframe - 1) в предыдущем фрейме не должно быть никакого скрипта. Что-то длинноватый текст получается, наверно уже и читателей не оталось ("редкая птица долетит до середины Днепра") будем заканчивать. Последнее изменение - в обработчике события enterFrame вместо всяких там gotoAnd... пишим грубо конкретное stop() и запускаем: loadMC: _currentframe: 1 frame1: _currentframe: 1 frame2: _currentframe: 2 enterF: _currentframe: 2 afterG: _currentframe: 2 enterF: _currentframe: 2 afterG: _currentframe: 2 enterF: _currentframe: 2 afterG: _currentframe: 2 enterF: _currentframe: 2 afterG: _currentframe: 2 enterF: _currentframe: 2 afterG: _currentframe: 2 enterF: _currentframe: 2 afterG: _currentframe: 2 ........................ Что и требовалось - фрейм всегда вторрой, обработчик живее всех живых и способен делать что требуется, считать задержки, ожидать конкретных событий, следить за значениями переменных и т.д. Вобщем можно подводить итоги: Как сделать: паузу см. код в самом начале. Как сделать: реверс анимации используем gotoAndStop(this._currentframe - 1) Как сделать: ускоренный реверс анимации - gotoAndStop(this._currentframe - 2) Правда для чистого реверса FrameActions либо не должно быть совсем либо они должны блокироваться флагом реверсирования. Вот собственно и все - как этим материалов воспользоваться, решать вам самим, "Кто предупрежден - тот вооружен", но если позволите я попробую сформулировать некоторые размышления по этому поводу. Прежде всего хочу отметить что данная граблеобразная "особенность" Flash нигде в доступной мне документации полностью не описана. Может быть это ноу-хау флэш-гуру. Второе - нельзя абсолютно доверять значению переменной _currentFrame - она изменяется после каждой команды gotoAnd... Третье - последовательность исполнения FrameActions и обработчика события enterFrame зависит от конкретной ситуации - т.е. каким образом совершен переход на данный кадр. Четвертое - событие enterFrame не срабатывает при переходе на фрейм с помощью команды gotoAndPlay И наконец, надо как-то честно предупредить начинающий флэшеров что во флеше есть не только "конфетки" но и такого рода грабли. Хотелось бы добавить в этакий кодекс молодого строителя флэш-коммунизма следущее: "Фрейм фрейму рознь" "Стоп это плэй, а плэй это стоп" "Верить никому нельзя, трэйсу можно ... самому полному трейсу" и т.д. Список предлагаю продолжить. P.S. Все замечания к данному тексту прошу дублировать на apm@tut.by Best regards, APM |
|
|||||
|
Регистрация: Sep 2001
Адрес: Moi address ne dom i ne ulica...
Сообщений: 634
|
Vot eto-da!! Ti prosto molodez (Takoi "Research" prodelat!!! i eshe podelitsia - ne kashdii moshet).... Ia dumaiu tebe nado napisat v "Macromedi`u" "Bag_report" i oni za takoi "Research" podrobnii - tebe dolshnii medal dat!!!! (Vo kak!!!) (Pervii grabli ia proveril, u menia takshe!! eshe raz thanks ogromnii - tebe ot vseh!!!) |
|
|||||
|
Шли свою рисерчину в уроки!
__________________
http://www.petgraph.ru |
|
|||||
|
Регистрация: Sep 2001
Адрес: Минск, РБ
Сообщений: 106
|
RE: YuriiZelenev
По поводу извещения Макромедии, то мне кажется, что это насколько преждевременно, на самом деле кроме очевидного прокола с _currentFrame, все остальное пока не кажется ошибкой – скорее это особенность реализации. А то, что это не отражено в документации, то это типовая проблема – документация всегда отстает как минимум на одну версию. Более того, возможно, что отмеченные особенности на самом деле являются вообще новым словом в программировании, и когда-нибудь будут восприниматься совершенно естественно, это сейчас они несколько непривычны тем, кому не приходилось делать параллельные или многопоточные системы. Я постараюсь как-нибудь в одном из следующих материалов это обосновать. Есть и еще одна проблема – адекватный перевод. Читать на англицком я еще могу, но что-то написать удается с большим трудом. Поэтому, если выбирать из одного английского текста, и трех русских, то я выбираю второе. Можно попробовать по-другому, если кто-то возьмет на себя нелегкий труд по переводу, то обещаю, что славу, гонорары и шишки поделим по справедливости или поровну (по выбору переводчика). RE: petgraphh Нет, я пока не считаю нужным помещать эти материалы в раздел "Уроки" - причин несколько: во-первых, материал должен устаканиться у меня самого в голове, во-вторых, немного обкатан в дискуссии, в-третьих, в первую очередь он предназначен для тех, кто либо еще, либо уже не читает никаких уроков, в-четвертых , необходима редакторская правка, и , наконец, пожалуй, самое главное, этот материал не полон, нет иллюстративных и полезных примеров, как можно наступить на грабли, и, наоборот, подойти, к "граблям" с нужной стороны и что-то полезное при этом сделать. Вот, например, используя данной конкретный материал и следующую часть (постараюсь выложить в понедельник), можно сделать функцию по синхронизации мультика и звука. Хотя и считается, что это принципиально невозможно, однако это не так. Руки просто не доходят. Если же считаете, что материал годится даже в таком виде, то можно просто сделать на него соответствующую ссылку с собственным комментарием, для начинающих флешеров. И спасибо за отзывы. |
|
|||||
|
Регистрация: May 2002
Адрес: Ростов-на_Дону
Сообщений: 542
|
2ARM
Это круто, круто, круто!!! Впервые вижу такой детальный анализ, столь блестяще проведенный. Дело не в том, что твой текст может быть недоработан стилистически, или не украшен картинками, он проливает свет на алгоритмы функционирования Флэш. Такое действительно необходимо видеть в уроках. Обидно, что я натолкнулся на этот материал случайно. Я вооще предлагаю организовать на основе твоего текста и подобных отдельный цикл - исследование Флэш типа "Русские грабли" и пошлю это сообщение модератору. Куда бы писали обо всех найденных недокументированных свойствах Флэша. На западе книги с аналогичным содержанием становятся бэстселлерами. Люди на них делают состояния. Взять хотя-бы издательство O'REILLY. Серия с гравюрами животных на обложке. У меня есть "Хитрости Windows 98" Дэвида Карпа, она мне очень в свое время помогла www.annoyances.org ]http:www.annoyances.org [/url] . У нас же о своих находках , увы, не принято говорить. На них делают деньги. Тихо. Немного. И посмеиваются над незнающими. А ведь сделав себе имя на анализе столь недокументированного черного ящика, как Флэш, можно стать не только знаменитым, но и богатым человеком. Честь и хвала таким первооткрывателям, как ARM, УильямБрэдбери и другим. С праздником Победы!
__________________
Uri-Uri Как могут существовать вещи, которые никогда не случаются? Измена мира к лучшему! |
|
|||||
|
Цитата:
__________________
d0dge. |
|
|||||
|
Цитата:
Я вот наример ничего не понял... Напишите, как лучше понимать такие статьи? Какой ключ к пониманию?..
__________________
d0dge. |
|
|||||
|
Регистрация: May 2002
Адрес: Петрозаводск
Сообщений: 63
|
APM: RESPECT!
Просто СУПЕР! |
![]() |
Часовой пояс GMT +4, время: 17:49. |
|
|
« Предыдущая тема | Следующая тема » |
|
|