Вдохнуть и не дышать - пауза во флеш-играх
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() {…}). При отключении паузы все происходит в обратной последовательности.
Есть конечно и минусы. Если до паузы клип был остановлен в каком-либо кадре, то после - он запустится. Это решается путем добавления к клипу переменной отражающей его состояние проигрывания, но у меня пока в этом не было необходимости.
Интересно на 39%




Очень хитро
Ничего не понимаю во флеше ) Но что, если эту муху останавливать как объект (типа пусть продолжает махать крыльями, трястись и моргать), делать её “принтскрин” и ставить на верхний слой? - Объекты не перемещаются события не случаются, а картинка это всё просто сверху накрывает.
Хорошее решение, но после нужно снять ролик с паузы и начать проигрывать с того же места. За это время в игре можно проиграть, мультфильм может промотать далеко. Да и звуки будут слышны.
А так интересный ход конечно.
эээ…
Опять же, ничего не понимаю во флэше, но как можно проиграть, если объекты не движутся (только дергаются их детали - это чтобы не тормозить всё “дерево” объекта)?
Ролик снимается тоже вроде просто, или я туплю: нажали кнопку паузы - снимается картинка и одновременно запускается игра.
Да и со звуками та же тема - обычно у игр есть типичное отключение звуков. Это как-то хитро делается?
>>если объекты не движутся (только дергаются их детали)
А каким образом все объекты перестали двигаться? - для всех была вызвана функция stop() (или в цикле их перебрали, или они на событие сами среагировали). Вопрос - как сделать этот процесс проще для разработчика.
ну ладно, пускай тогда это прием только для баннеров работает )
Да он везде может работать.
Особенно там, где изначально пауза не планировалась, а в конце работы вдруг понадобилась (заказчик захотел). А объектов много и все на разном уровне вложенности.
Другое дело что это не догмат, а всего лишь альтернативный способ. Для расширения кругозора, если хотите. А кому-то может быть поможет. Мне помогает
хитро однозначно, респект! пока не приходилось сталкиваться с такой задачей, но иногдя для эстетики можно и добавлять в код этот гениальный кусочек:) пасип
Очень хорошая статья, но можно для начинающих описать “new Array”?
Я понимаю что это какой-то массив… Но, возможно напишите такториал по массивам или порекомендуете где можно изучить доходчиво и на русском?
Кстати, как тема для будущих уроков: “Сохранение игры в любом месте”. Возможно даже с выносом сейв-файла во внешний .txt или .xml
Лучше всего почитать хорошую книгу (автор Колин Мук)
Вот нашел в гугле: http://www.flashdocs.net/modules.php?name=News&file=article&sid=23
>>Сохранение игры в любом месте
Это безусловно интересная задача, но не так сложно сохранить результаты, как восстановить потом по ним все объекты.
Огроменное мерси за ссылку!
Всенепременно изучу.
Ну если не в любом месте, то хотя бы в ключевых точках
И конечно особенно интересно как сделать:
a. Чтобы флеш сохранял сам в себя. Например можно создать и удалить записи, скажем 3-х игроков.
б. Чтобы флеш сам на жестком диске создавал файл (в любом формате) и сохранял все туда.
Мне кажется что между классом Array и сохранением игры очень большой диапазон знаний
Сохранять локально данные можно в объекте Shared Object (это что-то вроде Cookies, только родное, флэшовое).
>>Мне кажется что между классом Array и сохранением игры очень большой диапазон знаний…
Это верно
Просто, обладая базовыми навыками, хочется их расширять… вот стараюсь сделать хоть простую (если не сказать примитивную) игрушку, но сам. Соответственно чем больше я в ней проработаю разных комбинаций, тем лучше буду понимать как их применить в сложных проектах.
>>Сохранять локально данные можно в объекте Shared Object
Думаю это будет полезно, раз уж блог о создании игр.
Просим таториал!
Есть вероятность что народ меня в такой просьбе поддержит
Кстати, пользуясь тем что тема про клики и речь зашла про темы статей…
Есть туча способов назначить на одну кнопку несколько действий (например, чтобы после каждого клика она меняла свой текст, цвет и функции). Так вот, неплохо бы услышать ваши хитрые советы, как можно сделать это максимально быстро и легко, к тому же сэкономив на весе ролика и размерах кода.
Не совсем понял в чем задача.
Максимально быстро и легко обычно получается когда переносишь код и символы из предыдущих проектов.
Если я все-таки правильно понял задачу:
Можно сделать символ из N кадров, в каждом из которых, кнопка (символбез текста) в нужном виде и с нужным кодом. Текст в каждом кадре пишется слоем выше. Наверное это самый быстрый и простой способ для аниматора.
>>Можно сделать символ из N кадров, в каждом из которых,
). Ну а если текст в кнопке динамический? Например есть две версии сайта русский и английский. Название кнопки в каждом имеет денамический текст. Более того, как русская так и английская кнопка имеют два текста и две функции. Например по умолчанию: Текст - “нажать”, функция - пока нету. Нажимаем. Тогда текст: - “нажата”, функция - “играет музыка”. Нажимаем снова и переходим на фазу по умолчанию. Пример взят из головы. Можно усложнить задачу, чтобы бало 3 таких кнопки и при нажатии на одну из них, другие переходили в неактивную или нужную по логике фазу.
>>кнопка (символбез текста) в нужном виде и с нужным кодом.
>>Текст в каждом кадре пишется слоем выше.
Можно и так (по крайней мере я так делаю
Это не универсальная задача, ее можно усложнять и изменять вечно. Я не могу все время давать ответ. Тем более что к флэш-играм это не имеет никакого отношения, а ответы на многие вещи можно найти нажав F1.
Все можно сделать как анимацией, так и программно. Каждый по своему опыту выбирает что лучше, в любом случае решений всегда несколько.
Если у тебя изменяется текст, функции и вид кнопки, логично что нужно как-то описать сначала все состояния (или нарисовать каждое в отдельном кадре) и затем переключать их (изменять текст, цветовые трансформации) и выполнять нужный код по ситуации. При переключении свойству onRelease присваивается другая функция.
Если задействованы 3 кнопки, то логичней центр управления вынести над ними описав некий виртуальный объект “Набор кнопок” (переменные и функции) и обрабатывать в нем нажатие на кнопки. Причем кнопка может при нажатии сама изменить себя, а затем вызвать функцию “набора” чтобы он деактивировал остальные (и запомнил какая нажата, а какие нет). А можно на классах сделать (один для кнопки и один для “набора кнопок”).
Это все не сложно объяснять, но это не по теме блога, это общие знания о флэш-программировании.
Спасибо за развернутый ответ — обязательно воспользуюсь
А про неприминимость к играм вы не правы. Как раз именно в играх много раз вижу, что такие функции у авторов косячат. Особенно часто это бывает когда по-баловству жму многофункциональную кнопку быстро и много раз подряд. Мувики не разбирал — не знаю с чем это связано, но доставляет массу хлопот.
Дякую за статью. Не забрасывайте блог и постоянных посетителей. Кстати, поздравляю: Большой Андронный Колайдер запустили, а мы все еще живы!
Еще более простой способ (хотя, наверное только для AS3):
stage.frameRate = pause ? 0 : 30; // или ваш любимый фпс
objects.stop() не работает, если символы “многоэтажные” - верхний уровень выбирает объект, а анимация на более нижнем уровне (как у тебя в примере с препятствиями - кактус-доска-ежик, ксати, спасибо за идею, я первые шаги на флеше делаю, пока только вникаю, как тут что).
Очень хорошие первые шаги
Обнулить фреймрейт - отличная идея.
только маленький хинт: если хочется, чтобы кнопка паузы перерисовалась (например || на > ), нужно заменить кнопку, а уже на следующем кадре занулить фреймрейт. А то если не будет движения мыши и фпс == 0, то ничего перерисовываться не будет, и при аккуратном клике без движения мыши можно будет наблюдать старое состояние кнопки.
А вот пример простой паузы которую я чаще всего использую в своих приложениях:
в кадре где нужно сделать паузу прописываем:
stop ();
pauseAnim=setInterval (this, “nextFrame”, 5000);
в следующем кадре вставляем:
clearInterval (pauseAnim);
play();
Вот и все! 5000 - это задержка в миллисекундах. Соответственно можно менять на подходящее значение.
Отличный сайт, суперские работы, наверняка хороший и умный автор, спасибо за примеры, Ура!:)
to Molodoi_Abrikos
Если флэшка начнёт тормозить, то таймер всё равно сработает через 5 секунд, а кадры не все успеют отобразиться.
С паузой в AS3 через обнуление фреймрейта есть один глюк: иногда через несколько секунд после нажатия на паузу флэш еще разок обновляет кадр. Кто нибудь сталкивался, как это забороть?
Попробуй timeout увеличить. Он задается в свойствах проекта и равен 15 секундам по умолчанию. По прошествии этого времени флеш обновляет кадр принудительно. Еще перерисовка может происходить из-за интенсивного кликанья мышью. Так что, эта пауза тоже не без недостатков. Я у себя в игре помимо зануления фреймрейта отключал вызов функций пересчета координат и т.д. объектов. Раз в пятнадцать секунд просто менялся кадр у червяков - вот и все. Многие вообще не парятся - объекты останавливаются на паузе, но продолжают шевелится.
Спасибо за совет, теперь все ок.
спасибо Вам за этот способ… что не находила в инуте по этому вопросу, ваш способ оказался более “дееспособным”)) но вот про это
<<<Есть конечно и минусы. Если до паузы клип был остановлен в каком-либо кадре, то после - он запустится. Это решается путем добавления к клипу переменной отражающей его состояние проигрывания, но у меня пока в этом не было необходимости.
можно подробнее(( а то у меня такой случай…
Есть идея, правда ещё не пробовал:
При паузе, мы проходимся по всем клипам, обнуляем onEnterFrame, но сами клипы не останавливаем, сохраняем только их текущий кадр (в самом же клипе). Следующий кадр опять проходимся по всем клипам и смотрим у кого текущий кадр изменился - помечаем их как “играющий” и возвращаем в сохранённый кадр.
При отмене паузы запускаем на воспроизведение только клипы помеченные как “играющие”.
Исходник мне .. я хачу исходник этого флеша .. я понимаю что прошло уже много тысяч лет, но этот вопрос таки магит быть ешо актуальным.. низнаю кто как, но я наилучше всё понимаю в исходниках .. а не в таких кусках кода, где нужно думать ешо .. я такого не люблю .. я же программист, а программисты по своей природе ленивые .. всё устал писать ..
Вам исходного кода недостаточно
Копи-пастить даже обезьяны умеют.
Давно это было и наверное уже все разобрались, но все таки напишу )
В AS3 есть чУдная System.pause(); и выход из неё - System.resume();
делает фриз всего фильма (твины, функции и т.д.)
вроде бы пока не было никаких неприятных неожиданностей
я всё-таки погорячился
во флеше по прежнему требуется четкое планирование, никаких волшебных методов, останавливающих всё на свете )
а что с System.Pause?
Она только для отладочной версии проигрывателя