Вдохнуть и не дышать - пауза во флеш-играх

04.06.2008, автор Stormit, рубрики: ActionScript, Анимация

Во flash-играх часто возникает необходимость сделать паузу. Подразумевается, что действующие лица перестают двигаться и взаимодействовать между собой. В последнее время это актуально и для игровых баннеров. Людей раздражает постоянно мельтешащая анимация и некоторые сайты выдвигают требование ставить баннер на паузу через 15 секунд. Если эта функциональность не закладывалась с самого начала, то включить паузу не всегда просто и сильно зависит от того, как все устроено.

Мне известно 2 подхода к flash-программированию: структурированный и хаотичный. При первом все символы и объекты организуются в строгую иерархию, управление сосредоточено в одном месте, и этот “мозг” каждый кадр перебирает массив подчиненных ему объектов и вызывает для каждого функцию действия. Все строится по принципам ООП. Таким образом работают, например, движки 2D физики и 3D. Хороший способ, уменьшает вероятность ошибки, но требует основательного подхода и много времени.

Есть еще хаотичное или стихийное программирование, когда для каждого клипа (которому это нужно) задается событие onEnterFrame и он запускается в “свободное плавание” (программисты со стажем сейчас меня нещадно осудят). Это настоящее самоуправление, каждый клип живет в пределах своих фигурных скобок. Друг о друге символы знают мало, обычно разбиваются по группам и заносятся в массивы. Метод тоже хороший, можно все сделать быстро, но есть шанс запутаться и поматерить флэш, который “опять глючит”. Этот метод я обычно использую для задач-однодневок, пока все свежо в памяти.

Есть еще третий метод, который мне нравится больше всего - он сочетает в себе и структуру и свободу выбора - ООП основанное на событиях. Но это уже условное отделение - классы как-никак.

Так вот, возвращаясь к вопросу о глобальной паузе: для структурного подхода все просто: заводится логическая переменная (пауза есть/нет), опираясь на которую, главный клип либо вызывает для всех функцию действия, либо нет. Это что касается кода, остановить твиннинг гораздо сложнее. Например, летит муха, у нее дрожит туловище, она машет крылышками и к тому же моргает. Нужно 3 раза вызвать функцию stop(). А если на сцене символов много, и все они разные? Как минимум для каждого объекта нужно описывать функцию его полной остановки (с событиями кстати также - наследование не поможет если символы разные).Для стихийного подхода к программированию это почти расстрел. В обоих случаях нужно писать много строк Actionscripta. Некоторое время я так и мучался, попутно выдумывая, как это можно упростить. Вот то, что есть у меня на сегодня:

Что может приводить объект в движение? Твиннинг или ActionScript (а точнение событие EnterFrame). SetInterval я во внимание не беру.
Значит должна быть функция которая останавливает проигрывание клипа и отключает для него onEnterFrame.

 needBePaused = new Array();//тут хранятся все клипы для ПАУЗЫ
_global.addToPause = function(obj){
    if(!obj._inPause){//2 раза в ПАУЗУ не добавляем
        needBePaused.push(obj);
        obj._inPause = true;
    }
}
_global.setPause = function(flag) {
    isPause = flag;//переменная, на всякий случай
    var i = needBePaused.length;
    while(i--) {
        var curObj = needBePaused[i];
        if (flag) {
            curObj.stop();
            curObj.oef = curObj.onEnterFrame;//временно сохраняем
            curObj.onEnterFrame = null;
        } else {
            curObj.onEnterFrame = curObj.oef;//восстанавливаем
            curObj.play();
        }
    }
}

Этот код лучше положить в _root, в первый кадр. Для клипа который должен останавливаться нужно вызвать функцию addToPause(this). Лучше всего прописать ее в самом клипе в первом кадре. Даже если есть анимация воспроизводящая головка много раз пройдется по первому кадру, сработает проверка и 2 раза клип в массив не добавится. Как по мне, это удобный способ. Строка addToPause(this) копируется в буффер, а дальше начинается рейд по символам и Ctrl+v.

Теперь пауза включается из любого места вызовом функции setPause(true). Каждый клип останавливается, а его onEnterFrame сохраняется в переменной oef и обнуляется (на конструкцию onClipEvent это не действует, используйте onEnterFrame = function() {…}). При отключении паузы все происходит в обратной последовательности.

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

Интересно на 80%

(18) Хитрых на тему «Вдохнуть и не дышать - пауза во флеш-играх»

  1. Fushigi

    Очень хитро :)

  2. timaktaev

    Ничего не понимаю во флеше ) Но что, если эту муху останавливать как объект (типа пусть продолжает махать крыльями, трястись и моргать), делать её “принтскрин” и ставить на верхний слой? - Объекты не перемещаются события не случаются, а картинка это всё просто сверху накрывает.

  3. Stormit

    Хорошее решение, но после нужно снять ролик с паузы и начать проигрывать с того же места. За это время в игре можно проиграть, мультфильм может промотать далеко. Да и звуки будут слышны.
    А так интересный ход конечно.

  4. timaktaev

    эээ…
    Опять же, ничего не понимаю во флэше, но как можно проиграть, если объекты не движутся (только дергаются их детали - это чтобы не тормозить всё “дерево” объекта)?
    Ролик снимается тоже вроде просто, или я туплю: нажали кнопку паузы - снимается картинка и одновременно запускается игра.
    Да и со звуками та же тема - обычно у игр есть типичное отключение звуков. Это как-то хитро делается?

  5. Stormit

    >>если объекты не движутся (только дергаются их детали)
    А каким образом все объекты перестали двигаться? - для всех была вызвана функция stop() (или в цикле их перебрали, или они на событие сами среагировали). Вопрос - как сделать этот процесс проще для разработчика.

  6. timaktaev

    ну ладно, пускай тогда это прием только для баннеров работает )

  7. Stormit

    Да он везде может работать.
    Особенно там, где изначально пауза не планировалась, а в конце работы вдруг понадобилась (заказчик захотел). А объектов много и все на разном уровне вложенности.
    Другое дело что это не догмат, а всего лишь альтернативный способ. Для расширения кругозора, если хотите. А кому-то может быть поможет. Мне помогает :)

  8. sta1ex

    хитро однозначно, респект! пока не приходилось сталкиваться с такой задачей, но иногдя для эстетики можно и добавлять в код этот гениальный кусочек:) пасип

  9. Hitokiri

    Очень хорошая статья, но можно для начинающих описать “new Array”?

    Я понимаю что это какой-то массив… Но, возможно напишите такториал по массивам или порекомендуете где можно изучить доходчиво и на русском?

    Кстати, как тема для будущих уроков: “Сохранение игры в любом месте”. Возможно даже с выносом сейв-файла во внешний .txt или .xml

  10. Stormit

    Лучше всего почитать хорошую книгу (автор Колин Мук)
    Вот нашел в гугле: http://www.flashdocs.net/modules.php?name=News&file=article&sid=23
    >>Сохранение игры в любом месте
    Это безусловно интересная задача, но не так сложно сохранить результаты, как восстановить потом по ним все объекты.

  11. Hitokiri

    Огроменное мерси за ссылку! :) Всенепременно изучу.

    Ну если не в любом месте, то хотя бы в ключевых точках :) И конечно особенно интересно как сделать:

    a. Чтобы флеш сохранял сам в себя. Например можно создать и удалить записи, скажем 3-х игроков.

    б. Чтобы флеш сам на жестком диске создавал файл (в любом формате) и сохранял все туда.

  12. Stormit

    Мне кажется что между классом Array и сохранением игры очень большой диапазон знаний :)
    Сохранять локально данные можно в объекте Shared Object (это что-то вроде Cookies, только родное, флэшовое).

  13. Hitokiri

    >>Мне кажется что между классом Array и сохранением игры очень большой диапазон знаний…

    Это верно :) Просто, обладая базовыми навыками, хочется их расширять… вот стараюсь сделать хоть простую (если не сказать примитивную) игрушку, но сам. Соответственно чем больше я в ней проработаю разных комбинаций, тем лучше буду понимать как их применить в сложных проектах.

    >>Сохранять локально данные можно в объекте Shared Object
    Просим таториал! :) Думаю это будет полезно, раз уж блог о создании игр.

    Есть вероятность что народ меня в такой просьбе поддержит :)

  14. Hitokiri

    Кстати, пользуясь тем что тема про клики и речь зашла про темы статей…

    Есть туча способов назначить на одну кнопку несколько действий (например, чтобы после каждого клика она меняла свой текст, цвет и функции). Так вот, неплохо бы услышать ваши хитрые советы, как можно сделать это максимально быстро и легко, к тому же сэкономив на весе ролика и размерах кода.

  15. Stormit

    Не совсем понял в чем задача.
    Максимально быстро и легко обычно получается когда переносишь код и символы из предыдущих проектов.
    Если я все-таки правильно понял задачу:
    Можно сделать символ из N кадров, в каждом из которых, кнопка (символбез текста) в нужном виде и с нужным кодом. Текст в каждом кадре пишется слоем выше. Наверное это самый быстрый и простой способ для аниматора.

  16. Hitokiri

    >>Можно сделать символ из N кадров, в каждом из которых,
    >>кнопка (символбез текста) в нужном виде и с нужным кодом.
    >>Текст в каждом кадре пишется слоем выше.
    Можно и так (по крайней мере я так делаю :) ). Ну а если текст в кнопке динамический? Например есть две версии сайта русский и английский. Название кнопки в каждом имеет денамический текст. Более того, как русская так и английская кнопка имеют два текста и две функции. Например по умолчанию: Текст - “нажать”, функция - пока нету. Нажимаем. Тогда текст: - “нажата”, функция - “играет музыка”. Нажимаем снова и переходим на фазу по умолчанию. Пример взят из головы. Можно усложнить задачу, чтобы бало 3 таких кнопки и при нажатии на одну из них, другие переходили в неактивную или нужную по логике фазу.

  17. Stormit

    Это не универсальная задача, ее можно усложнять и изменять вечно. Я не могу все время давать ответ. Тем более что к флэш-играм это не имеет никакого отношения, а ответы на многие вещи можно найти нажав F1.
    Все можно сделать как анимацией, так и программно. Каждый по своему опыту выбирает что лучше, в любом случае решений всегда несколько.
    Если у тебя изменяется текст, функции и вид кнопки, логично что нужно как-то описать сначала все состояния (или нарисовать каждое в отдельном кадре) и затем переключать их (изменять текст, цветовые трансформации) и выполнять нужный код по ситуации. При переключении свойству onRelease присваивается другая функция.
    Если задействованы 3 кнопки, то логичней центр управления вынести над ними описав некий виртуальный объект “Набор кнопок” (переменные и функции) и обрабатывать в нем нажатие на кнопки. Причем кнопка может при нажатии сама изменить себя, а затем вызвать функцию “набора” чтобы он деактивировал остальные (и запомнил какая нажата, а какие нет). А можно на классах сделать (один для кнопки и один для “набора кнопок”).
    Это все не сложно объяснять, но это не по теме блога, это общие знания о флэш-программировании.

  18. Hitokiri

    Спасибо за развернутый ответ — обязательно воспользуюсь :)

    А про неприминимость к играм вы не правы. Как раз именно в играх много раз вижу, что такие функции у авторов косячат. Особенно часто это бывает когда по-баловству жму многофункциональную кнопку быстро и много раз подряд. Мувики не разбирал — не знаю с чем это связано, но доставляет массу хлопот.

Оставить комментарий