Дострочное пересдача экзамена
|
Привязка динамики к времени и кадрам
Отсчет времени
Функция getTimer() возвращает время (в миллисекундах), прошедшее с момента запуска фильма. Если, к примеру, на момент вызова этой функции фильм воспроизводится уже шесть секунд, то скрипт
playBackTime = getTimer();
присвоит переменной playBackTime значение 6000 (1000 миллисекунд в каждой секунде). Это – точное время, отсчитываемое по системным часам пользовательского компьютера; оно не зависит ни от частоты кадров фильма, ни от быстродействия процессора, ни от того, воспроизводится ли фильм или стоит на одном и том же кадре. Подчеркнем, что функция возвращает время, прошедшее с момента запуска всего фильма, а не отдельных монтажных столов.
Промежуток времени между двумя событиями внутри фильма все же можно измерить. Для этого следует в нужный момент присвоить какой-либо переменной значение, возвращенное функцией getTimer(), а потом сравнить с этой переменной новое значение, возвращенное функцией. Поясним это на следующем примере:
// Скрипт для кнопки A on (release) { startTime = getTimer(); } // Скрипт для кнопки B on (release) { nowTime = getTimer(); if (nowTime – startTime < 1000) { message.text = "Вы нажали кнопку слишком быстро"; } else { message.text = "Слишком поздно"; } }
Здесь, если нажата и отпущена одна из кнопок (кнопка A), фиксируется стартовая точка отсчета времени. Когда нажата и отпущена кнопка B, время снова фиксируется. Условный оператор определяет, больше или меньше секунды прошло между двумя этими моментами, и выполняет соответствующее действие. Сходным образом можно реализовать для одной кнопки обработку двойного щелчка – следующий скрипт будет выполнять действия только в том случае, если второй щелчок на кнопке произошел не позднее, чем через полсекунды после первого:
on (release) { if (getTimer() – lastClick < 500) { // Действия } lastClick = getTimer(); }
Используя функцию getTimer() совместно с событием enterFrame и условными операторами, можно создать механизм выполнения тех или иных действий в определенное время – независимо от монтажного стола и с большой точностью отсчета. Возьмем такой пример:
onClipEvent (enterFrame) { if (getTimer() > 5000) { // Действия } if (getTimer() > 10000) { // Действия } if (getTimer() > 15000) { // Действия } }
Этот скрипт будет выполнять действия каждые пять секунд по ходу воспроизведения фильма – зачастую это единственный способ, если требуется точный отсчет времени.
В следующем упражнении мы с вами, используя функцию getTimer(), создадим таймер-будильник.
Примечание Функцию getTimer() можно найти в списке инструментов панели Действия в разделе Functions.
- Откройте файл makeMyDay2.fla из папки Lesson15/Assets.
Мы продолжаем работу над проектом, начатым в предыдущем упражнении. Напомним, что в этом файле имеется две сцены, Alarm и Messages. Как и в предыдущем упражнении, сейчас мы будем работать только со сценой Alarm, только на сей раз сосредоточимся на правой половине экрана. Здесь, в правом верхнем углу, имеется три текстовых поля: minutesToAlarm, secondsToAlarm и numberOfLoops (сверху вниз). Это текстовые поля для ввода; первые два предназначены для установки времени, по прошествии которого должен сработать будильник, третье будет определять, сколько раз будильник должен прозвонить.
Ниже этих текстовых полей находится кнопка Start, которой будет запускаться таймер/будильник.
Под этой кнопкой расположен экземпляр фильма-символа под названием clock, содержащий движущиеся элементы (подобно настоящему секундомеру). Давайте познакомимся с ним поближе.
- Двойным щелчком на экземпляре клипа clock откройте его для редактирования на месте.
Монтажный стол этого клипа состоит из двух слоев: слой Clock содержит общее графическое оформление, а в слое Hands находится три экземпляра клипов, представляющих элементы циферблата. Один из этих экземпляров, secondHand, представляет секундную стрелку часов; она будет вращаться при запущенном таймере. Непосредственно под этим экземпляром находится второй экземпляр – minuteHand; это будет минутная стрелка. Третий экземпляр клипа выглядит как маленькая красная метка в верхней части циферблата. Этот экземпляр называется alarmHand, эта метка переместится на сколько-то делений после установки и запуска таймера.
- Вернитесь на основной монтажный стол. Откройте панель Действия, выделите кнопку Start и введите следующий скрипт:
on (release) { clock.alarmOn = true; clock.startingTime = getTimer(); }
Когда эта кнопка будет нажата и отпущена, будут присвоены значения двум переменным в экземпляре клипа clock. Как вы вскоре увидите, то, что переменная alarmOn получила значение true, будет знаком к "включению" скрипта, присоединенного к этому экземпляру. Переменная startingTime получает возвращенное функцией getTimer() значение, равное числу миллисекунд, прошедших с момента запуска фильма. Фиксация точного времени запуска таймера – важнейший момент для этой части нашего проекта, и сейчас вы в этом убедитесь.
- Выделите экземпляр клипа clock и введите в панели Действия следующий скрипт:
onClipEvent (enterFrame) { if (alarmOn) { } }
В этом скрипте условный оператор проверяет значение переменной alarmOn каждый раз, когда происходит событие enterFrame. Как вы помните, на предыдущем шаге мы запрограммировали, что при нажатии на кнопку Start эта переменная получает значение true. На нескольких следующих шагах мы добавим действия в этот условный оператор, и действия эти будут выполняться только в том случае, если alarmOn равно true. Действия будут перемещать стрелки часов и подавать сигнал в нужный момент. Таким образом, кнопка Start запускает таймер.
- Внутрь условного оператора вставьте следующую строку:
totalTimeToAlarm = (Number(_root.minutesToAlarm.text) * 60) + Number(_root.secondsToAlarm.text);
Вы помните, что в нашей сцене имеется одно текстовое поле для ввода минут, и другое – для ввода секунд. Оба они нам понадобятся, чтобы определить, через какой промежуток времени должен сработать будильник. Во введенной нами строке общее время получается так: число минут, введенное в соответствующее поле, умножая на 60, превращаем в число секунд, а то, что получилось, прибавляем к числу секунд, введенное в другое поле.
(Number(_root.minutesToAlarm.text * 60)) складываем с (Number(_root.secondsToAlarm.text)) и получаем значение totalTimeToAlarm.
В обеих частях выражения мы применили функцию Number() – ради уверенности, что значения minutesToAlarm.text и secondsToAlarm.text будут восприниматься как числовые, а не строковые. Сейчас мы поясним, почему это необходимо. Возьмем пример. Предположим, пользователь ввел в текстовое поле minutesToAlarm число 5, а в текстовое поле secondsToAlarm – число 37. С этими значениями наше выражение будет выглядеть так:
(Number("5") * 60) + Number("37")
Как видите, введенные значения изначально трактуются как строковые, а в этом случае у нас не получилось бы никаких математических вычислений. Однако с помощью функции Number() мы преобразуем эти значения в числовые, и выражения принимает такой вид:
(5 * 60) + 37
Примечание Значение свойства text текстового поля всегда считается строкой, поэтому для математических операций следует преобразовывать их в числа.
В минуте 60 секунд, поэтому введенное число минут мы умножаем на 60. В нашем примере получится 300. Это число мы прибавляем к введенному числу секунд, и получаем 337 (секунд) – это значение и присваивается переменной totalTimeToAlarm. В дальнейшем мы будем сравнивать с этим значением число секунд, прошедших с момента запуска таймера. Как только число прошедших секунд превысит это значение, скрипт будет знать, что пора включать звуковой сигнал.
Совет Наш таймер мог бы прекрасно работать в том случае, если бы мы установили значение totalTimeToAlarm единожды, однако мы поместили эту строку скрипта в обработчик события enterFrame, и значит, значение этой переменной может обновляться, если надо, 24 раза в секунду (частота кадров в нашем фильме). Это дает пользователю возможность динамически менять настройку таймера (вводить другое число минут и секунд), даже если таймер уже запущен, и значение totalTimeToAlarm будет при этом автоматически обновляться.
- Сразу после строки скрипта, добавленной на предыдущем шаге, добавьте следующую строку:
secondsElapsed = Math.round((getTimer() – startingTime) / 1000);
Для нас очень важно отслеживать время, прошедшее с момента, когда пользователь нажал кнопку Start и активировал таймер. Это и делает данная строка скрипта. Вычисления производятся следующим порядком:
Текущее время, полученное с помощью функции getTimer() (проверяется 24 раза в секунду, поскольку эта строка скрипта выполняется обработчиком события enterFrame ), вычитается из значения переменной startingTime:
getTimer() – startingTime
Как вы помните, переменная startingTime содержит время, прошедшее от начала фильма до нажатия кнопки Start. Постоянно проверяя текущее время и сравнивая его с этим значением, скрипт определяет, сколько прошло от нажатия кнопки Start до текущего момента. Эта часть выражения дает результат в миллисекундах, ну, например, 29349. Разделив это число на 1000 (следующая часть выражения),
/ 1000
Мы получаем число прошедших секунд – 29,349. Последняя часть выражения округляет это значение до целого числа:
Math.round()
В конце концов, переменной secondsElapsed присваивается значение 29. Следует помнить, что это значение будет увеличиваться при каждом выполнении скрипта (ведь время идет). При этом увеличение будет происходить только в целых числах – 29, 30, 31 и так далее. Новое значение мы будем получать каждую 1/24 секунды – именно с такой частотой будет выполняться эта строка скрипта.
Итак, у нас есть две переменные, необходимые для остальных действий данного скрипта.
- Сразу после предыдущей строки скрипта добавьте следующую:
alarmHand._rotation = totalTimeToAlarm / 10;
Как вы помните, alarmHand – это имя экземпляра клипа – красной метки внутри экземпляра клипа clock, показывающей на циферблате часов момент срабатывания сигнала. Эта строка скрипта поворачивает alarmHand, устанавливая в нужное положение. Например, если сигнал должен прозвучать через 20 минут, alarmHand необходимо повернуть так, чтобы красная метка оказалась напротив 20-минутной отметки на циферблате. Посмотрим, каким же образом это получается.
Полный круг составляет 360 градусов. Наш циферблат разделен на 60 минутных отметок, отсюда мы получаем, что одной минуте соответствует поворот на 6 градусов (6 x 60 = 360). Таким образом, чтобы установить метку на 20-минутную отметку, необходимо повернуть экземпляр клипа alarmHand на 120 градусов (6 градусов в минуту x 20 минут). Выражение, присваивающее значение переменной totalTimeToAlarm (шаг 5) пересчитывает 20 минут в 1200 секунд. Теперь мы делим это число на 10, и получаем 120 – именно на столько градусов нам нужно повернуть alarmHand, чтобы отметить 20 минут.
- Сразу после предыдущей строки скрипта добавьте следующие строки:
secondHand._rotation = secondsElapsed * 6; minuteHand._rotation = secondsElapsed / 10;
Эти две строки вращают экземпляры клипов secondHand и minuteHand, основываясь на постоянно обновляющемся значении secondsElapsed. Логика здесь та же, что и на предыдущем шаге – круг состоит из 360 градусов, наш циферблат имеет 60 делений, по 6 градусов на каждую минуту или секунду. За каждую прошедшую секунду секундная стрелка должна переместиться на 6 градусов. Поэтому первое действие добавленного нами скрипта поворачивает экземпляр клипа secondHand на значение secondsElapsed, умноженное на 6. Таким образом, через одну секунду он повернется на 6 градусов, через две – на 12, и так далее, создавая эффект движения секундной стрелки на настоящих часах. С минутной стрелкой дело обстоит несколько иначе. Минутная стрелка на часах проходит 1/60 того пути, что прошла секундная. Например, за 60 секунд секундная стрелка проходит полный круг. Минутная стрелка к этому моменту должна пройти по циферблату только 6 градусов, указывая, что прошла одна минута. Поэтому второе действие в нашем скрипте поворачивает экземпляр клипа minuteHand на значение secondsElapsed, деленное на 10. Так, если прошло 60 секунд, это выражение даст результат 6 – на столько градусов и переместится minuteHand.
- Сразу после предыдущей строки скрипта добавьте условный оператор:
if (secondsElapsed == totalTimeToAlarm) { activateAlarm(); }
Этот условный оператор, выполняемый 24 раза в секунду (как и прочие действия этого скрипта), сравнивает значение secondsElapsed со значением totalTimeToAlarm. Если эти значения равны – значит, пора подавать звуковой сигнал, и оператор выполняет соответствующее действие. Действие это заключается в вызове функции activateAlarm(). Функцию мы сейчас опишем.
- В самый конец текущего скрипта добавьте следующее:
onClipEvent(load) { function activateAlarm() { alarmOn = false; secondHand._rotation = 0; minuteHand._rotation = 0; alarmHand._rotation = 0; alarmSound = new Sound(); alarmSound.attachSound("annoying"); alarmSound.start(0, _root.numberOfLoops.text); } }
Этим скриптом, сразу после загрузки экземпляра клипа clock, будет описана функция activateAlarm(). Функция первым делом присваивает alarmOn значение false. Тем самым будет "отключен" скрипт, связанный с событием enterFrame, и таймер остановится. Три следующих действия функции возвращают все стрелки часов на нулевую отметку. После этого создается новый объект Sound под именем alarmSound. Этот объект будет представлять собой, как вы понимаете, сигнал будильника. Следующее действие присоединяет к созданному объекту Sound файл звукозаписи из библиотеки, который называется "annoying". Последним действием, с помощью метода start(), запускается воспроизведение звука. Первый параметр определяет, с какой секунды звукозаписи должно начаться воспроизведение, второй параметр – сколько раз следует повторить звукозапись. Мы хотим воспроизводить звукозапись с самого начала, поэтому в качестве первого параметра указываем 0. Значение второго параметра будет зависеть от числа, которое ввел пользователь в текстовое поле numberOfLoops на основном монтажном столе.
- Командой Управление > Проверить фильм (Control > Test Movie) запустите тест проекта.
Когда фильм запустится, введите в текстовые поля для таймера соответствующие числа и нажмите кнопку Start. Часовые стрелки придут в действие. Когда наступит время подачи сигнала, таймер остановится, стрелки встанут на ноль, и раздастся звуковой сигнал, который будет повторяться столько раз, сколько вы указали в поле numberOfLoops.
- Закройте тестовый фильм и сохраните ваш проект под именем makeMyDay3.fla.
Вы убедились, что функция getTimer() играет важнейшую роль там, где требуется точный отсчет и измерение времени.
Мы продолжим работу над этим проектом в следующем упражнении.