Аналоговые часы
Исходный файл: Simpleclock.fla, Betterclock.fla
Одной из возможностей использования ActionScnpt является ние даты и текущего времени на компьютере пользователя. Это осуществляется благодаря объекту Date. Этот объект может использоваться различными способами, простейшим из них является создание анимированных аналоговых часов.
Другие возможности
Вы можете внести изменения в код списка ответов. Совсем необязательно придерживаться используемой в нашем примере модели "да/ нет/не знаю". Ваши вопросы и ответы могут касаться определенной темы, например, выиграет ли сегодня местная спортивная команда или какой будет погода.
Сценарий, рассматриваемый в данном разделе, выполняется независимо дизайна музыкального автомата. Ваше устройство может быть похоже на напольный музыкальный автомат или совсем не походить на него. Вы даже можете создать музыкальный автомат с многочисленными экранами, представляющими различные группы песен. Кнопки "Forward" (Вперед) и "Back" (Назад) используются для перехода от кадра одной песни к кадру другой песни.
В качестве стрелок часов вы можете использовать любой объект. Это могут быть простые линии или созданное вами изображение. Вы также можете украсить часы числами или фоновыми рисунками.
Еще одной интересной возможностью будет создание часов, стрелки которых двигаются в обратном направлении. Такие часы можно иногда встретить в магазинах и ресторанах. Вы также можете добавить звук, который будет воспроизводиться каждый час или каждые 15 минут.
Изображение стекла было создано аналогично пузырькам. Благодаря применению свойства альфа-прозрачности сквозь него видны пузырьки Для того чтобы ролик вписывался в ваш сайт или проект, вы можете украсить его своим логотипом.
Дополнительно вы можете добавить в игру кнопки для загрузки каких-то уже существующих колоний. Это избавит вас от необходимости каждый раз создавать их заново.
Игрушки и безделушки.
Волшебный хрустальный шар
Музыкальный автомат
Аналоговые часы
Лавовая лампа
Игра "Жизнь"
Игра "Жизнь"
Исходный файл: gameoflife.fla
Игра "Жизнь" известна как результат серьезных разработок в области искусственного интеллекта и одновременно как популярная игра. Она была изобретена математиком Джоном Конвэйем и приобрела известность благодаря опубликованной в 1970 году статье в журнале "Scientific American". Вскоре после этого игра стала чрезвычайно популярной среди программистов.
Выглядит все очень просто — в ячейки сетки на игровом поле помещается произвольный набор точек. На очередном шаге игры содержание каждой ячейки сетки подвергается преобразованиям согласно определенному набору правил. Если данная ячейка содержит точку и в прилегающих к ней ячейках находится две или три точки, то содержимое данной ячейки остается без изменений. Если в прилегающих ячейках содержится меньше двух точек, то точка в данной ячейке "умирает" от одиночества, а если больше трех, то точка "умирает" от тесноты. Если же данная ячейка пуста и в прилегающих ячейках содержится ровно три точки, то в данной ячейке "рождается" новая точка.
Вот и все правила, которые вам нужны. Результаты могут оказаться удивительными. Попробуйте запустить исходный файл. Создайте колонию точек подобно изображенным на рис. 6.15 и нажмите кнопку Run.
Использование объекта Date
Объект Date можно представить как небольшой массив, содержащий некоторую информацию о текущем моменте времени. При создании объекта Date за основу берется текущее время, установленное на компьютере пользователя.
Не стоит полагаться на точность времени, установленного на компьютере пользователя. Вы удивитесь тому, сколько людей имеют неточные часы. Тем не менее я обычно не задумываясь использую эти часы, особенно для игр. Если неправильно указано время отправки электронного письма, это может привести к проблемам, для flash-ролика точность времени не так важна.
Объект Date включает следующие элементы: число, месяц, год, часы, минуты и секунды. Для вывода любого из них необходимо использовать соответствуюшую функцию: getDate (). Приводимая ниже программа обработки содержит все функции, которые используются для получения информации из объекта Date:
on (release) {
now = new Date();
trace("toString:" + now.toString());
trace("getDate:" + now.getDate());
trace("getDay:" + now.getDay());
trace("getFullYear:" + now.getFullYear());
trace("getHours:" + now.getHours());
trace("getMilliseconds:" + now.getMilliseconds());
trace("getMinutes:" + now.getMinutes());
trace("getMonth:" + now.getMonth());
trace(getSeconds:" + now.getSeconds());
trace("getTime:" + now.getTime());
trace("getTimezoneOffset:" + now.getTimezoneOffset ());
trace("getYear:" + now.getYear());
trace("getUTCDate:" + now.getUTCDate());
trace("getUTCDay:" + now.getUTCDay());
trace("getUTCFullYear:" + now.getUTCFullYear());
trace("getUTCHours:" + now.getUTCHoursO);
trace("getUTCMilliseconds:" + now.getUTCMilliseconds());
trace("getUTCMinutes:" + now.getUTCMinutes());
trace("getUTCMonth:" + now.getUTCMonth());
trace("getUTCSeconds:" + now.getUTCSeconds());
Следует обратить внимание на несколько моментов. Все функции UTC подразумевают, что система пользователя настроена на соответствующую временную зону. Для того чтобы получить всеобщее (по Гринвичу) время, необходимо добавить или вычесть определенное количество часов. Результатом выполнения функции getTime будет количество миллисекунд с 1 января 1970 года. Функция day обозначает день недели и задается числом от 0 до 6. Месяц представляет собой число от 0 до 11. Число выбирается из диапазона от 1 до 31. Возможно, все это трудно для понимания и запоминания, однако данные функции аналогичным образом задаются и в других языках программирования, например С и JavaScript.
Вот результат выполнения всех функций trace:
toString:Sat Oct 14 18:47:06 GMT-0600 2000
getDate:14
getDay:6
getFullYear:2000
getHours:18
getMilliseconds:0
getMinutes:44
getMonth:9
getSeconds:7 getTime:971570647000
getTimezoneOffset: 360
getYear:100
getUTCDate:15
getUTCDay:0
getUTCFullYear:2000
getUTCHours:0
getUTCMilliseconds:0
getUTCMinutes:44
getUTCMonth:9
getUTCSeconds:7
Вы можете задать любой элемент объекта Date. Каждая функция, начинаюшаяся с get, имеет соответствующую ей функцию, начинающуюся с set. К примеру, для установки часа используется функция setHour (newHour) Имейте в виду, что это приведет к изменению только объекта Date, которому вы обратились, а не системных часов пользователя. При создании нового объекта Date время в нем будет установлено в соответствии системными часами.
К сведению
Кроме рассмотренных функций в сценарии кадра имеется код, вызывающий функцию creatGrid, и команда stop (). Возможна также другая реализация. Дело в том, что игра нуждается в получении определенных данных для запуска. Ведь если вы нажмете кнопку Run при пустом игровом поле, то ничего не произойдет. Поиграйте с колонией, изображенной на рис 6.15. Ее называют "маленький взрыв". Программисты, впервые реализовавшие игру "Жизнь", придумали имена некоторым таким "цивилизациям".
Попробуйте создать свои колонии или поищите в Интернете уже существующие. Поиск по ключу "game of life" откроет вам множество страниц с самыми разнообразными конфигурациями.
В конце анимации вы можете поместить команду stop (), чтобы воспроизведение ролика не повторялось, а также другую кнопку, которая ocyществит возврат ролика к кадру 1 в случае, если пользователь захочет задать еще один вопрос.
Лавовая лампа
Исходный файл: Lavalamp.fla
Этот ролик воссоздает классическую лавовую лампу. На компьютерах и в сети можно увидеть множество подобных объектов. Многие из них представляют собой простые Flash-анимации, создаваемые без написания кода.
Но в этом случае после окончания анимации узор повторяется, а интереснее сделать такую лавовую лампу, узор которой в каждый момент был бы разным.
Подготовка ролика
После того как вы поместили 10 экземпляров клипа на рабочее поле и присвоите песням имена в первом кадре главной временной шкалы, осталось добавить звук.
Прежде всего, импортируем 10 песен в библиотеку ролика и присвоим им имена, начиная с "song1" и заканчивая "song10". После импорта каждого звукового файла необходимо изменить его свойство связи таким образом, чтобы он был включен в создаваемый .swf-файл. Для каждой песни требуется создать идентификатор и поставить флажок напротив свойства Export for ActionScript. Соответствующее диалоговое окно показано на рис. 6.8. Его можно вызвать из меню Options окна Library.
Рисунок 6.8 Диалоговое окно Symbol Linkage Properties позволяет включать звуки в swf-файл, даже если их нет в главной временной шкале
К сожалению, во Rash нет возможности использования внешних звуковых файлов. Единственным способом создать подобный музыкальный автомат будет импорт всех песен и включение их в swf-файл. Будем надеяться, что в следующих версиях программы появится возможность доступа к внешним звуковым файлам и их воспроизведения
При помоши объекта Date можно создать интересные часы. Переводя значения часов, минут и секунд текущего времени в градусы, вы можете задать параметр „rotation трех различных клипов таким образом, чтобы они двигались, как стрелки часов.
На рис. 6.10 показан внешний вид таких часов. Короткая рука обозначает часовую, длинная - минутную, а хвост - секундную стрелки.
Рисунок 6.10 Часы показывают 1 час 45 минут и 10 секунд
На рисунке не видно, что руки (и хвост) часов двигаются подобно стрелкам настоящих часов. Эти действия выполняются в три этапа. Вначале полученное значение текущего времени помешается в переменные hour, minute и second. Затем значения этих переменных преобразуются в значения углов. Далее полученные значения используются для задания параметра _rotation трех клипов, представляющих руки и хвост.
Создание ролика Lava Lamp требует особой тщательности. Например, пузырьки представляют собой круги без границы и с радиальной заливкой между непрозрачным и прозрачным красным цветом. Прозрачный красный цвет получается в результате установки свойства alpha в значение 0%. На рис. 6.14 изображен клип, а также панели Fill (Заливка) и Mixer (Миксер), при помощи которых можно задать градиент красного цвета.
Рисунок 6.14 В панели Fill можно задать градиентную заливку цветом. Панель Mixer позволяет задавать значение прозрачности
Сначала рассмотрим, как выполняется анимация. Ролик состоит из двух частей. Первая представляет собой статический кадр, который выглядит, как показано на рис. 6.1. Ролик будет запущен после щелчка по хрустальному шару.
Единственным необходимым элементом в этом ролике является команда stopO, помещаемая в любой слой. На рис. 6.2. показана главная временная шкала ролика. Строчная буква "а" в первом кадре второго слоя (слоя "Text") обозначает, что этому кадру назначен код ActionScript, в данном случае команда stop ().
Рисунок 6.2 Главная временная шкала содержит полную анимацию хрустального шара
Устройство главной временной шкалы зависит от фантазии аниматора. В рассматриваемом примере изображение лисы состоит из основного слоя и одного слоя для каждой руки. Изображение шара также включает несколько слоев.
Особое внимание следует обратить на то, как анимация развертывается во времени. Первый кадр представляет собой статический кадр без анимации, он содержит текст (см. рис./6.1) и невидимую кнопку, которая помешается поверх хрустального шара.
Кнопка создается следующим образом: создайте новую кнопку, при помощи любой цветной области (например, зеленого прямоугольника) придайте ей нужную форму и поместите в один из верхних слоев главной временной шкалы. На данном этапе кнопка будет видна (рис. 6.3).
Рисунок 6.3 В первом кадре ролика видно изображение кнопки над хрустальным шаром
Нам необходимо, чтобы кнопка была активной и в тоже время скрытой от пользователя. Для этого в панели Properties выберите эффект Alpa и установите значение прозрачности 0% (рис. 6.4). Можно просто заполнить в кнопке только кадр Hit, тогда она также будет не видна пользователю, но активна.
Рисунок 6.4 В панели Properties можно установить значение параметра Alpha в 0%, тем самым делая элемент невидимы
Эффект Alpha назван по аналогии с термином "alpha channel" (альфа-канал), который используется для описания изображений. Считается, что графическое изображение состоит из четырех каналов: красного, зеленого, синего и альфа. Первые три канала определяют цвет пикселов, последний - их прозрачность. Если значение альфа-канала равно 0, изображение совершенно прозрачно. Поэтому при установке свойства Alpha в значение 0 flash-элемент станет невидимым.
Подготовка ролика В дополнение
Функция cycle является центральным моментом нашей программы. Она используется для вычисления правил применительно к каждой ячеке. Обратите внимание, что мы дублируем массив grid. Это делается для того, чтобы при изменении значения какого-нибудь элемента массива grid это не повлияло на дальнейшие вычисления на данном шаге программы. Все вычисления происходят опираясь на значения элементов массива baseGrid.
function cycle() {
// Дублируем массив grid. var baseGrid = duplicateGrid();
// Делаем проход по всем ячейкам,
for(y=0;y
for(x=0;x
thisBox = baseGrid[y][x];
mc = this["gridbox "+x+" "+y];
// Вычисляем количество "заселенных" ячеек вокруг
// данной.
n = 0;
n += baseGrid[y-1][x-1];
n += baseGrid[y-1][x];
n += baseGrid[y-1][x+1];
n += baseGrid[y][x-1];
n += baseGrid[y][x+1];
n += baseGrid[y+1][x-1];
n += baseGrid[y+1][x];
n += baseGrid[y+1][x+1];
// Если в этой ячейке уже была точка и если количество
// "жильцов" вокруг равно 2 или 3, то точка остается, .
if (thisBox) {
if ((n == 2) or (n == 3)) {
newValue = true;
} else {
newValue = false;
}
// Новая точка "рождается", если ячейка была пуста
//и если в смежных ячейках находится ровно 3 точки.
} else {
if (n == 3) {
newValue = true;
} else {
newValue = false;
}
}
// Меняем текущий кадр клипа mc.
grid[y][x] = newValue;
if (newValue) {
mc.gotoAndStop(2);
} else {
mc.gotoAndStop(1);
}
}
}
}
Функция duplicateGrid() создает копию массива grid и возвращает ее в качестве своего значения.
function duplicateGrid() {
var newGrid = new Array();
for(y=0;y
var temp = new Array();
for(x=0;x
temp.push(grid[y][x]);
}
newGrid.push(temp);
}
return(newGrid);
}
Да, но почему мы должны пользоваться функцией duplicateGrid(), вместо того чтобы просто приравнять массив baseGrid массиву grid? Потому что иначе у нас не было бы реальной копии массива. Вместо этого и grid и baseGrid ссылались бы на один и тоже массив и изменения в массиве grid появлялись бы и в массиве baseGrid.
Клип "actions" содержит обработчик onClipEvent (enterFrame), который вызывает функцию runCicle при каждом обращении к кадру. Эта функция проверяет глобальную переменную running и запускает сусle, если ее значение истинно (true).
function runCycle() {
if (running) {
cycle();
}
}
Рассмотрим теперь сценарии кнопок. Каждая кнопка содержит обработчик вида on (release), который вызывает одну из следующих функций. Первая (кнопка Run) задает глобальной переменной running значение true.
function startCycle() {
running = true;
}
Если же пользователь нажмет кнопку Step, то функция cycle будет вызвана лишь один раз и переменная running не изменит своего значения.
function stepCycle() {
cycle();
}
При нажатии кнопки Stop переменной running присваивается значение false.
function stopCycle() {
running = false;
}
И наконец, нажатие кнопки Clear очищает массив grid и все ячейки сетки
function clear() {
for(y=0;y
for(x=0;x
grid[y][x] = 0;
this["gridbox "+x+" "+y].gotoAndStop(1);
}
}
running = false;
}
Осталось только рассмотреть код, который находится на кнопке внутри каждого клипа-ячейки. Этот сценарий определяет состояние ячейки. В функции creatGrid мы определили переменные х и у для каждого клипа. Это позволяет установить соответствие между ячейками и элементами массива и вносить изменения в массив при изменении состояния ячейки.
on (release) {
if (_currentframe == 1) {
gotoAndStop(2);
_parent.grid[y][x] = true;
} else {
gotoAndStop(l);
_parent.grid[y][x] = false;
}
}
Подход
Прежде чем создавать часы, необходимо научиться работать с объектом Date. Именно он содержит текущее время, доступное для отображения
Для создания лавовой лампы, работающей по принципу случайности (рис. 6.13), необходимо использовать ActionScript. Вначале необходимо создать 20 клипов, представляющих пузырьки лавовой лампы. Затем надо задать постоянный вызов функции, перемещающей пузырьки вверх и вниз по экрану.
Рисунок 6.13 Объект "лавовая лампа " состоит из дна, крышки, внутренней части из прозрачного стекла и красных пузырьков
Ролик начинается с создания сетки, состоящей из клипов (ячеек). Также создается двумерный массив булевых переменных. Каждый элемент массива соответствует определенной ячейке и указывает, в каком кадре находится этот клип-ячейка ( то есть находится ли в данной ячейке "жилец").
Основная функция ролика просматривает все ячейки и вычисляет изменения в них. Выполнение этой функции представляет собой один шаг игры. Если пользователь нажимает кнопку Run, ролик выполняет эти шаги непрерывно. При выборе кнопки Step исполняется только один шаг.
Наиболее сложной задачей в данном ролике является создание изображений и анимации. Сценарий же довольно прост.
Создание подобного ролика, содержащего 10 различных кнопок, с 10 различными кодами, предназначенными для воспроизведения 10 различных песен, является интересной задачей. Ролик будет работать, однако его сложно создать и еше сложнее изменить.
Наиболее простым способом будет создать одну кнопку и использовать ее 10 раз, один раз для каждой песни. Каждая кнопка будет представлять собой клип, содержащий одну и ту же кнопку. Таким образом, в библиотеке ролика окажется всего один клип и одна кнопка. Этот клип будет помешен на рабочее поле 10 раз, все его копии будут идентичны. Первое действие при запуске ролика - изменение текста каждой копии клипа. Это действие описывается при помощи следующего кода:
// Задаем названия песен.
this["1"].text = "Song Name 1";
this["2"].text = "Song Name 2";
this["3"].text = "Song Name 3";
this["4"].text = "Song Name 4";
this["5"].text = "Song Name 5";
this["6"].text = "Song Name 6";
this["7"].text = "Song Name 7";
this["8"].text = "Song Name 8";
this["9"].text = "Song Name 9";
this["10"].text = "Song Name 10";
Для того чтобы упростить задачу, клипам присвоены имена от " 1" до "10". В результате выполнения вышеприведенного кода все копии клипа будут отображать разные названия песен. Поэтому, несмотря на то, что в библиотеке содержится один клип, все его копии будут выглядеть по-разному.
Более того, названия всех 10 песен будут включены в один сценарий Если бы каждый клип содержал, название одной песни, вам пришлось бы проделать немало работы, открывая и закрывая каждый из 10 клипов для внесения в него изменений. Данный сценарий дает возможность быстро изменить все названия песен.
Свести количество клипов к одному помогает и код, назначенный кнопке внутри клипа:
on (release) {
_root.playSong (this._name);
}
Эта строка кода отправляет одно из имен клипа от "1" до "10" в функцию playSong, находящуюся на корневом уровне (уровне рабочего поля). Эта часть кода может выполняться в любом клипе, так как в каждом случае использует различное имя экземпляра клипа. Если при создании нового экземпляра клипа вы не забыли назначить ему новое имя, значение переменной this._name будет каждый раз иным.
Данный код позволяет использовать одну копию клипа необходимое число раз. В случае внесения в клип каких-либо графических или функциональных изменений вам придется сделать это всего единожды. Кроме того, конечный .swf-файл будет меньше файла, библиотека которого содержит 10 копий аналогичных клипов.
Создание кода
В сущности «волшебство» данного ролика создается в сценарии Action Script кнопки. Как было сказано выше, сценарий задает переход ролика ко второму кадру и запускает анимацию. Это фактически последнее важное событие. Перед этим генерируется ответ, который помешается в текстовую область.
Так как ответ активизируется щелчком по кнопке, весь код необходимо поместить в сценарий, назначенный кнопке. Такой сценарий всегда начинается с оператора on, далее следует описание реакции на событие. Одним из часто используемых событий является событие release (нажатие кнопки).
Вначале сценарий создает массив и заполняет его списком ответов. Для этого существует множество способов. Один из них приведен ниже:
responses = new Array("Yes", "No", "Ask again later","It is certain", "Doubtful", "Probably", "The answer is unclear","Of course not!", "Certainly!", "It looks positive", "It looks negative");
Это наиболее короткий способ создания массива и его одновременного заполнения. Однако он выглядит немного беспорядочно, так как текст переносится с одной строки на другую. Приведем другой способ:
responses = new Array();
responses[0]("Yes");
responses[1]("No");
responses[2]("Ask again later");
responses[3]("It is certain");
responses[4]("Doubtful");
responses[5]("Probably");
responses[6]("The answer is unclear");
responses[7]("Of course not!");
responses[8]("Certainly!");
responses[9]("It looks positive");
responses[10]("It looks negative");
Этот способ является более аккуратным, в нем каждый ответ располагается на отдельной строке. Вы можете сразу увидеть, из каких элементов он состоит. Однако здесь вам придется в каждой строке вводить номер элемента в скобках. В случае ошибки вы можете пропустить очередной ответ или оставить место пустым. Поэтому лучше пользоваться третьим способом:
Код, задающий воспроизведение звукового файла, несложный, но и не такой простой, как можно было бы ожидать. Вместо одной команды воспроизведения звука вам придется записать три строки: первая создает звуковой объект, вторая соотносит звуковой файл из библиотеки объектом, третья задает воспроизведение звукового файла.
song = new Sound();
song.attachSound("song1") ;
song.start();
Функция playSong должна выполнять еще несколько действий. Прежде всего, останавливать воспроизведение предыдущей песни. Это осуществляется при помощи команды stop. Предположим, что предыдущая песня содержится в глобальной переменной song и воспроизводится в данный момент. Приведем простой вариант функции:
function playSong(songnum){
// Останавливаем воспроизведение предыдущей песни,
song.stop();
// Проигрываем новую песню,
song = new Sound ();
song.attachSoundt "song"+songnum);
song.start();
}
Осталось добавить еще один специальный эффект - подсвечивание названия выбранной песни. Клип каждого выбираемого элемента содержит два кадра: без подсветки и с подсветкой. На рис. 6.9 изображение музыкальный автомат с подсветкой выбранного элемента.
Перед запуском воспроизведения каждой песни необходимо y6eдиться в том, что подсветка всех песен выключена, а затем включить подсветку только выбранной песни:
function playSong(songnum) {
// Останавливаем воспроизведение предыдущей песни.
song.stop();
// Убираем подсветку.
for(i=1;i
this[i].gotoAndStop(1);
}
// Проигрываем новую песню,
song = new Sound();
song.attachSound("song"+songnum);
song.start();
this[songnum].gotoAndStop(2);
}
Рисунок 6.9 Музыкальный автомат воспроизводит песню под номером 2
Код, который выполняет все вышеописанные действия, - это cценарий onClipEvent (enterFrame), помещаемый в клип. Код можно посмотреть в файле Simpleclock.fla.
onClipEvent (enterFrame) {
// Узнаем текущее время.
now = new Date();
hour = now.getHours();
minute = now.getMinutes();
second = now.getSeconds();
// Конвертируем в значение для 12-часового дня.
if (hour > 12) {
hour -= 12;
}
// Рассчитываем углы для поворота стрелок.
hourAngle = 360*hour/12;
minuteAngle = 360*minute/60
secondAngle = 360*second/60;
/// Поворачиваем сами ролики
_root["hour hand"]._rotation = hourAngle;
_root["minute hand"]._rotation = minuteAngle;
_root["second hand"]._rotation = secondAngle;
}
Чтобы определить значение углов, значение времени делится на наибольшее возможное значение и умножается на 360. Например, значение минут делится на 60, в результате чего получается значение между 0 и 1, а затем умножается на 360, что дает значение угла между 0° и 360°. Чтобы стрелка была 12-, а не 24-часовой, из значения часов вычитается 12.
Результатом каждой операции является угол от 0° до 360°. 0° обозначает 0 (или 12) часов, 0 минут, 0 секунд. В данном случае изображения всех трех клипов, представляющих стрелки часов, будут указывать вверх (рис. 6.11). Затем, после задания параметра „rotation, стрелки будут указывать на соответствующее место.
Рисунок 6.11 Руки и хвост (то есть стрелки часов), направленные четко вверх, соответствуют 12:00:00. Когда вы зададите параметр _rotation, стрелки будут указывать в соответствующем направлении
Проблема состоит в том, что устройство будет работать не совсем как обычные часы. Например, на рис. 6.10 часовая стрелка указывает на 9 часов. Она будет продолжать указывать на отметку 9, даже когда будет 9:59, а затем в 10:00 сразу передвинется на отметку 10. В настоящих часах часовая стрелка будет в течение часа постепенно передвигаться, пока не достигнет отметки 10 в 10 часов. Для того чтобы получить такой результат, необходимо немного увеличивать угол часовой стрелки каждую минуту и угол минутной стрелки каждую секунду, Приведем соответствующий код:
Lava Lamp использует 20 экземпляров клипа, созданных из одного библиотечного эталона. С помощью команды attachMovie копии клипа добавляются в ролик. Более подробно о команде attachMovie рассказано в главе 5, раздел "Эффект трехмерности".
При запуске ролика в первом и единственном кадре временной шкалы выполняется функция initLamp. При этом помимо 20 клипов пузырьков будет создан массив объектов, которые определяют скорость движения каждого пузырька.
Кроме того, верхняя и нижняя части лампы будут непрозрачными, из-за чего здесь пузырьки не будут видны. Поверх клипов пузырьков будет помешено изображение полупрозрачного стекла.
При использовании команд attachMovie или duplicateMovieClip необходимо указать уровень нового клипа. Уровень определяет порядок перекрывания клипов. Все новые клипы будут помешены перед существующими. Это значит, что пузырьки будут располагаться перед изображениями верхней, нижней и прозрачной частей лавовой лампы. С помощью команды duplicateMovieClip вы можете создать новые копии этих трех изображений, которые будут помешены поверх пузырьков.
Приведем код функции initLamp:
function initLamp () {
// Инициализируем переменные, обозначающие верхнюю и нижнюю
// координаты лавовой лампы по оси Y.
top = 0;
bottom = 300;
// Создаем экземпляры клипа, содержащего пузырек.
numBubbles = 20;
for (i=0; i<numBubbles; i++) {
attachMovie("bubble", "Bubble"+i, i);
}
// Дублируем изображения стекла, низа и верха лампы, чтобы // они оказались над пузырьками.
duplicateMovieClip("Glass", "Glass", i + +);
duplicateMovieClip("Top", "Top", i++);
duplicateMovieClip("Bottom", "Bottom", i++);
// Создаем объекты, содержащие значение скорости пузырьков.
bubbles = new Array();
for (i=0; i
bubbles[i] = {speed:0};
}
}
После того как все элементы подготовлены, воспроизведение ролика осуществляется по следующему принципу: время от времени вызывается функция, которая обновляет местоположение пузырьков и создает новые. Клип, расположенный за пределами рабочего поля, вызывает функцию moveBubbles в каждом событии enter Frame.
Функция moveBubbles задает перемещение пузырьков вверх или вниз и их остановку в верхней или нижней части ролика, а также в одном случае из 30 вызывает функцию newBubble для создания нового пузырька.
Волшебный хрустальный шар
Исходный файл:
Crystalball.fla
Наверное, самой распространенной интерактивной программой, которую можно встретить в Internet, является программа-предсказатель, работаюшая на основе случайных чисел. Обычно она называется "Маеgic Eight Balls" (Восемь волшебных шаров), по имени популярной игрушки Tyco.
На рис. 6.1 показано, как может выглядеть подобная игра.
Рисунок 6.1 Лиса ответит на ваш вопрос : после того, как вы щелкните по хрустальному шар
После щелчка по шару лиса
После щелчка по шару лиса помашет лапами и пользователь получит ответ, который будет выбран наугад из списка.
Создание музыкального автомата - наглядный способ продемонстрировать, как используется звук во Flash. Это обычный ролик, воспроизводящий несколько песен.
Интерфейс программы изображен на рис. 6.7. Такой музыкальный автомат может содержать до 10 различных песен. Песня воспроизводится после щелчка по ее названию в списке.
Рисунок 6.7 Виртуальный музыкальный автомат напоминает устройство, которое можно было встретить в 50-е годы в любой закусочной
В данном разделе мы создадим лавовую лампу, функционирующую по принципу случайности. Это значит, что код случайным образом определяет, когда и где появляются новые пузырьки. В результате узор никогда не будет повторяться.
Время, запрограммированное в компьютере пользователя, должно отображаться в виде настенных или наручных часов. Часы должны иметь часовую, минутную и секундную стрелки. Лучше сделать часы необычными и в качестве стрелок использовать не простые линии, а какой-нибудь клип.
Программа создает сетку, заполняющую экран. Каждая ячейка может содержать или не содержать точку. Щелкнув по ячейке, пользователь может изменить ее состояние.
Рисунок 6.15 В игре "Жизнь" живут и умирают маленькие красные точки
Когда пользователь завершает наполнение ячеек, он нажимает кнопку начала игры. При каждом проигрывании кадра применяется к каждой ячейке описанный набор правил. В результате наполнение некоторых ячеек меняется.
Пользователь может нажать кнопку Stop для остановки игры. Имеются также кнопка пошагового исполнения алгоритма (Step) и кнопка очистки игрового поля (Clear).
Альбом для рисования
Исходный файл: Drawing-line.fla, Drawing-fill.fla
Хотя предыдущие два примера используют ваши творческие способности, в действительности они не дают возможности создавать что-либо новое. Теперь давайте рассмотрим программу для рисования, работа в которой начинается с чистого листа и которая позволяет пользователю изображать все, что угодно, и распечатывать результат.
Добавление кнопок Clear и Print
Чтобы очистить рабочую область, мы просто нарисуем сверху заполненный цветом области прямоугольник. Это выполняется с помощью сценария кнопки Clear (Очистить).
Мы устанавливаем толщину линии 0. Затем перемещаем указатель в верхний левый угол нашей области и рисуем прямоугольник, который точно ее повторяет и определяет область заливки. Цвет заливки - белый, так как именно он выбран фоновым в нашем ролике.
on (release) {
// Толщина линии - ноль.
_roou.lineStyle(0,OxFFFFFF,100);
// Перемещаем указатель в верхний левый угол.
_root.moveTo(actions.xmin,act ions.ymin);
// Создаем область заливки.
_root.beginFill(OxFFFFFF);
_root.lineTo(actions.xmax,actions.ymin);
_root.lineTo(actions.xmax,actions.ymax);
_root.lineTo(actions.xmin,actions.ymax);
_root.lineTo(actions.xmin,actions.ymin);
_root.endFill();
}
Еше легче создать кнопку Print (Печать). Для этого необходимо добавить команду print. Осталось еше присвоить метку "#р" единственному кадру ролика.
on (release) {
// Распечатываем клип
print(_root,"bframe");
}
Команда print выводит заданный клип на печать. Добавив к команде слева _root, вы можете напечатать все содержимое рабочего поля. Второй параметр определяет границы области печати. Подробности вы найдете в руководстве пользователя Flash.
Рисунок 7.7 Изображение примера использования ролика.
Другие возможности
Подобная программа может применяться почти к любому объекту. Таким объектом, например, может быть машина, в которой пользователь может изменять колеса и другие детали, или лицо с различными вариантами глаз, носа, ушей, волос и т. д.
Вы можете усовершенствовать программу, добавив возможность выбора толщины линии по аналогии с цветами. Можно создать кнопку, которая будет определять переменную lineSize в клипе "actions". Добавив в палитру белый цвет, вы дадите пользователю возможность стирать уже нарисованное.
Вы можете легко заменить имеющиеся звуки любыми другими. Просто удалите старые звуки из библиотеки и импортируйте на их место ваши собственные. Не забудьте произвести настройку диалогового окна Symbol Linkage Properties.
Вы также имеете возможность изменять количество звуков, например, уменьшать количество циклов барабанного боя и увеличивать количество отдельных звуков. Звуков может быть сколько угодно, главное, чтобы имена копий клипов совпадали с именами соответствующих звуков библиотеки.
Ничто не мешает вам изменить анимацию любого переключателя, Обладая достаточным количеством времени, вы можете отказаться от идеи повторно используемых клипов и создать свой клип для каждого переключателя. Но имейте в виду, что это усложнит вашу задачу, если вы захотите потом как-то еще изменить ролик.
В файле примера лиса, выполнив один раз выбранное пользователем движение, возвращается к основному танцу. Вы можете изменить программу таким образом, чтобы лиса повторяла выбранное движение до тех пор, пока пользователь не выберет новое. Этого можно достичь возвращением каждой последовательности кадров, отвечающей за определенное движение, к своей собственной метке вместо "danceO". В таком случае вам может понадобиться отдельная кнопка в кадре "record" для возвращения лисы к ее основному танцу.
Игрушки-конструкторы.
Составь лису методом "Перетащи и положи"
Создай лису методом "Нажми и измени"
Альбом для рисования
Музыкальный миксер
Танцующая лиса
К сведению
He забудьте присвоить каждой из 18 кнопок уникальное имя и сопоставить это имя с именем соответствующего звука в библиотеке. Кроме того,название звука необходимо задать в диалоговом окне Symbol Linkage Properties (рис. 7.9).
То, какой будет анимация каждого типа кнопки, решаете вы. В нашем примере кнопки барабанного боя мигают, изменяя свой цвет с белого на черный и обратно, кнопки басов и отдельных звуков увеличиваются. Чтобы обеспечить непрерывное воспроизведение, в последний кадр циклов барабанного боя и басов необходимо вставить команду gotoAndPlay (2). Клипы отдельных звуков после окончания своего воспроизведения должны возвращаться к кадру 1. Первый кадр этих звуков должен содержать команду stop О для того, чтобы их воспроизведение запускалось при первой загрузке ролика.
Три кнопки в кадре "record", инициирующие танец, должны содержать сценарии для вызова функции danceButton. Вот пример для одной из кнопок:
on (press) {
danceButton("dance1");
}
В кнопке Done должен содержаться сценарий для вызова функции stopRecord.
on (press) {
stopRecord();
}
Клип "actions" в кадре "playback" содержит код, вызывающий функцию danceFrame при каждом обращении к этому кадру.
onClipEvent(enterFrame) {
_root.danceFrame();
}
Следует также назначить команду gotoAndstop каждой из кнопок главного меню. В первый кадр главной временной шкалы поместите команду stop(), чтобы остановить анимацию в начальный момент времени.
Для того чтобы закончить создание ролика Makeafox-switch.fla, следует обратить внимание еще на несколько деталей. Во-первых, каждый первый кадр клипа должен содержать команду stop(). Это поможет избежать безостановочного воспроизведения всех вариантов клипа при первом запуске ролика. Затем каждый клип должен быть помещен на рабочее поле и назван, как соответствующий элемент списка в коде.
Не забудьте поместить команду stop() в первый кадр клипа, содержащего кнопку, включающую режим заливки. Вы можете создать намного больше кнопок для предоставления пользователю большого количества цветов для рисования.
Музыкальный миксер
Исходный файл: Musicmixer.fla
Flash позволяет работать не только с графическими объектами. Вы, например, можете воспроизводить одновременно несколько звуков, создавая музыкальный коктейль. При этом пользователь получит право выбирать любой музыкальный отрезок и время его воспроизведения.
Подготовка ролика
Для создания игрушки-конструктора, работающей по методу drag-and-drop, прежде всего необходимо иметь различные графические изображения. На рис. 7.1 в правой части изображено туловище, в левой - различные изображения рук, ног, ртов и глаз.
Рисунок 7.1 Изображенные слева части тела можно переместить к расположенному справа туловищу
Ролик можно запустить, открыв файл Makeafox-drag.fla. Вы можете выбрать любую часть тела и переместить ее в любую часть экрана.
Основными элементами ролика являются 18 звуков. В примере MUSICmixer.fla использовались звуки, созданные профессиональным композитором. Вам придется сочинить звуки самому, привлечь к этому друга или коллегу или позаимствовать музыку из любых других источников.
Циклы барабанного боя и басов состоят из коротких звуков, создающих законченные музыкальные фразы. Они должны быть короткими, чтобы не перегружать файл, но достаточными для того, чтобы создать интересный звук.
После импорта 18 звуков во Flash в диалоговом окне Symbol Linkage Properties (рис. 7.9) необходимо установить свойство Export for ActionScript, а также задать идентификатор.
Рисунок 7.9 Настройки диалогового окна Symbol Linkage Properties определяют, каким образом звук будет включен во Flash-ролик
Необходимо создать три различных типа кнопок. В действительности они представляют собой не кнопки, а клипы. Поэтому, чтобы избежать путаницы, мы назовем их "переключателями". Переключатели содержат невидимые кнопки, реагирующие на щелчок мыши. Они состоят как минимум из двух кадров. Первый из них соответствует выключенному состоянию переключателя, остальные - включенному. Так как звуки барабанов и басов представляют собой повторяющиеся циклы, анимация этих двух переключателей воспроизводится непрерывно, пока не будет прекращена повторным щелчком мыши. В отличие от этого анимация переключателя отдельного звука воспроизводится один раз и затем возвращается к состоянию "выключено". Состав анимационных последовательностей вы можете просмотреть в файле Musicmixer.fla.
Кнопки в переключателях - это простые белые фигуры, которые помешаются за другими графическими изображениями, чтобы их не было видно. В примере для переключателей барабанов и басов используется небольшая круглая кнопка, для переключателей отдельных звуков - треугольная. Чтобы было проще размещать кнопки за графическими объектами, создано только два типа изображений кнопок. Шесть копий каждого переключателя помешены на рабочее поле. Их расположение может быть любым (рис. 7.8).
Мы должны сделать клип "dance" правильно. В исходном файле он представляет последовательность из 20 кадров, которая разбита на четыре части по 5 кадров. Каждая часть начинается с кадра, имеющего метку, например "dance0". Последний кадр в каждой последовательности не i держит изображения, но содержит команду gotoAndPlay("dance0") Таким образом, когда данная последовательность движений заканчивается, лиса возвращается к повторению последовательности dance0 (основное движение танца). Остальные три метки кадров называются "dance1", "dance2" и "dance3".
Последний кадр каждой танцевальной последовательности содержит только сценарий. Это сделано потому, что, когда выполняется команда gotoAndPlay (), содержимое кадра не отображается.
Основная временная шкала ролика содержит три кадра. Первый кадр помечен как "menu" (меню) и содержит команду stop(). Второй кадр имеет метку "record"(запись) и третий — "р1ауЬаск" (воспроизведение). Ниже мы рассмотрим код для этих трех кадров.
В кадре "menu" содержится две кнопки: Record и Playback. Я использовал один символ из библиотеки как образец для создания кнопок, но поместил на них различный текст. Каждая из этих кнопок совершает переход на соответствующий кадр.
В кадре "record" содержится четыре кнопки. Три из них включают в танец соответствующее движение, и четвертая прерывает процесс записи.
Наконец, кадр "playback" содержит единственную кнопку, останавливающую воспроизведение.
Подход
Программа должна распознавать нажатие и отпускание кнопки мыши. Она должна определять, над каким клипом находится в данный момент курсор, и предоставлять возможность перетаскивания выбранного клипа при нажатой кнопке мыши.
Это не так легко, как кажется. Для того чтобы определить, какой клип выбрал пользователь, необходимо сравнить позицию курсора мыши с областью, занимаемой каждым клипом.
Библиотека данного ролика имеет не такую, как мы рассматривали раньше, организацию. Вместо отдельных изображений каждого варианта элемента лисы используются клипы. Каждый клип содержит все варианты данного элемента, по одному в кадре. Например, клип "Eyes" ("Глаза") будет стоять из трех кадров, каждый из которых содержит другое изображение глаз.
В приложении используется шесть циклов барабанного боя, шесть циклов басов и шесть отдельных звуковых эффектов. Одновременно может играть только один "барабанный" цикл, поэтому при выборе второго цикла необходимо отменить первый. Басы могут воспроизводиться одновременно. Отдельные звуки воспроизводятся один раз.
В ролике используется три различных набора переключателей. Первый предназначен для выбора цикла барабанного боя. При включении одного из них предыдущий автоматически отключается. Второй набор переключателей используется для одновременного включения одного, нескольких или всех циклов басов. Повторный щелчок по включение кнопке барабанного боя или басов приведет к ее отключению.
Третий набор кнопок предназначен для воспроизведения отдельных звуков. Они включаются только на время воспроизведения звука. В отличие от циклов барабанного боя или басов, которые воспроизводятся непрерывно, повторное воспроизведение отдельного звука можно запустить, только еще раз щелкнув по соответствующей кнопке.
Центральным объектом этой программы является клип "dance". Он содержит всю последовательность танца лисы. Вы можете управлять лисой, перемещаясь к кадру, с которого начинается последовательность, составляющая данное танцевальное па.
Первым делом программа отмечает начало процесса записи. При нажатии кнопки программа фиксирует время нажатия и название движения. Информация помешается в массив объектов следующего формата: {время: значение, движение: значение}.
В начале процесса воспроизведения также отмечается текущее время. Затем программа все время проверяет, не пора ли лисе совершить первое из записанных движений, то, которое является первым элементом массива. Когда этот момент времени проходит, начинается ожидание второго момента времени, и т.д. Специальное танцевальное движение stop используется, чтобы обозначить окончание времени записи. Когда воспроизведение доходит до команды stop, ролик возвращается в главное меню.
Составь лису методом "Перетащи и положи"
Исходный файл: Makeafox-drag.fla
Многие компьютерные игры созданы по подобию игрушек докомпьютерной эры. Одна из таких старых игрушек - "Mister Potato Head" (Господин картофельная голова). Она представляла собой набор пластиковых частей тела которые ребенок мог прикрепить к картошке и сделать смешного человечка. Позже вместо картошки стали использовать пластиковое туловище.
Создание кода
Если вы уже работали во Flash, вы можете подумать, что это легко - необходимо просто использовать клипы частей тела и команды startDrag, и stopDrag. На самом деле такой подход только все усложнит. Я не любитель команды startDrag и не буду использовать ее здесь, поскольку перемешать с ее помощью элементы по рабочему полю не так уж и просто.
Представив каждую часть тела в виде кнопки, вы можете назначить ей обработчик события on (press) и применить команду startDrag. Однако кнопка не может служить в качестве цели команды startDrag, такой целью может быть только клип. Если же вы представите их в виде клипов, им нельзя будет назначить функцию on (press), так как она используется только с кнопками. Еще одним вариантом является представление каждой части тела как клипа с кнопкой внутри. Здесь можно легко запутаться, так как каждый раз при добавлении в ролик новой части вам придется выполнить несколько действий.
Лучшим выходом будет написать код, выполняющий процедуру drag-ard-drop самостоятельно. Отдельным частям не будет назначено никакого кода, благодаря чему их будет легко создавать и добавлять новые.
Весь код поместим в клип "actions", который как обычно находится вне, пределов рабочей области и содержит только надпись "Actions".
Данному клипу назначен сценарий ActionScript, управляющий перемещением всех элементов. Он должен включать несколько функций onClipEvent. Ниже приведено краткое описание событий и реакций на них, которые сценарий должен выполнять:
• load (загрузить) - задание переменной, указывающей, что никакого перемещения еще не происходит;
• mouseDown (кнопка мыши нажата) - определение выбранного элемента и создание переменной, сообщающей, что этот элемент перетаскивается. Определение смешения между местом, над которым нажата кнопка мыши, и центром выбранного элемента;
• mouseUp (кнопка мыши отпущена) - установка начальных параметров переменной, указывающих, что никакой элемент в данный момент не перетаскивается;
• enterFrame (проигрывание кадра) - изменение положения перемещаемого элемента соответственно движению курсора минус разница между координатами центра элемента и координатами точки, по которой щелкнул пользователь.
Здесь не применяется перетаскивание, поэтому сценарий будет немного проще. Код представляет собой сценарий onClipEvent (mouseDown) помешенный в клип "actions", который расположен за пределами рабочего поля клипа. Как и функция hitTest в ролике Makeafox-drag.fla, данный сценарий проверяет, какой клип выбран.
Однако вместо имен "Part1" - "Part 13" клипы получают значащие имена (например, "Eyes" и "Head"). Сценарий должен проверить каждый клип, для чего все клипы собраны в общий список.
При нахождении соответствующего клипа код продвигается на один кадр вперед. Если впереди кадров больше нет, он возвращается к кадру 1.
onClipEvent (mouseDown) {
// Определяем, в каком месте щелкнул пользователь
x = _root._xmouse;
y = _root._ymouse;
// Выясняем, по какому элементу произведен щелчок
list = ["Eyes", "Mouth", "Head", "Legs", "Left Arm", "Right Arm", "Body"];
for(i=0;i
if (_root[list[i]].hitTest(x, y, true)) {
// Меняем выбранный элемент
with (_root[list[i]]) {
// Переходим к следующему кадру
if (_currentFrame == _totalframes) {
gotoAndStop(1);
} else {
nextFrame();
}
}
break;
}
}
}
Номер кадра и обшее количество кадров определяется при помощи параметров _currentFrame и _totalFrame. Это очень удобно в случае, когда клипы могут включать любое количество кадров, а код -учитывать все возможные варианты.
Конструкция with указывает, что все команды и функции кода в рамках этой конструкции должны выполняться для определенного клипа. Это позволит вам обойтись без добавления _root [movieclip] в начале каждой команды или функции.
Ролик Makeafox-switch.fla можно увидеть на Web-сайте. На рис. 7.4 показан один из возможных вариантов, получившихся в результате внесенных изменений. Независимо от того, сколько раз и в какой последовательности пользователь щелкает по элементам изображения, оно всегда будет оставаться цельным.
Рисунок 7.4 Пользователь может щелкнуть по любой части тела и изменить ее
Код назначен кнопкам, которые размешены внутри переключателей. Первый кадр каждого переключателя содержит код для запуска воспроизведения звука. Помимо этого код задает переход клипа к следующему кадру. Кнопка присутствует во всех кадрах клипа. Различные сценарии используются для остановки звука в цикле барабанов и цикле басов.
Самый простой сценарий - у переключателей отдельных звуков. Задача данного сценария - запустить воспроизведение звука и задать его переход к следующему кадру.
on (press) {
// Указываем, что надо проиграть из библиотеки звук
// соответствующий выбранному клипу.
instanceSound = new Sound(),
instanceSound.attachSound(this._name);
instanceSound.start();
// Начинаем анимацию, показывающую, что кнопка выбрана.
gotoAndPlay(2);
}
}
Обратите внимание, что имя звука описывается при помощи синтаксиса this._name. Это значит, что имя клипа будет являться и именем звука Если клип называется "instance 1", код попытается воспроизвести звук с именем "instance 1". Первое имя "instance 1" соответствует имени клипа на рабочем поле, второе имя "instance 1" является именем соответствующего звука в библиотеке. Эта схема работает только в том случае, если имена полностью совпадают.
Преимущество данного способа заключается в том, что один и тот же клип может использоваться на рабочем поле для воспроизведения различных звуков. Имя звука берется из имени копии клипа, а не из переменной ActionScript, что делает такой клип более универсальным.
Анимация начинается после перехода клипа к следующему кадру. В конце анимации клип возвращается к первому кадру, а находящаяся в нем команда stop () остановит его повторное воспроизведение.
В случае отдельных звуков одна и та же кнопка находится во всех кадрax, что дает пользователю возможность запустить воспроизведение нового звука даже во время воспроизведения анимации клипа.
Клипы для басов и отдельных звуков аналогичны. Основное их различие состоит в том, что первый звук должен периодически повторяться. Для этого в команду start требуется добавить два параметра: смещение от начала звука и количество циклов. В нашем случае смешение не нужно следовательно, оставим его значение равным 0. Периодическое повторение звука необходимо, поэтому соответствующий параметр должен иметь очень большое значение.
Рассмотрим сценарий кадра "record". Он начинается с инициализации массива и определения времени начала записи.
// Определяем массив.
danceArray = new Array();
// Считываем текущее время.
startTime = getTimer();
Функция danceButton вызывается одной из трех кнопок, расположенных внизу экрана. Они определяют время и название танцевального движения и помещают эту информацию в массив. Они также дают команду клипу "fox" (его библиотечное имя - "dance") к исполнению движения.
// Пользователь нажимает одну из "танцевальных" кнопок,
function danceButton(moveName) {
// Промежуток времени, прошедший с начала проигрывания.
thisTime = getTimer() - startTime;
// Помещаем временной интервал и название движения в массив.
danceArray.push({time: thisTime, move: moveName});
// Показываем движение,
fox.gotoAndPlay(moveName);
}
Когда пользователь нажмет кнопку Done, движение "stop" будет помещено в массив и ролик перейдет к кадру "menu".
// Нажимаем кнопку Done.
function stopRecordO {
// Вычисляем временной интервал.
thisTime = getTimerO - startTime;
// Добавляем в массив.
danceArray.push({time: thisTime, move: "stop"});
// Возвращаемся в главное меню.
gotoAndStop("menu");
}
Рассмотрим сценарий кадра "playback". Он начинается с определения времени начала воспроизведения и присваивания переменной dance-step значения 0. Эта переменная содержит номер следующего в очереди танцевального па.
// Определяем время.
startTime = getTimer();
// Начинаем с шага 0.
danceStep =0;
Клип "actions" вызывает функцию danceFrame, которая проверяет состояние последовательности танцевальных движений. Она вычисляет текущее время и сравнивает его со временем запуска следующего движения.
Когда это время наступает, функция проверяет, не является ли это движение командой stop. Если это так, то последовательность завершается. В противном случае клип "fox" переходит на соответствующий кадр, и переменная danceStер увеличивает свое значение на единицу.
// Вызывается при каждом обращении к кадру
// из клипа "actions".
function danceFrame() {
// Вычисляем время.
thisTime = getTimer() - startTime;
// Проверяем момент запуска следующего движения, if (thisTime >= danceArray[danceStep].time) {
// Определяем движение.
move = danceArray [danceStep] .move;
// Если это "stop", возвращаемся в кадр "menu",
if (move == "stop") {
gotoAndstop("menu");
} else {
// В противном случае отображаем движение танца.
fox.gotoAndPlay(move);
// Увеличиваем переменную.
danceStep++;
}
}
}
Создание полной программы рисования
Хотя предыдущая программа демонстрирует продвинутые возможности ActionScript, результат ее работы не очень-то интересен. В программу можно добавить другие фигуры и цвета, а также возможность выводить на печать результаты рисования.
Второй параметр функции lineStyle отвечает за выбор цвета. В предыдущем примере был выбран черный цвет — 0x000000. Префикс Ох сообщает программе, что следующее за ним число надо воспринимать в шестнадцатеричном формате, так же, как это происходит при HTML-верстке. Шесть последних цифр обозначают собственно цвет. Также можно использовать значение цвета, получаемое вызовом функции getRGB. В ролике Drawing-fill.fla я использовал несколько разноцветных кнопок. Каждая из этих кнопок представляет собой клип с кнопкой внутри.
На рис. 7.6 показан вид исходного файла Drawing-fill.fla. Слева расположены кнопки, с помощью которых пользователь может управлять цветом.
Рисунок 7.6 Кнопки в левой части экрана дают пользователю возможность выбрать цвет и фигур
Каждая из этих кнопок создана из одного библиотечного эталона. Когда копия помешается на рабочее поле, можно настроить ее цвет с помощью меню color на панели Properties. Внутри клипа находится кнопка, чтобы отслеживать выбор пользователя. Ниже приведен сценарий кнопки. Значение цвета кнопки помещается в переменную brushcolor. Ее значение затем передается переменной linecolor в клип "actions".
on (release) {
// Определяем цвет.
myColor = new Color(this);
brushColor = myColor.getRGB();
// Передаем значение переменной linecolor клипа "actions"
_root.actions.lineColor = brushColor;
// Определяем позицию рамки.
_root["Color Selection"]._x = this._x;
_root["Color Selection"]._y = this._y;
}
Сценарий кнопки устанавливает координаты клипа "Color Selection", то есть рамки, равными координатам клипа, по которому щелкнул пользователь. При этом вокруг кнопки с выбранным цветом появится контур (рис. 7.6.)
Маленькая кнопка с кружочком посередине служит для выбора режима рисования - с заливкой или без. Клип с этой кнопкой состоит из двух кадров: с пустым и заполненным кружочком. Кнопка содержит сценарий, позволяющий переключаться между кадрами, и определяет переменную fill клипа "actions".
on (release) {
if (_currentFrame ==1) {
gotoAndStop(2);
_root.actions.fill = true;
} else {
gotoAndStop(l);
_root.actions.fill = false;
}
}
С помощью кнопок, определяющих цвета, и кнопки выбора режима (с заливкой/без заливки) пользователь может рисовать разноцветные фигуры. Как и в предыдущем примере, код, необходимый для рисования, содержится в клипе "actions".
Он начинается с определения значения следующих переменных: draw - false, fill - false, linecolor - 0x000000. Также определяются четыре переменные, для которые ограничивают область в которой пользователь может рисовать.
onClipEvent (load) {
// Рисовать или не рисовать?
draw = false;
// Определяем значение fill
fill = false;
// Начальный цвет линии - черный. linecolor = 0x000000;
// Определяем границы области рисования.
хтах = 550;
xmin = 70;
утах = 400;
ymin = 0;
}
При нажатии кнопки мыши курсор начинает оставлять след. Координаты курсора хранятся в переменных х и у. Их значения проверяются, и, если они выходят за фаницы разрешенной области, рисование не происходит.
Переменная linecolor передается функции lineStyle в качестве аргумента, определяющего цвет линии. Если переменная fill имеет значение true, то определяется новый массив. Он содержит координаты всех точек вдоль кривой, которую нарисовал пользователь. Массив состоит из объектов следующего вида: {х: значение, у: значение}. Элементы массива потребуются для создания залитой цветом области.
onClipEvent (mouseDown) {
// Определяем позицию курсора.
х = _root._xmouse;
у = _root . _ymouse;
// Рисуем, если не вышли за границы поля
if ((x>xmin) and (x<xmax) and (y>ymin) and (y<ymax)) {
draw = true;
// Определяем параметры линии.
_root.lineStyle(1,lineColor,100);
_root.moveTo(x,у);
// Если выбран режим заливки, то создаем массив if (fill) {
fillArray = new Array();
fillArray,push({x:x, y:y});
}
}
}
После того как переменной draw присвоено значение true, продолжаем линию до тех пор, пока пользователь не отпустит кнопку мыши. При каждом обращении к кадру переменным х и у присваиваются текущие координаты курсора. Если эти значения выходят за разрешенные границы, переменные х и у переопределяются. Затем используется команда lineTo для отображения очередного сегмента линии. Если выбран режим заливки, то добавляется новый элемент в массив fillArray.
onClipEvent (enterFrame) {
if (draw) {
// Определяем текущую позицию.
x = _root,_xmouse;
у = _root._ymouse;
// Задаем границы области рисования,
if (x < xmin) x = xmin;
if (x > xmax) x = xmax;
if (y < ymin) у = ymin;
if (y > ymax) у = ymax;
// Рисуем линию.
_root.lineTo(x,у);
// Если выбран режим заливки, то запоминаем точку,
if (fill) {
fillArray.push({х:х, y:y});
}
}
}
Когда пользователь отпускает кнопку мыши, переменная draw принимает, значение false, и рисование прекращается. Если при этом выбран режим заливки, то в цикле просматривается массив fillArray и созданная область перерисовывается. При этом также используются команда beginFill и endFill. В результате область заливается цветом linecolor.
onClipEvent (mouseUp) {
if (draw) {
// Прекращаем рисовать.
draw = false;
// Перерисовываем кривую и заливаем
// получившуюся область,
if (fill) {
// Начинаем с первой точки.
_root.moveTo(fillArray[0].x,fiiiArray[0] .у);
// В цикле определяем область для заливки.
_root.beginFill(lineColor);
for(var i=l;i < fillArray.length;i++) {
_root.lineTo(fillArray[i].x,fillArray[i].y);
}
_root.endFill();
}
}
}
Другой способ состоит в том, что вы можете вызвать команду beginFill до того, как пользователь начнет рисовать, и команду endFill - когда он закончит, вместо того чтобы перерисовывать кривую. Но Flash не очень любит использовать заливку при разных обращениях к кадру, и результат может быть хаотичен. Лучше сохранить кривую, а затем перерисовать ее и создать всю заливку в пределах одного обработчика.
Создание простой программы рисования
Конечный ролик позволит пользователю рисовать, используя различные фигуры и цвета, однако для начала дадим ему возможность нарисовать непрерывную линию.
Мы воспользуемся новыми командами для рисования, появившимися в версии MX. Описание этих команд вы можете найти на панели ActionScript (Objects -> Movie -> Movie Clip -> Drawing Methods) или в окне Reference (справка).
Эти команды как бы имитируют движения пользователя, передвигающего мышь. Сначала используем команду line style для определения толщины и цвета будущей линии. Команда moveTo передвигает указатель точки для рисования по экрану; линия при этом не прорисовывается. И наконец, мы используем команду lineTo для рисования линии из текущей позиции в заданную.
Единственным элементом нашего ролика является клип "actions", который содержит весь необходимый код.
Сценарий начинается с присваивания переменной draw значения false. Эта переменная используется, чтобы определить, рисует пользователь или нет. Затем с помощью linestyle мы задаем толщину и цвет.
Третий параметр команды lineStyle определяет прозрачность линии, то есть свойство alpha. Значение 100 соответствует абсолютно непрозрачному объекту, значение 50 делает объект полупрозрачным.
onClipEvent (load) {
// Рисовать или не рисовать?
draw = false;
// Линия шириной в 1 пиксел, черная, непрозрачная
_root.lineStyle(1,0x000000,100);
}
Когда пользователь нажимает кнопку мыши, переменной draw присваивается значение true. Затем команда moveTo перемещает указатель в текущую позицию курсора. Мы используем конструкцию _root для обращения к свойствам _xmouse и _ymouse, т.к. хотим чтобы центр координат был независим от положения клипа "actions".
onClipEvent (mouseDown) {
// Будем рисовать
draw = true;
// Переходим к координатам курсора.
_root.moveTo(_root._xmouse, _root._ymouse);
}
Когда пользователь отпускает кнопку мыши, переменной draw присваивается значение false, и процесс рисования завершается.
onClipEvent (mouseUp) {
// Завершаем рисование.
draw = false;
}
Значение переменной draw проверяется при каждом обращении к кадру. Если оно истинно, то рисуется линия от предыдущей к текущей позиции курсора.
Константы true и false могут использоваться конструкциями if и for в качестве проверки условия выполнения кода. Вы также можете использовать их для отслеживания объектов, которые могут нахолиться только в двух состояниях (вкл/выкл).
onClipEvent (enterFrame) {
if (draw) {
_root.lineTo(_root._xmouse,_root._ymouse);
}
}
Обратите внимание, что все обращения к командам рисования происходят через конструкцию _root. Это делается для того, чтобы линии рисовались в самом ролике, на рабочем поле, а не на рабочей области клипа "actions". Можно создать отдельный клип "canvas " (холст) и рисовать линии в нем. Прорисовываясь, линии автоматически оказываются на самом заднем плане, так что, если в клипе ( или ролике) есть еще какие-то объекты, они будут закрывать линию. Наверное, вам будет удобней рисовать на пустом уровне.
На рис. 7.5 показана кривая, которая получилась в результате нажатия пользователем кнопки мыши и перемещения курсора. Помните, что скорость рисования соответствует частоте смены кадров ролика, поэтому для того, чтобы процесс рисования проходил плавно, это значение должно быть максимальным и равняться 120 калр/с. Готовый ролик вы можете увидеть, загрузив файл Drawing-line.fla.
Рисунок 7.5 Простая программа рисования позволяет нарисовать длинную черную кривую
Танцующая лиса
Исходный файл: Dance.fla
Вы видели, как пользователь может создавать изображения и последовательности звуков. Попробуем теперь создать последовательность анимаций. В этом примере пользователь создает мультик с танцующей лисой. Во время сеанса записи пользователь может выбрать в режиме реального времени движения, которые будет делать лисица. Каждое движение записывается, и потом пользователь может проиграть созданную им последовательность движений.
Рисунок 7.10 Показан фрагмент исходного файла. Лиса находится в процессе танца
Исходное изображение будет полным, но,
Исходное изображение будет полным, но, когда пользователь щелкнет по одному из его элементов, он изменится. Например, пользователь может щелкнуть по глазам и вместо них появится другая пара глаз.
Задача данного раздела - создать программу, в которой пользователь может рисовать, как в простом графическом приложении. Пользователь должен иметь возможность рисовать простые линии и фигуры, а также применять различные цвета.
В данном разделе рассматривается создание игрушки, которая позволяла бы пользователю сочинять свои собственные музыкальные произведения, смешивая звуки барабанного боя, циклы басов и другие отдельные звуковые эффекты. При этом необходимо обеспечить возможность замены файлов, а также предусмотреть обратную связь с пользователем чтобы он видел, какие музыкальные отрезки воспроизводятся. На рис. 7.8 показан интерфейс такого приложения.
Рисунок 7.8 Музыкальный миксер состоит из шести циклов барабанов, шести циклов с басами и шести отдельных звуковых эффектов
Задача этого проекта - создать приложение, которое позволит пользователю присоединять части тела лисы к неподвижному туловищу и так составлять изображение зверька. Метод drag-and drop (перетащи и положи) должен быть знаком всем, кто умеет работать с компьютером.
У этой программы есть два режима: запись и воспроизведение. Сначала пользователь использует режим записи и контролирует поведение лисы в режиме реального времени. Он может включить в танец одно из трех разных движений. В перерывах между выбранными движениями лиса исполняет основной танец.
Для завершения записи пользователь может нажать кнопку Done и вернуться в главное меню. Воспроизведение включается кнопкой Playback, после чего в точности воспроизводится записанная последовательность.
Другие возможности
Приведенный здесь пример - игра для совсем маленьких детей. Тем не менее, используемый в ней принцип может быть использован при создании более совершенных игр.
Детям более старшего возраста подойдет игра, целью которой является нахождение чисел или слов какого-либо одного типа. К примеру, задача игры может состоять в выборе глаголов из имеющихся в наличии слов разных частей речи. Другой вариант - географическая викторина, в которой игроку необходимо выбрать определенные страны или места.
В игру легко внести различные изменения. Заданное количество выстрелов можно заменить таймером. Игра может состоять из уровней: игрок будет переходить на другой уровень, поразив определенное количество лис.
Имейте в виду, что игра дает возможность набирать более 50 очков. Каким образом? В ходе игры лисы начинают появляться друг за другом все быстрее и быстрее. Через некоторое время на экране одновременно будут появляться несколько лис. Когда пути двух лис пересекаются, вы можете убить их одним выстрелом, однако это требует сноровки. Если хотите, отмените данное свойство.
В игре могут использоваться некоторые звуковые эффекты и фоновые звуки. Игра будет более интересной, если добавить отвлекающую внимание анимацию, например пролетающую птицу или ветер, раскачивающий ветви.
Чтобы улучшить игру, я увеличил промежутки времени между появлениями лисы. Сейчас они составляют 2 секунды, а должны быть больше двух минут, чтобы игра стала напоминать "Охоту на оленей". Вы можете даже сделать промежутки случайными, чтобы было еще интереснее.
Вместо того чтобы переключать внимание охотника справа налево, вы можете двигаться по кругу. В некотором отношении это может быть проще. Вам не надо беспокоиться о слоях перспективы, как в этой игре. Вместо этого фон может быть одной неподвижной картинкой. Однако, вы также должны найти способ соединять друг с другом левую и правую половины круговой панорамы. Самый простой способ сделать это - заставить правую сторону повторить полную картину вида рабочего поля слева. Тогда, даже если игрок пытается продвинуться дальше вправо, вы просто повторяете весь путь налево. Потребуется немало терпения и труда, чтобы все получилось гладко, но достичь этого возможно.
Имейте в виду, что клипы, изображающие лис, не обязательно должны быть одинаковыми. Сценарий реагирует только на метки "whack" (удар) и "popup" (выглядывающая лиса), а после 24 кадра еще и на начало анимации выглядывающей лисы. Вы можете использовать несколько клипов, изображающих разных лис. Необходимо лишь убедиться, что они достаточно похожи для того, чтобы код мог их обрабатывать, а также присвоить им соответствующие имена при размещении экземпляров клипов на рабочем поле. Использование различных лис сделает игру интереснее.
Завершение игры может быть задано различными способами. В нашем примере ролик воспроизводится, пока интервал между появлениями лис не будет меньше одной секунды, что соответствует появлению 100 лис. Игра может заканчиваться и после того, как произведено определенное количество щелчков. Ваша игра может состоять из нескольких уровней. Поразив заданное число лис, пользователь переходит к другому уровню.
Игры типа "Найди и нажми".
Найди лису
Поймай лису
Подстрели лису
Охота на лис
К сведению
Игра включает еще два кода кнопок Play, один для окна начала, другой для окна завершения игры. Кроме того, все кадры содержат команду stop () , запрещающую переход ролика к следующему кадру.
Выбор цвета найденных объектов зависит от фона. В нашем примере фон состоит из зеленого, коричневого и голубого цветов, поэтому для пойманных лис мы выбрали красный цвет.
После создания кода необходимо присвоить копиям клипа имена с "fox0" по "fox6", соответствующие их именам в библиотеке. В нашем примере центр всех клипов с изображениями лис совпадает с центром рабочего поля. Это было сделано следующим образом: анимация была добавлена в главную временную шкалу, выделена, скопирована при помощи команды Edit -> Copy Frames (Редактировать ->Копировать кадры) и вставлена в пустой клип.
Все стандартные части предыдущих игр присутствуют и здесь. Есть окно начала игры с кнопкой в нем. Есть два текстовых поля: очки и оставшиеся выстрелы. Курсор невидим и заменен клипом с изображением р ла. Во всех этих случаях используется код как в игре "Подстрели лису*
Найди лису
Исходный файл: Findafox.fla
В игре "Найди лису" игроку показывают изображение, в котором он должен определить местоположение определенных объектов. В данном случае в ролике Findafox.fla местом действия является лес, а объектами, которые ищет игрок, - лисы.
На первый взгляд игра представляется простой, однако основная ее идея в том, чтобы хорошо замаскировать объекты. На рис. 8.1 показан ролик, изображающий семь лис, спрятанных в лесу.
Рисунок 8.1 Сцена включает семь спрятанных лис, которых должен найти игрок
Охота на лис
Исходный файл: Huntafox.fla
Одна из самых устойчиво популярных долгие годы игр - "Охота на оленей". В этой игре вы часами сидите, наблюдая пейзаж, пока не покажется олень, которого можно будет застрелить. Несмотря на то, что продано миллионы копий этой игры, она достаточно простая. Во Flash можно легко сделать что-нибудь в этом роде.
Подготовка ролика
Наиболее сложная часть создания игры - подготовка фона. Наш ролик состоит из девяти слоев, включающих изображения земли, деревьев и других элементов леса. Использование различных слоев необходимо для того, чтобы лисы могли быть спрятаны за некоторыми из них.
Ролик также включает два вида клипов с лисами. В одном лиса показана при помощи тонких линий, чтобы ее можно было спрятать в нарисованном стволе дерева. Другой представляет собой сплошное изображение лисы, которое появляется на заднем плане. Оба клипа приведены на рис. 8.2.
Рисунок 8.2 Два клипа используются, чтобы прятать лис среди деревьев. Каждый из них используется в зависимости от цвета фона позади лисы
На рабочее поле помещено несколько копий каждого клипа. Они расположены в одном из четырех различных слоев. Кроме основного кадра игра содержит окно начала и окно завершения игры. В обоих окнах есть кнопка, позволяющая пользователю начать игру.
Основной код находится в клипе, расположенном за пределами рабочего поля. Код оперирует именами клипов начиная с "fox()" и заканчивая "fox6".
Имеющиеся 18 отверстий в бревне - это 18 копий одного клипа. Первый кадр данного клипа изображает обычное отверстие. Следующим элементом временной шкалы клипа является анимация лисы, ненадолго выглядывающей из отверстия и затем вновь исчезающей. Другая анимационная последовательность изображает попадание в лису и ее исчезновение. Она запускается, если пользователь успел щелкнуть по лисе (рис. 8.5)
Рисунок 8.5 Игрок только что поразил лису
Для того чтобы код мог управлять 18 клипами, им были присвоены имена от "fox0" до "fox17". Необходимо также создать динамическую текстовую область с именем showScore. На рис. 8.6 изображена панель Properties данной текстовой области.
Рисунок 8.6 Текстовая область связывается с переменной showScore в панели Properties
Наиболее сложным является создание клипов. Чтобы лучше понять, о чем пойдет речь в этом разделе, внимательно изучите ролик Shootafox.fla.
В библиотеке вы увидите три клипа: Peeking Fox (Выглядывающая лиса), Running fox (Бегущая лиса) и Swinging fox (Раскачивающаяся лиса). Каждый из этих клипов состоит из одного кадра или короткой анимации лисы, за которой следует короткая анимация, изображающая удивленную лису, обведенную желтым контуром. Первая часть соответствует, движению живой лисы, вторая часть обозначает, что пользователь зверька. Вторая часть начинается с кадра, имеющего метку "hit". Ролик также включает семь клипов с именами "fox()" - "fox6". Эти клипы содержат внутри себя один из вышеописанных клипов, однако теперь, анимация изображает, как лиса движется по игровому полю или выглядывает из-за дерева. Клипы, расположенные внутри каждого из клипов с именами "fox0" - "fox6", содержат метку "fox", благодаря чему код может обращаться к ним. Для того чтобы показать, что лиса поражена, копия клипа "fox", находящегося внутри клипов "fox0" - "fox6", переходит к кадру "hit".
Большое значение имеет распределение слоев. Ролик состоит из 15 слоев, представляющих собой либо элементы обстановки (в данном случае лес), либо самих лис. Это позволяет прятать лис за одними предметами и показывать перед другими. Отдельные слои зарезервированы для клипов "actions" и "cursor".
В качестве курсора используется клип с изображением перекрестия. За кадром 1, в котором находится простое перекрестие, следует небольшая анимация вспышки, запускаемая во время выстрела игрока. Затем клип возвращается к кадру 1, который содержит команду stop ().
Как и остальные ролики, рассматриваемые в данной главе, этот ролик включает начальное окно игры, саму игру и окно завершения игры.
Структура ролика такая же, как и в предыдущем примере. Четыре слоя "Фон", "Кусты", "Холмы" и "Деревья" - шириной примерно в 1200 пикселов центрованы на рабочем поле шириной в 550 пикселов. Слои Кусты" "Холмы" и "Деревья" Содержат по одному клипу в каждом - они называются "bushes", "hills" и "trees" и включают в себя все элементы соответствующего слоя.
Слоев с лисами два. Один слой содержит лис, прячущихся за кустами, а другой - прячущихся за деревьями. Клипы с лисами за деревьями носят имена от "foxO" до "fox6", а клипы с лисами за кустами - от "fox7" до "fox9".
Клипы с лисами такие же, как в игре "Подстрели лису", только лиса остается видимой гораздо дольше. Чтобы лисы могли прятаться за узкими деревьями, в каждом клипе я использовал слои-маски, позволяющие скрыть те части лисы, которые не должны быть видны.
Изображения лис внутри каждого клипа с лисой такие же, как в игре "Подстрели лису". Однако последний кадр анимации попадания отправляет родительский клип назад к его первому кадру. Это означает что, когда вы попадаете в лису, она исчезает сразу же, как заканчивается анимация попадания.
Подход
Может показаться, что эту игру до смешного легко создать. И действительно, игра бы состояла всего из нескольких кнопок, если бы не следующие два условия: во-первых, необходима обратная связь с пользователем, он должен знать, какие объекты найдены; во-вторых, игра должна распознавать, найдены ли все объекты.
Обратную связь можно создать, применив к клипу, содержащему лису, свойство трансформации цвета. Применив соответствующий цвет, вы добьетесь выделения лисы.
Для того чтобы определить, все ли лисы найдены, используется массив истинных и ложных значений. В начале игры массив содержит семь ложных значений. По мере того, как пользователь будет находить лис, значения станут меняться на истинные. Когда все семь значений массива примут значение true, игрок поймет, что нашел всех лис.
Вместо кнопок мы будем использовать клипы. Кроме того, потребуется управляющий клип со сценарием ActionScript, следящим за нажатием кнопки мыши. Когда нажатие будет обнаружено, функция hitTest кода начнет проверку клипов с изображениями лис и определит, какой из них был выбран. Это происходит аналогично определению выбранного клипа в игре "Составь лису', которая описывалась в главе 7.
Каждое отверстие в бревне представляет собой экземпляр одного клипа. Клип изображает либо пустое отверстие, либо анимацию лисы, выглядывающей из этого отверстия.
Другой клип под названием "actions" управляет очередностью и периодичностью воспроизведения клипов. В начале игры лисы будут выглядывать через каждые две секунды. С каждым разом интервал между появлениями лис немного сокращается.
Когда игрок щелкает по экрану, клип "actions" определяет, какая лиса была выбрана. После этого клип воспроизводит другую анимацию, изображающую лису в состоянии легкого шока.
Каждый раз при появлении лисы значение счетчика увеличивается на один пункт. Когда игрок попадает в лису, значение другого счетчика Taк же увеличивается на единицу. Счет отображается следующим образом: количество попаданий в лису, потом знак /, затем количество появлений лисы. Другими словами, значение "5/12" будет обозначать, что игрок поразил 5 лис из 12.
Поскольку рассматриваемая игра была создана на основе игры "Поймай лису", основная часть кода должна быть вам знакома. Тем не менее, в него были внесены некоторые изменения и дополнения.
Первые изменения касаются способа организации клипов, которые должны содержать анимацию движения и одновременно показывать, произошло ли попадание в лису. Для этого необходимо использовать клип внутри клипа. Вложенный клип имеет два состояния: "поражен" и "не поражен". Во внешнем клипе описывается движение лисы.
В игре отслеживается и обшее количество выстрелов, и количество попаданий. Оба числа отображаются на экране. После того как пользователь израсходует все выстрелы, игра завершается.
Еще одно новшество данной игры - использование необычного курсора. Стандартный курсор мыши спрятан, вместо него виден клип, перемещающийся по рабочему полю за курсором (см. нижнюю часть рис. 8.7).
Все, что вы должны сделать по сравнению с предыдущей игрой, - это позволить пользователю перемешаться по большому фоновому изображению из стороны в сторону. Но это не так-то просто. Одни элементы фона ближе к играющему, чем другие. Чтобы у игрока действительно создалось ощущение движения охотника, близкие объекты должны двигаться быстрее дальних.
Чтобы этого добиться, мы разбиваем элементы фона на четыре группы: близко - деревья, подальше - кусты, еще дальше - холмы, затем - небо и земля. Небо и земля остаются неподвижными. А деревья, кусты и холмы движутся в зависимости от того, насколько далеко они от игрока.
Лисы прячутся за деревьями и в кустах. Это значит, что они должны двигаться вместе с этими элементами. Посмотрите на исходный файл Huntafox.fla на сайте, чтобы понять, как это выглядит. Если вы двигаете курсор вправо по рабочему полю, панорама смешается вправо. Видите, как деревья движутся быстрее кустов, а кусты быстрее холмов? Заметьте также, что деревья иногда затеняют кусты. Хорошему игроку нужно совсем немного подвигать панораму, чтобы убить максимально возможное количество лис. На рис. 8.8 показан случай, когда лиса выглядывает за-за дерева.
Рисунок 8.8. Лиса выглядывает из-за дерева
Подстрели лису
Исходный файл: Shootafox.fla
Рассмотрим еще одну игру из серии "Найди и нажми" - игру-тир. Как и в игре "Найди лису", задача пользователя - щелкнуть по объектам на экране. На игру "Поймай лису" она похожа тем, что объекты появляются на экране в произвольных местах и через произвольный интервал времени.
Но в отличие от предыдущих игр, объекты будут двигаться, лиса будет не просто появляться из отверстия, а бегать, поворачиваться или выглядывать из-за дерева. Игрок должен обладать хорошей реакцией, чтобы попасть по лисе до того, как она снова исчезнет.
На рис. 8.7 показана сцена, очень напоминающая сцену игры "Найди лису". Однако теперь лиса не будет ждать, пока игрок обнаружит ее. Рисунок демонстрирует кадр анимации, в которой лиса быстро перебегает из одной части экрана в другую.
Рисунок 8.7 В игре "Подстрели лису" лиса перемешается по игровому полю
Создание кода
При загрузке клипа в нем создается массив found. Следующий код заполняет массив значениями false:
onClipEvent (load) {
// Создаем массив, в который записываем, какие лисы
// найдены.
found = [];
for (i=0; i<7; i++) {
found[i] = false;
}
}
При нажатии кнопки мыши положение курсора сохраняется в переменных х и у. Затем при помощи функции hitTest эти значения соотносятся с координатами клипов лис. Когда совпадение найдено, соответствующее изображение становится красным. Этого достаточно, чтобы изображение спрятанной лисы выделилось из фона. Каждый щелчок мышью запускает проверку массива found на наличие значения false. Это означает, что, по крайней мере, одна лиса еще не найдена. Когда все лисы найдены, клип переходит к следующему кадру:
onClipEvent (mouseDown) {
// Определяем, в каком месте пользователь щелкнул мышью.
х = _root._xmouse;
у = _root._ymouse;
// Проверяем, какое изображение лисы найдено,
for (i=0; i if (_roott"fox"+i],hitTest(x, y, false)) {
// Изменяем цвет лисы.
myColor = new Color(_root["fox"+i]);
myColor.setTransform({rb:128,bb:0,gb:0});
// Запоминаем, что лиса найдена.
found[i] = true;
break;
// Проверяем, все ли лисы найдены.
gameover = true;
for (i=0; i if (found[i] == false) {
// Если хотя бы одна еще не найдена,
// игра не закончена.
gameover = false;
//если пользователь выиграл.
// Заканчиваем игру,
if (gameover) {
_root.gotoAndPlay ("Game Over");
}
}
Команда break используется в цикле for и других для его немедленной остановки. Это удобно, когда по той или иной причине необходимо остановить цикл. В вышеприведенном коде цикл проходит значения от 0 до 6, но может завершиться в случае, если функция hitTest примет значение true.
Весь код данной игры назначен клипу "actions", расположенному за пределами рабочего поля. Он начинается с инициализации всех глобальных переменных. В начале ролика интервал появления лис равен 2 секундам (2000 миллисекундам).
onClipEvent (load) {
// Указываем промежуток времени между появлениями лис.
timeBetweenFoxes = 2000;
// Определяем время до появления следующей лисы.
nextFox = getTimer() + timeBetweenFoxes;
// Инициализируем переменные пораженных и показанных лис.
score = 0;
numFoxes = 0;
}
Функция getTimer () - это своеобразные часы. Функция возвращает количество миллисекунд, прошедших после начала ролика. Значение этих часов постоянно увеличивается, поэтому данную функцию удобно использовать для управления временными интервалами в вашей игре.
Функция onClipEvent (enterFrame) определяет, наступило ли время для появления следующей лисы. Затем она выбирает такое новое отверстие, которое не используется в данный момент. Интервал времени между появлениями лис сокращается на 10 миллисекунд, в результате чего игра с каждым разом все больше ускоряется. Если значение интервала составляет менее 1000 миллисекунд, игра завершается. За 150 секунд пользователь получает 100 возможностей поразить лису.
onClipEvent (enterFrame) {
// Определяем, не пора ли показывать следующую лису,
if (getTimerO >= nextFox) {
// Сокращаем время между показами.
timeBetweenFoxes -= 10;
// Выясняем, не пора ли заканчивать игру,
if (timeBetweenFoxes < 1000) {
_root.gotoAndPlay("End") ;
// Если нет, показываем следующую лису.
} else {
// Увеличиваем счетчик показанных лис.
numFoxes++; _root.showScore = score + "/" + numFoxes;
// Определяем, какая лиса покажется,
while (true) {
fox = Int (Math.Random0*18) ;
if (_root["fox"+fox]._currentFrame == 1) break;
// Выбранная лиса появляется из отверстия.
_root ["fox"+fox].gotoAndPlay ("popup") ;
// Устанавливаем время появления следующей лисы.
nextFox = getTimerO + timeBetweenFoxes;
Как и в предыдущих примерах, основной код назначен клипу "actions". Первая часть кода - функция onClipEvent (load). Клип устанавливает счета на 0 и инициализирует переменную shotsLeft, которой присваивается значение 50. Это позволяет игроку сделать 50 выстрелов и убить как можно больше лис. Переменная shotsLeft используется для отображения счета на экране, а переменная showshotsLeft, связанная с текстовой областью, отображает, сколько выстрелов осталось у игрока.
При помощи функции Mouse.hide () в блоке onClipEvent (load) скрывается курсор мыши.
onClipEvent (load) {
// Задаем время между появлениями лис.
timeBetweenFoxes = 2000;
// Вычисляем, когда должна появиться следующая лиса.
nextFox = getTimer()+timeBetweenFoxes;
// Инициализируем переменную, содержащую количество
// попаданий и число выстрелов.
score = 0;
shotsLeft = 50;
_root.showScore = "Score:"+score;
_root.showShotsLeft = "Shots Left:"+shotsLeft;
// Прячем курсор.
Mouse.hide();
}
Использование объекта Mouse позволяет контролировать видимость курсора, расположенного над рабочим полем ролика. При помощи команды Mouse.hide() вы можете скрыть курсор, при помощи команды Mouse. show () - вновь вывести его на экран. Так как курсор скрыт, его необходимо заменить чем-нибудь, чтобы игрок видел, по какому месту экрана он щелкает. В данном случае клип "cursor" ставится в соответствие положению курсора мыши. В остальном функция onClipEvent (enterFrame) повторяет аналогичную функцию игры "Поймай лису".
onClipEvent (enterFrame) {
// Передвигаем курсор.
_root["cursor"]._x = _root._xmouse;
_root["cursor"]._y = _root._ymouse;
// Проверяем, не пора ли показывать следующую лису
if (getTimer()>=nextFox) {
// Сокращаем время до следующего появления лисы.
timeBetweenFoxes -= 5;
// Проверяем, не завершена ли игра
if (shotsLeft < 1) {
_root.gotoAndPlay("End");
// Если нет, показываем новую лису.
} else {
// Задаем появление новой лисы,
Хотя и клипы и слои отличаются от тех, что использованы в игре "Подстрели лису", основной сценарий этой игры применим и в нашем случае. Это сценарий, назначенный клипу "actions". Необходимо внести только два изменения, и я не буду приводить здесь весь код. Первое изменение состоит в том, что теперь можно выбирать из 10, а не из 7 лисиц, поэтому число внутри функции Math.random должно быть 10.
Второе изменение обращает внимание на положение курсора, так что сцена перемешалась, если пользователь двигает курсор вправо или влево. В этом случае вызывается функция moveScene на корневом уровне. Она принимает значения -1 или 1 в зависимости от направления движения.
// Перемещаем панораму,
if (_root._xmouse < 50) {
_root.moveScene(1);
} else if (_root._xmouse > 500) {
_root.moveScene(-1);
}
Клип "moveScene" находится на главной временной шкале. Этот сценарий начинается с определения нескольких переменных. panAmount отслеживает расстояние, на которое пользователь сдвинулся вправо или влево. Например, если пользователь двигается влево, тогда графика движется вправо и panAmount принимает значение 1. Если он продолжает двигаться в этом направлении, panAmount увеличивается до 2, -, и т.д. Если пользователь движется в противоположном направлении, panAmount принимает значения -1, -2 и так далее.
Поскольку мы не можем нарисовать бесконечно широкую сцену, нам приходится задавать границы панорамирования. Две переменные содержат максимально разрешенное передвижение влево и вправо. Я определил эти границы путем проб и ошибок. Начал я с 50 и увидел, что игрок может доходить до конца деревьев. Тогда я начал пробовать меньшие числа, пока игрок не перестал вылезать за границы сцены.
panLimitLeft = -30;
panLimitRight = 30;
panAmount = 0 ;
Чтобы перемешаться по сцене, сначала проверяется, не превышает ли следующее значение panAmount допустимые границы. Функция работает только в том случае, если следующее значение находится в пределах допустимого.
Потом три клипа - "trees", "bushes" и "hills" - перемещаются в нужном направлении. Деревья перемещаются с коэффициентом (фактически скоростью) 10, кусты - с коэффициентом 5 и холмы - 4. Я подобрал эти значения путем проб и ошибок. По-моему, они создают достаточное ощущение глубины.
Первые 7 лисиц, которые находятся прямо за деревьями, движутся с ними вместе с коэффициентом движения 10. Остальные три лисы перемещаются с коэффициентом 5, поскольку сидят за кустами.
Когда игрок находит лису, он
Когда игрок находит лису, он должен выбрать ее щелчком мыши. Если пользователь сделал правильный выбор, он должен это увидеть. Он также должен знать, какую лису нашел.
После того как все семь лис найдены, игра должна автоматически перейти в новое окно. Это значит, необходимо следить за тем, какие объекты найдены, а какие нет.
Задача игры состоит в том, чтобы отверстие, в котором появляются объекты, выбиралось программой произвольным образом. Лиса может показаться в любом из 18 отверстий и почти сразу же исчезнуть.
На рис. 8.4 показан кадр анимации игры. В то время, когда лиса выглядывает, пользователь должен щелкнуть по ней и получить очки.
Игра ведется на время и счет.
Рисунок 8.4 Одна из лис выглянула из отверстия
За основу данной игры взята игра "Поймай лису". Лисы постоянно бегают из одной части игрового поля в другую. Мы будем использовать три анимационных последовательности: лиса перебегает с места на место, раскачивается под деревом и выглядывает из-за дерева. Каждая анимация используется два или три раза, различные их комбинации составляют семь возможных анимаций, воспроизводящихся во время игры.
С интервалом в две секунды и менее запускается одна из анимационных последовательностей, и игрок получает возможность щелкнуть по лисе. Анимация должна продолжиться, показав перед этим, попал ли игрок в цель.
Игра должна отслеживать количество сделанных выстрелов и количество попаданий, а также задавать ограничение на число произведенных выстрелов. Курсор следует сделать не в виде стрелки, а в виде прицела ружья.
Задача состоит в том, чтобы сделать игру - стрелялку, позволяющую пользователю передвигаться влево и вправо по пространству, большему, чем способно вместить в себя рабочее поле экрана. Мишени возникают в случайное время и в случайных местах, вне зависимости от того, куда сейчас смотрит игрок. Перемещение должно создавать игроку иллюзию пространства, так чтобы близкие объекты двигались быстрее далеких.
Другие возможности
Существует несколько способов усовершенствования этой игры. Вы можете ускорять падение яблок, задать интервал между падениями двух яблок или изменить общее количество бросаемых яблок.
Вы также можете использовать другое изображение лисы и иначе настроить функцию moveapples, увеличивая или уменьшая размер корзины для яблок.
Сообразительный программист наверняка изобразит корзину, наполняющуюся яблоками по мере их попадания, и заставит лису время от времени высыпать собранный урожай в определенном месте экрана. В следующем разделе будет рассмотрена игра, созданная на основе данной, но в ней будут и плохие яблоки, которые нельзя ловить.
Это обучающая игра и, к сожалению, подходит лишь для маленьких детей, еще не выучивших алфавит. Однако вы можете изменить содержимое каждого кадра, содержащего хорошее или плохое яблоко. Одним из вариантов может быть увеличение яблока, для того чтобы на нем могла поместиться более длинная фраза.
Вариантом для детей более старшего возраста могут быть яблоки, включающие глаголы и существительные. Они также могут содержать четные и нечетные числа, числа кратные трем или сокращаемые дроби. Дети еще более старшего возраста могут выбирать страны определенного континента или названия деревьев. Игра может иметь любую тему, главное, чтобы на вопросы можно было дать ответ "верно/неверно".
Так как столкновение замедляет скорость игры, она представляет собой идеальный вариант игры на время. Начало игры можно обозначить при помощи объекта date (см. раздел "Аналоговые часы" в главе 6). Теперь вы будете знать, сколько игроку требуется времени для прохождения игры. На скорость байдарки может влиять не только столкновение со скалой. Соответственно изменив код, вы можете сделать так, чтобы байдарка набирала скорость только при движении вперед. Это сделает игру более захватывающей.
Вы можете создать другой вариант данной игры: попробуйте изменить направление движения объектов, вместо байдарки используйте машину или велосипед, а реку замените дорогой. Получится хорошая игра-гонка
Игра уже достаточно сложна для примера в книге. Однако существует много мелких деталей, которые вы можете добавить, чтобы она стала еще более увлекательной. Например, вы можете изменить холмы фона в клипе и заставить их увеличиваться по мере приближения машины. Это создаст иллюзию, что машина подъезжает к холмам.
Вы можете добавить разные типы бонусов, стоящие разное количество очков. Вы также можете ограничить скорость машины, но ввести бонусы, позволяющие эту скорость увеличить.
Игры типа "Поймай или пропусти".
Поймай яблоко
Поймай хорошее яблоко
Сплав на байдарке
Гонки
Гонки
Исходный файл: Racing.fla
Чтобы сделать из игры "Сплав на байдарке" игру "Гонки", надо просто изменить графику и ничего больше. Замените байдарку на машину. Замените кадры с поворотами, чтобы показывать поворот колес машины, а не поворот байдарки в другом направлении. Замените кадр перевернувшейся лодки на кадр автокатастрофы и т.д.
Однако мы можем использовать похожую технику для создания гоночных игр разных типов. Вместо вида на дорогу сверху мы можем сделать вид с водительского места. Дорога движется к игроку (см. рис 9.9).
Рисунок 9.9 В игре гонки дорога движется по направлению к игроку
К сведению
Вышеприведенный код использует установленный по умолчанию размер рабочего поля для ролика - 550x400. Если вы хотите указать другой размер, необходимо внести соответствующие изменения в код. Вы также можете настроить левую и правую границу игрового поля. Выше приведенный код ограничивает расположение яблок и лисы по вертикали диапазоном между 30 и 520 пикселами, задавая ширину границы, размером 30 пикселов. Вы можете их увеличить или уменьшить.
Для остановки анимации первый кадр клипа лисы должен содержать команду stop (). Не забудьте также вставить команду gotoAndPlay в последний кадр клипа.
Ролик содержит динамическую текстовую область, связанную с переменной score, поэтому отображение счета не составит проблемы.
Полная игра (файл Applecatch.fla), состоит из трех кадров. Первый является кадром начала игры и содержит команду stop(). При помощи соответствующей кнопки осуществляется переход к кадру "Play", в котором происходит основное действие игры. Затем следует кадр "Game Over". В отличие от предыдущих игр, использующих различные сцены, кадры данной игры находятся в одной и той же. Но вы можете использовать вариант и с различными сценами.
Как и в игре "Поймай яблоко" перед и после кадра "play" находятся соответственно кадры "start" и "game over". He забудьте также о текстовой области "score" и других компонентах, упомянутых в разделе "К сведению" для предыдущей игры.
Данная игра содержит два кадра, обозначающих конец игры. Первый кадр имеет метку "lose" и содержит сообщение для игроков, которые столкнулись с большим количеством камней и проиграли игру. Второй кадр, помеченный как "win", содержит сообщение для тех, кто миновал все камни. Кадры отличаются только текстом. Оба кадра содержат кнопку "Play" для перезапуска игры.
Ролик-пример содержит вводный кадр и в нем кнопку начала игры. Третий кадр содержит сообщение "Game over" и не включает в себя клип с бонусом, который содержится только во втором кадре. Это предотвращает получение игроком очков после окончания игры. Я также добавил в ролик-пример фоновый пейзаж.
Подготовка ролика
Фон ролика представляет собой сложное изображение, которое, однако, не играет никакой роли. Активными элементами игры являются только яблоки и лиса. Эталоны этих клипов хранятся в библиотеке, но ни один из них не размешается на рабочем поле. Они создаются при помощи кода по мере необходимости.
Клип, содержащий яблоко, представляет собой статическое изображение. Клип с лисой более сложный. Его первый кадр, помеченный "stand", содержит изображение неподвижной лисы. Второй кадр, "run", представляет собой начало анимации, в которой ноги лисы двигаются. В последнем кадре анимации содержится функция gotoAndPlay, возвращающая клип к кадру "run". В результате мы имеем два варианта поведения клипа с лисой: первый- клип остается в кадре 1; второй запускает анимацию всех кадров, начиная с кадра 2.
Так как и лиса, и яблоки появляются в ролике только после соответствующего запроса кода, в диалоговом окне Linkage properties содержащим их эталонам необходимо назначить свойство "Export for ActionScrip. Яблоко получает идентификатор "apple", лиса - идентификатор "running fox".
Вместо клипа "apples" мы будем использовать клип "rocks". В ролике Riverkayak.fla клип "rocks" состоит из трех кадров. Каждый кадр содержит анимированное изображение, состоящее из другого элемента библиотеки. Хотя каждый камень находится в одном кадре клипа, анимация воспроизводится в графическом элементе. Запустив ролик, вы увидите, что в каждом кадре вокруг камня течет вода.
Клип лисы , ловящей яблоки, будет заменен на клип лисы в байдарке Первый кадр изображает лису в байдарке, повернутой вниз по течению и с веслами над водой. Затем следуют кадры "left" и "right", содержащие изображение повернутой байдарки и одного весла, опущенного в воду. На рис.9.7 изображена лиса, поворачивающая вправо. После этого в кадре 4 запускается анимация "spill", представляющая удар байдарки о камень.
Рисунок 9.7 Второй кадр ролика лисы содержит изображение лисы, поворачивающей вправо
Для того чтобы клипы "rocks" и "fox" были включены в ролик, им аналогично клипам "apples" и "fox" предыдущих игр необходимо присвоить имена в панели Linkage Properties.
Фон и линии, обозначающие границы дороги, - неподвижные элементы. Но для камней и звездообразных меток нужны клипы. Клип центральной линии - это просто линия, но расположенная таким образом, чтобы центральная точка клипа была на вершине линии.
Машина сама по себе нуждается в трех кадрах.- прямое движение, левый и правый повороты, которые используются, чтобы показать, что машина поворачивает.
Клипы камней и бонусных меток должны быть помещены под нижней границей экрана и названы "SideObject" и "bonus". Клип машины следует поместить внизу экрана и назвать "саг". Кроме того, слева находится клип "actions". Во всех четырех клипах содержатся сценарии.
На экране должны быть два динамических текстовых поля: "timeDisplay» и "score". Они оба должны быть привязаны к переменным с такими же именами.
В ролике-примере я обозначил вводный кадр как кадр 1, таким образом, все действие начинается с кадра 2. Есть еше третий кадр с меткой "game over".
Подход
Для управления перемещением лисы используется объект Key. Он определяет, удерживает ли игрок клавишу (со стрелкой "вправо" или "влево"). Для создания объектов-яблок используется функция attachMovie. Яблоки помешаются в произвольные места в верхней части экрана, а затем начинают падать и либо ловятся лисой, либо достигают нижней границы экрана.
После создания яблока значение счетчика timesinceLastapple сбрасывается на 0. При каждом новом обращении к кадру его значение увеличивается. Следующее яблоко создается только тогда, когда счетчик принимает значение 20. Это означает, что яблоко может быть создано только через 20 кадров после появления предыдущего. Скорость падения яблока определяется переменной appleSpeed. Каждый раз при падении яблока переменная увеличивается. Таким образом, чем дольше длится игра, тем быстрее падают яблоки. Клип яблока удаляется либо после попадания в корзину, либо при достижении нижней границы экрана. Для того чтобы определить, попало ли яблоко в корзину, координаты яблока сравниваются с координатами корзины. Для облегчения вычислений центр координат клипа с лисой находится в середине корзинки. На рис. 9.2 показан этот клип (его центр отмечен крестиком).
После сбрасывания определенного количества яблок игра заканчивается. Счетом будет служить количество пойманных яблок, отображаемое в правом верхнем углу экрана.
Рисунок 9.2 Центр координат клипа с лисой находится в середине корзинки
В игре "Поймай яблоко" единственный клип яблока в библиотеке содержал статическое изображение, состоящее из одного кадра. Для показа различных типов яблок нам понадобится два разных клипа, один для хороших яблок, другой для плохих. Кроме этого, каждый клип будет состоять из множества кадров с изображениями различных яблок. Клип хорошего яблока будет состоять из 5 кадров, соответствующих гласным. Клип плохого яблока будет состоять из 20 кадров, представляющих согласные звуки. Буква "Y" использоваться не будет.
Когда наступает время бросать яблоко, оно может с равной степенью вероятности оказаться как хорошим, так и плохим. Код отобразит произвольный кадр из соответствующего клипа.
После того как игрок поймает яблоко, код определит его тип и соответственно изменит счет. Подготовка ролика
В библиотеке ролика вы увидите два клипа яблока. Первый, "bad apple", содержит 20 кадров. Каждый кадр включает изображение яблока и согласной. Другой клип, "good apple", содержит 5 кадров для 5 гласных. На рис. 9.5 изображено основное окно Flash, открытое на клипе "bad apple".
В диалоговом окне Symbol Linkage Properties обоим клипам будет назначено свойство Export for ActionScript и присвоен идентификатор "good apple" или "bad apple".
Прежде всего, код необходимо изменить таким образом, чтобы объекты двигались не вниз, а вверх. Далее, весь код, связанный со столкновениями, необходимо привести к одной форме, рассматривающей любое столкновение как плохое.
Остальные изменения незначительны. Левая и правая границы должны двигаться, отображая камни в реке. Скорость игры может быть больше, и на экране одновременно может отображаться больше камней.
Вместо постепенного ускорения скорость игры будет падать до 0 при столкновении. В результате игрок почувствует удар. В конце игры будет такое же замедление.
Иллюзия глубины может быть достигнута простым использованием перспективы. На рисунке 9.9 показано, что границы дороги нарисованы диагонально по направлению к нижним углам экрана. Хотя ширина дороги предполагается постоянной, глазу кажется, что дорога спереди уже.
В дополнение к линиям, все элементы игры должны появляться с некоторого расстояния. Это означает, что они должны двигаться не только сверху вниз, но и в стороны. Сыграйте прямо сейчас, чтобы посмотреть, как движутся камни по краям дороги и дорожные метки, похожие на звезды.
Три типа элементов движутся в этой игре: камни по сторонам дороги, звездообразные "бонусы"-метки на дороге и центральная линия дороги. В зависимости от скорости машины камни движутся по экрану вниз быстрее или медленнее. Движение камней в сторону - разбегание, создающее иллюзию перспективы, - происходит с той же скоростью, что и вниз.
Звездообразные метки располагаются ближе к центру экрана, поэтому они движутся в стороны не так быстро, как вниз; скорость их движения в стороны составляет половину от значения скорости движения вниз. Это соответствует перспективе, заданной сторонами дороги. Центральная линия просто движется прямо вниз.
Все эти элементы повторяются в игре раз за разом. Например, как только камень достигает нижней границы экрана, он снова появляется на горизонте и опять движется к игроку.
В дополнение к движению трех элементов игры мы также изменяем их масштаб. Таким образом, объекты, которые предполагаются далекими, выглядят меньше и увеличиваются по мере приближения.
Наша цель не в том, чтобы создать перспективу, реальную до последнего пиксела, а в том, чтобы достаточно к ней приблизиться, предоставив возможность воображению пользователя довершить остальное и почувствовать себя въезжающим в экран.
Поймай яблоко
Исходный файл: Applecatch.fla
В первой игре "Поймай яблоко" лиса будет двигаться в нижней части экрана и пытаться поймать яблоки, падающие с дерева. На рис. 9.1 показан фрагмент игры. Полный ролик находится в файле Applecatch.fla.
Рисунок 9.1 Элементами игры "Поймай, яблоко" являются лиса в нижней части экрана и яблоки, падающие сверху
Создание кода
Как и в большинстве наших игр, все события данной игры запускаются при помощи клипа "actions". В нашем примере этот клип расположен за пределами рабочего поля в верхнем левом углу экрана.
Сценарий, назначенный клипу "actions", вызывает функции главной временной шкалы ролика. Это упрощает код, так как перед именами клипов не нужно добавлять префикс _root. После зафузки клипа код вызывает функцию initGame, а затем вызывает три функции при каждом обращении к кадру.
onClipEvent (load) {
root.initGame();
}
onClipEvent (enterFrame) {
_root.moveFox();
_root.dropNewApple();
_root.moveApples();
}
Таким образом, вся работа осуществляется четырьмя функциями, которые находятся в главной временной шкале. Рассмотрим каждую из них.
Первая функция, initGame, инициализирует в начале игры целый ряд переменных. Она создает и клип с лисой. Этот клип создается при помощи кода, а не добавляется при создании ролика потому, что лиса должна располагаться поверх яблок. Если бы клип лисы создавался одновременно с роликом, тогда каждое яблоко, созданное кодом, помещалось бы поверх лисы. Это позволяет нам управлять размещением уровня, в котором содержится лиса, относительно уровня с яблоками. Лисе отведен уровень 999,999. Яблоки будут помешаться начиная со слоя 1 и, следовательно, будут располагаться под лисой.
function initGame() {
// Инициализация переменных, хранящих
// номера первого и последнего яблока.
firstApple = 1;
lastApple = 0;
// Инициализация переменной, хранящей число пойманных яблок,
score = 0;
// Указываем общее количество яблок.
totalApples =20;
// Скорость падения и счетчик времени
// между появлениями яблок.
timeSinceLastApple = 0;
appleSpeed = 5;
// Создаем экземпляр клипа содержащий лису,
attachMovie ("running fox", "fox", 999999);
fox._x = 275;
fox._y = 300;
}
Для того чтобы переместить лису, объект Key должен проверить состояние клавиатуры. С помощью функций Key. isDown (Key.RIGHT) и Key. isDown (Key.LEFT) проверяется, нажаты ли стрелки "вправо" и "влево" соответственно. Переменная dx принимает значение от 10 до -10 и показывает насколько и в каком направлении должна переместиться лиса.
Код клипа "actions" аналогичен тому, что использовался в игре "Помай яблоко". Изменятся только функции. В функцию initGame было внесено лишь одно изменение: число падающих яблок было увеличено до 50.
Рисунок 9.5 Клип "bad apple" состоит из 20 кадров. Каждый кадр содержит изображение яблока и одного из согласных звуков
function initGame() {
// Инициализация переменных, хранящих
// номера первого и последнего яблока.
firstApple = 1;
lastApple = 0;
// Инициализация переменной, хранящей число пойманных яблок,
score = 0;
// Задаем общее количество яблок.
totalApples = 50;
// Скорость падения и счетчик времени между появлениями яблок.
timeSinceLastApple = 0;
appleSpeed = 5;
// Создаем экземпляр клипа, содержащий лису.
attachMovie("running fox","fox",999999);
fox._x = 275;
fox._y = 300;
}
Функция moveFox полностью совпадает с аналогичной функцией игры "Поймай яблоко", поэтому нет смысла повторять ее здесь. Функция drop-NewApple будет отличаться, так как она должна выбирать, какое яблоко бросать, а затем отображать произвольный кадр выбранного клипа.
function dropNewApple() {
// Проверяем, прошел ли заданный промежуток времени,
if (timeSinceLastApple > 20) {
// Бросаем яблоко, если не превышено
// их предельно допустимое количество,
if (lastApple < totalApples) { // Устанавливаем вероятность сброса яблока в 10%.
if (Math.random() < .1) {
// Создаем объект-яблоко.
lastApple++;
if (Math.random() < .5) {
//В 50% случаев яблоко плохое.
attachMovie( "bad apple", "apple"+lastApple, lastApple);
_root["apple"+lastApple].type = "bad";
} else {
// В 50% случаев яблоко хорошее.
attachMovie( "good apple", "apple"+lastApple, lastApple);
_root["apple"+lastApple].type = "good";
}
f=int(Math.Random()*_root["apple"+ lastApple]._totalFrames) + 1;
trace(f);
_root["apple"+lastApple].gotoAndStop(f) ;
Клипу "actions" назначен такой же сценарий, как и в первых двух играх данной главы, однако имена были изменены в соответствии с темой данной игры.
onClipEvent (load) {
_root.initGame();
}
onClipEvent (enterFrame) {
_root.moveFox();
_root.newRock();
_root.moveRocks();
}
Функции главной временной шкалы должны быть вам знакомы. Некоторые части кода аналогичны функциям, рассмотренным ранее, но имеют другие имена.
Функция initGame запускает игру со скоростью течения реки 0. Изображение лисы расположено не в нижней части экрана, а в центре.
function initGame() {
// Номера первого и последнего камня.
firstRock = 1;
lastRock = 0;
// Задаем переменную, содержащую количество столкновений.
spills = 0;
// Количество камней.
totalRocks = 50;
// Время, прошедшее со времени появления последнего камня.
timeSinceLastRock = 0;
riverSpeed = 0;
/// Помещаем на рабочее поле клип лисы.
attachMovie( "kayaking fox", "fox", 999999 );
fox._x = 275;
fox._y = 200;
}
Как и в предыдущих примерах, функция moveFox определяет, нажаты ли клавиши со стрелками "влево" и "вправо". Кроме этого, она проверяет, воспроизводится ли анимация "spill", и если ответ положительный, игнорирует нажатие клавиш.
Вместо поворота изображения код задает переход клипа "fox" к кадрам, помеченным "left" или "right". Первый кадр имеет метку "still" и отображает байдарку, плывущую вперед.
function moveFox() {
if (fox._currentFrame > 4) {
//Во время столкновения нажатие клавиш игнорируется.
dx = 0;
} else if (Key.isDown(Key.RIGHT)) {
// Передвигаем лису вправо.
dx = riverSpeed;
fox.gotoAndStop("left");
} else if (Key.isDown(Key.LEFT)) {
// Передвигаем лису влево dx = -riverSpeed;
fox.gotoAndStop("right");
} else {
// Клавиша не нажата.
dx = 0; fox.gotoAndStop("still");
}
// Передвигаем лису и отслеживаем,
// чтобы она не вышла за границы экрана.
fox._x += dx;
Основная часть кода - это сценарий клипа машины. Он начинается с задания переменной speed значения 0. Эта переменная должна быть на уровне _root, поскольку остальные клипы будут к ней обращаться.
onClipEvent(load) {
// Инициализируем переменную скорости.
_root.speed = 0;
}
Обработчик onClipEvent (enterFrame) сначала проверяет все четыре клавиши с изображением стрелок. Левая и правая клавиши со стрелкой перемешают машину влево или вправо и также заставляют клип с машиной показывать соответствующий кадр поворота.
Клавиши со стрелками вверх и вниз изменяют скорость машины на 0,1. Постоянно осуществляется проверка, не упала ли скорость ниже 0.
Если ни одна из клавиш со стрелками не нажата, клип с машиной возвращается к первому кадру. Обработчик осуществляет еще две проверки. Первая нужна, чтобы узнать, не находится ли под машиной клип "bonus". Если да, игрок получает очки, и бонус очень быстро проезжает далее, чтобы игрок не получил за него очки еще раз.
Вторая проверка выясняет, не коснулась ли машина обочины. Если да, движение машины в сторону ограничивается и замедляется.
onClipEvent(enterFrame) {
if (Key.isDownfKey.LEFT)) {
// Поворачиваем влево.
this._x -= 10;
this.gotoAndStop("left");
} else if (Key.isDown(Key.RIGHT)) {
// Поворачиваем вправо.
this._x += 15;
this.gotoAndStopC'right") ;
} else if (Key.isDown(Key.UP)) {
// Увеличиваем скорость.
_root.speed += .1;
} else if (Key.isDown(Key.DOWN)) {
// Тормозим.
_root.speed -= . 1;
// Проверяем, что скорость не меньше 0.
if (_root.speed < 0) _root.speed = 0;
} else {
_root.car.gotoAndStop("straight");
// Проверяем бонус.
if (this.hitTest(_root.bonus._x,_root.bonus._y)) {
_root.score++;
_root.bonus._y +=100;
// Замедляем движение, если коснулись обочины,
if (this._x < 80) {
this._x = 80;
_root.speed /= 2;
} else if (this._x > 470) {
this._x = 470;
_root.speed /= 2;
}}
Клип "sideObject" содержит сценарий, двигающий объект вниз и в сторону от центра. Для каждого следующего кадра значение _у увеличивается, а _х - изменяется. Оба параметра используют переменную speed для характеристики этого изменения, но _х использует коэффициент dx который может быть равен 1 или -1. Объект перемешается соответственно вправо или влево.
Когда объект достигает значения 600 по вертикали, что на 200 пикселов ниже границы экрана, он возвращается назад к значению 200, то есть вновь появляется на горизонте. С вероятностью 50/50 он помещается слева или справа от дороги. Именно в этот момент определяется значение переменной dx.
И наконец, масштаб объекта определяется в соответствии со значением _у. Это означает, что объект становится больше по мере приближения
Сплав на байдарке
Исходный файл: Riverkayak.fla
В этом разделе данной главы мы, используя код двух предыдущих игр, создадим совершенно другую на первый взгляд игру. В этой игре наш герой лиса будет плыть по реке на байдарке, избегая препятствия и стараясь добиться хорошего времени.
Для трансформации предыдущих игр в эту, как ни удивительно, не нужно прилагать много усилий. И в то же время игры будут совершенно разными. Взглянув на рис.9.6, вы убедитесь, насколько данная игра отличается от игр "Поймай яблоко".
Лисой можно управлять при помощи
Лисой можно управлять при помощи клавиш "влево" и "вправо". Лиса будет передвигаться в течение всего времени, пока пользователь удерживает одну из клавиш. Перед правой или левой границей экрана лиса автоматически остановится.
Яблоки падают из произвольных мест верхней части экрана и через произвольный интервал времени, но не слишком часто. Вначале яблоки падают медленно, но в ходе игры скорость их падения увеличивается. После того как упадет определенное количество яблок, игра завершается. Счет будет равен количеству пойманных лисой яблок.
Задача проекта - так изменить игру "Поймай яблоко", чтобы учитывалось различие букв (гласные/согласные). Поймав любое яблоко с нарисованной гласной буквой, игрок получит очко, поймав яблоко с согласной, он потеряет очки. При этом счет не может быть меньше 0.
Одной из задач данной игры является создание определенной иллюзии у игрока. Хотя байдарка остается в центре экрана, у игрока складывается впечатление, что она движется вниз по реке. Это достигается при помощи объектов, двигающихся вверх по экрану.
Рисунок 9.6 Игра "Сплав на байдарке" состоит из байдарки в центре экрана и камней и веток деревьев, несущихся ей навстречу
Большая часть кода будет взята из двух игр, рассмотренных ранее в данной главе. Однако, в отличие от предыдущих игр, избегать придется все, а не только некоторые объекты. Счет будет содержать не количество набранных очков, а количество столкновений байдарки с объектами. Чем больше произойдет столкновений, тем скорее закончится игра.
Главная задача этой игры - создание иллюзии глубины. Хотя экран по-прежнему двумерный и никаких реальных трехмерных кодов не используется, игрок тем не менее должен чувствовать, что дорога входит в экран, а не ползет по нему сверху вниз.
В дополнение мы примем небольшой набор правил. На дороге есть отметки, которых водителю необходимо коснуться, чтобы заработать очки. Чем быстрее водитель едет, тем большего числа потенциальных отметок он может коснуться, прежде чем закончится время игры. Но чем быстрее он едет, тем больше у него шансов не успеть поймать метку до того, как она уйдет. К тому же, если водитель дотронулся до границ дороги, он замедляет ход и уменьшает свою потенциальную возможность заработать очки, поскольку на меньшей скорости ему попадается меньше меток.