Создание Flash-игр

         

Стрельба по воздушным шарам

Исходный файл: Balloonshoot.fla

Первая игра состоит из трех основных элементов: лисы, воздушных шаров и снарядов. В нашем примере лиса стреляет всего лишь горошинами из соломинки (рис. 10.1). Поэтому игра подойдет для любой аудитории.

Рисунок 10.1 Лиса стреляет по пролетающим воздушным шарам из соломинки

Задача проекта

Задача этого проекта - создать игру, в которой лиса перемещается влево и вправо и стреляет вверх по воздушным шарам. Шары появляются слева и справа, на разной высоте и летят с разной скоростью. После того как пролетит определенное количество шаров, игра заканчивается. Счет определяется количеством лопнувших шаров. Готовую игру можно просмотреть в файле Balloonshoot.fla.

Подход

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

Подготовка ролика

В ролике Balloonshoot.fla клип лисы содержит кадр с меткой "stand" и анимационную последовательность, помеченную "walk". Анимация изображает лису, перемещающуюся влево (рис. 10.2), однако при помощи Action-Script вы можете повернуть лису в другую сторону, не создавая отдельной анимации. Главное условие: соломинка должна занимать во всех кадрах одно и то же положение относительно центральной точки клипа.





Рисунок 10.2 Лиса идет влево и всегда готова выстрелить из соломинки

Клип, соответствующий воздушному шару, также состоит из нескольких кадров. Первый кадр содержит изображение обычного шара. Остальные кадры воспроизводят анимацию лопающегося шара. Воспроизведение этой короткой анимации задается при попадании в шар. На рис. 10.3 показан единственный кадр анимации ролика, возможно, вы захотите изобразить взрыв более подробно.

Рисунок 10.3 При попадании в шар запускается воспроизведение анимации взрыва

Для окраски шара используются оттенки серого цвета. Цвет задается одновременно с созданием нового клипа шара. В результате один клип шара каждый раз принимает новый оттенок.
Клип снаряда содержит короткую линию. Хотя в качестве снаряда используется горошина, вертикальная линия создает видимость движения вверх.

Создание кода

Небольшой клип "actions" помешается за пределами рабочего поля и контролирует процесс игры путем обращения к функциям главной временной шкалы. Она запускает игру при загрузке и вызывает ряд функций в каждом кадре.

onClipEvent(load) {
_root.initGame();
onClipEvent(enterFrame) {
_root.newBalloon() ;
_root.moveBalloons() ;
_root.moveFox();
_root.moveBullets();
}

Функция initGame задает все основные переменные, используемые в игре.

function initGame() {
// Инициализируем переменные, связанные с объектами-шарами.
nextBalloonTime = 0;
nextBalloon = 0;
balloons = [];
numBalloons = 10;
// Инициализируем переменные,
nextBulletTime = 0;
nextBullet = 0;
bullets = [];
// Количество очков равно 0.
score = 0;
}

Перед созданием нового шара необходимо провести три проверки. Первая определяет, остались ли в игре шары, вторая- прошло ли достаточно времени после создания предыдущего шара. Последняя проверка представляет собой своего рода игру "орел и решка": новый шар создается с вероятностью 50%.
После завершения проверок функция newBalloon создает новый шар с 50-процентной возможностью появления шара с левой или правой стороны. Скорость шара принимает произвольное значение от 3 до 5. Число является положительным, если шар будет пролетать слева направо и отрицательным в противном случае.
Цвет нового шара выбирается из пяти возможных оттенков. Для задания цвета используется функция setTransform.
Клипы шаров можно упорядочить, поместив их имена и значения скоростей в массив balloons.
Затем задаются переменные nextBalloon и nextBalloonTime, при помощи которых осуществляется обращение к переменной newBalloon.

function newBalloon () {
// Определяем, могут ли появиться новые шары,
if (nextBalloon < numBalloons) {
// Проверяем, пришло ли достаточно времени
// после появления последнего шара,
if (getTimerO > nextBalloonTime) {
// "Бросаем монетку",
if (Math.Random()<.5) {
"balloon"+nextBalloon,
// Создаем новый шар.
attachMovie("balloon", nextBalloon);
// Выбираем, с какой стороны
// и с какой скоростью полетит шар.
if (Math.Random()<.5) {
_root["balloon"+nextBalloon]._x = -30;
dx = int(Math.Random()*3)+3;
} else {
_root["balloon"+nextBalloon]._x = 580;
dx = -int(Math.Random()*3)-3;
// Выбираем высоту.
_root["balloon"+nextBalloon]._y = int(Math.Random()*100)+20;
// Выбираем цвет.
balloonColor = new Color("balloon"+nextBalloon)
r = int(Math.Random()*5)+1;
if (r == 1) {
balloonColor.setTransform({rb:255}) ;
} else if (r == 2) {
balloonColor.setTransform({gb:255}) ;
} else if (r == 3) {
balloonColor.setTransform({bb:255}) ;
} else if (r == 4) {
balloonColor.setTransform({rb:255,gb:255});
} else if (r == 5) {
balloonColor.setTransform({rb:255,bb:255});
}
// Добавляем новый шар.
balloons.push({clip:"balloon"+nextBalloon,d:dx});
// Изменяем значение переменных.
nextBalloon++;
nextBalloonTime = getTimerf) + 2000;
}}
}}

Созданные шары перемещаются на опрелеленное расстояние с помощью функции moveBalloons. Если шар достиг противоположной границы рабочего поля, его клип удаляется. Соответствующий элемент также удаляется из массива balloons.

Чтобы быстро задать 50-процентную вероятность, лучше использовать фрагмент кода (Math. Random () <. 5). Функция Math. Random () всегда принимает значение от 0 до 1,0 и никогда не бывает равна 1,0, поэтому условие <.5 дает 50-проиентную вероятность возникновения некоторого события.

Имейте в виду, что в цикле for функции moveBalloons перечисление осуществляется в обратном порядке: начинается с последнего элемента в массиве balloons и заканчивается 0. Благодаря этому удаление элемента не влияет на остальную часть массива. Предположим, из массива, состоящего из пяти элементов, был удален третий элемент. Тогда четвертый элемент становится третьим, а пятый - четвертым. Если бы вы считали в прямом направлении, вы бы пропустили третий элемент и сразу перешли к четвертому. При счете в обратном порядке такой проблемы не возникает.

Функция moveBalloons проверяет, все ли шары созданы и все ли шары исчезли, что говорит об окончании игры.

function moveBalloons() {
// Перемещаем все шары,
for(i=balloons.length-1;i>=0;i--) {
// Определяем скорость шара
//и получаем ссылку на клип,
dx = balloons[i].d; balloon = _root[balloons[i].clip];
// Перемещаем шар.
balloon._x += dx;
// При вылете за экран шар удаляется,
if ((dx < 0) and (balloon._x < -20)) {
balloon.removeMovieClip() ;
balloons, splice (i,l);
} else if ((dx > 0) and (balloon._x > 570) balloon.removeMovieClip();
balloons.splice(i,1);
// Если шары закончились, игра завершается.
if ((nextBalloon >= numBalloons) and (balloons.length < 1)){
gotoAndStop("game over");
}}

Функция moveFox определяет, нажаты ли клавиши со стрелками «влево» или "вправо", и перемешает лису на 10 пикселов влево или вправо при нажатии соответствующей клавиши. Как и в предыдущих играх, параметр _xscale клипа, содержащего лису, используется для поворота лисы. Функция также задает переход клипа к анимационной последовательности (изображает идущую лису и начинается в кадре 2), а также к кадр (изображает стоящую лису).

function moveFox () {
// Подвинуть лису влево.
if (Key.isDown (Key.LEFT)) {
dx = -10;
fox._xscale = Math.abs(fox._xscale);
// Подвинуть лису вправо, перевернув ее клип по вертикали.

То есть изменив знак у свойства _scale, мы создаем зеркальное отражение клипа; лиса теперь идет в другую сторону.

}else if (Key.isDown(Key.RIGHT)) { dx = 10;
fox._xscale = -Math.abs(fox._xscale);
// Иначе лиса не двигается.
} else {
dx = 0;
// Перемещаем лису.
fox._x += dx;
if ((dx == 0) and (fox._currentFrame != 1)) {
// Переходим к кадру, в котором лиса стоит,
fox.gotoAndStop(1);
} else if ((dx != 0) and (fox._currentFrame == 1)) {
// Переходим к кадру, где лиса бежит.
fox.gotoAndPlay(2);
}
}

Для того чтобы выстрелить, пользователь должен нажать на клавишу пробела. На нажатие клавиши реагирует скрытая кнопка, которая вызывает функцию shootBullet. Код кнопки будет рассмотрен далее, в разделе "К сведению".
Функция shootBullet проверяет, прошло ли достаточно времени после предыдущего выстрела. Это не дает игроку возможности стрелять залпом по всем мишеням.
Подобно шарам снаряды представлены одновременно клипом и элементом массива, в данном случае массива bullets. Массив используется функцией moveBullets для осуществления выстрелов.
Обратите внимание, что движение клипа, содержащего снаряд, начинается в точке, расположенной в 2 пикселях вправо и 55 пикселях влево от центра клипа лисы. Эта точка соответствует кончику соломинки.

function shootBullet () {
// Проверяем, что с момента
// предыдущего выстрела прошло достаточно времени.
if (getTimerO > nextBulletTimei {
// Создаем новую пулю.
attachMoviet"bullet", "bullet'4nextBullet,nextBullet+9999) ;
// Устанавливаем ее координагы.
_root ["bullef+nextBullet] ._jc = fox._x+2;
_root [ "bullef+nextBullet] ._y = fo.x._y-55;
/ / Добавляем новую пулю к массиву.
bullets.push(nextBullet) ;
// Изменяем значение переменных, отвечающих
//за появление пуль.
nextBullet++;
nextBulletTime = getTimer()+1000;
}}

Функция moveBullets работает аналогично функции moveBalloons, но перемещает снаряды не вправо и влево, а вверх. Она проверяет одно из следующих условий: снаряд достиг верхнего края экрана либо попал в шар и вызвал функцию checkCollision. В обоих случаях и клип, и элемент массива удаляются.

function moveBullets () {
/7 Проверяем, попали ли пули в шар.
for(i=bullets.length-1;i>=O;i--) {
// Выбираем элемент.
bullet = _root["bullet"+bullets[i]];
// Передвигаем пулю вверх,
bullet._y -= 10;
// Выясняем, достигла ли она конца экрана,
if (bullet._у < 0) {
bullet.removeMovieClip();
bullets.spliced,1) ;
// Определяем, не попал ли игрок по шару.
} else {
if (checkCollision(bullet)) {
bullet.removeMovieClip();
bullets.splice (i,1);
}}
}}

Функция checkCollision (она будет рассмотрена далее) проверяет все шары и определяет, не находится ли один из них вблизи данного снаряда. При помощи функции distance оценивается расстояние от центра снаряда до центра шара. Если расстояние составляет менее 10 пикселов, что приблизительно равно диаметру шара, выстрел засчитывается как удачный. В клипе шара происходит переход к кадру 2, элемент массива, связанный с шаром, принимает значение true, а функция moveBullet получает команду на удаление снаряда.

Почему для определения попадания используется функция distance, а не hitTest? Причина в том, что функция hitTest выдает значение true в случае, если снаряд попадет в любую часть шара, в том числе и в нитку, которая его держит

function checkCollision(bullet) {
// Просматриваем все шарики,
for(j =balloons.length-1;j >=0;j--) {
balloon = __root[balloons!j].clip];
// Проверяем, попала ли пуля.
if (distance(bullet,balloon) < 10) {
// Переходим к кадру, в котором шар взрывается.
balloon.gotoAndPlay(2);
// Убираем шар из массива,
balloons.splice(j,1);
// Увеличиваем счет,
score += 1;
// Возвращаем значение true,
return(true);
// Если игрок не попал, возвращаем значение false,
}}
return(false);
}

Для определения точного расстояния в пикселях между двумя клипами функция distance использует математическую формулу. Прежде всего, она определяет значение разницы координат клипов по горизонтали и вертикали и сохраняет это значение в переменных dx и dy. Затем вычисляет квадратный корень суммы квадратов данных значений. Формула приведена ниже.

function distance(clipl, clip2) {
// Определяем расстояние между клипами,
dx = clipl._х - clip2._x;
dy = clipl._y - clip2._y;
return (Math.sqrt(dx*dx+dy*dy));
}

К сведению

Нажатие клавиши пробела контролируется кнопкой. В нашем примере она расположена за пределами рабочего поля, в левом верхнем углу экрана и визуально представляет собой надпись "button". Кнопке назначен следующий код:

on (keyPress "") {
_root.shootBullet() ;
}

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

На первый взгляд не ясно, почему используется клавиша пробела, а не проверка Key. isDown, осуществляемая функцией moveFox. Функция Key.isDown проверяет, нажата ли клавиша во время определенного промежутка времени. В нашем примере нажатие осуществляется один раз в каждом кадре. Если игрок быстро нажмет на клавишу, это событие может произойти между проверками Key. isDown. Программа не увидит, что клавиша нажата, и выстрела не произойдет. Использование кнопки гарантирует, что нажатие клавиши будет замечено и обработано.

Скорость воспроизведения ролика составляет 30 кадров в секунду, Благодаря этому анимация воспроизводится более плавно. Изменив скорость воспроизведения ролика, вам, может быть, придется изменить скорость перемещения лисы, шаров и снарядов. В противном случае скорость игры может не соответствовать вашим ожиданиям.

Другие возможности

Существует несколько способов сделать нашу игру более интересной. Цвета могут быть не произвольными, а обозначать определенное количество очков. Например, красные шары могут стоить 100 очков, синие - 50 и т.д. От цвета, в свою очередь, может зависеть скорость и высота полета шара. При этом чем выше и быстрее летит шар, тем больше его ценность.
Вы можете вообще отказаться от использования шаров. В сущности данная игра напоминает игры наподобие "Sea Wolf", задачей которых является поражение самолетов, или игры про космических пришельцев. Все, что требуется, - это заменить графику.

Содержание раздела