Статьи

Создайте игру с воздушными шариками во Flash

Одна из самых популярных флэш-игр — Bloons , в которой вы играете в обезьяну, которая бросает дротики в воздушные шарики. Это породило множество сиквелов, даже разветвляющихся на другие жанры, такие как защита башни. Из этого туториала Вы узнаете, как создать собственную игру с воздушными шариками, используя движок QuickBox2D.


Давайте посмотрим на конечный результат, к которому мы будем стремиться:

Нажмите и удерживайте, чтобы определить угол выстрела. Попробуй лопнуть все шары!


В этом уроке мы будем использовать серию классов ActionScript для создания игры Bloons Inspired. Цель игры — стрелять по воздушным шарам, чтобы совать их всех.


Откройте Flash и создайте документ шириной 480 пикселей и высотой 320 пикселей. Установите частоту кадров 24 к / с.


Будет использован красочный и простой интерфейс с несколькими фигурами, кнопками и мувиклипами. В течение следующих нескольких шагов мы создадим этот графический интерфейс. Белка и изображение желудя взято с openclipart.org .


Этот фон был создан во Flash с использованием простых прямоугольников и овальных форм. Коричневая полоса внизу будет служить информационной полосой.


Чтобы создать заголовок, выберите инструмент «Текст» (T) и измените цвет на #EEEEEE; напишите текст заголовка (я использовал шрифт GoodDog) и добавьте простую тень. Для всплывающего окна выберите инструмент «Овал» (O) и создайте овал размером 20×30 px # FFCE47. Используйте Poly Star Tool для маленького треугольника под ним.


Снова используйте Text Tool, чтобы создать две кнопки, как показано на рисунке выше. Преобразуйте их в кнопки и дайте им описательные имена экземпляров, чтобы мы могли легко использовать их позже в коде. Преобразуйте графику на сцене в один мувиклип и назовите его TitleView — не забудьте установить флажок « Экспорт для ActionScript» .


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


Экран Credits появится перед экраном Title ; использовать графику и шрифты, прежде чем создать его. Назовите его CreditsView и не забудьте установить флажок « Экспорт для ActionScript» .


Предупреждение будет показано, когда все воздушные шары были выскочил; он будет отображать сообщение об игре и счет. Используйте инструмент Rectangle Tool, чтобы создать его и установить имя его экземпляра в AlertView . Снова отметьте поле « Экспорт для ActionScript» .


Мы будем использовать звуковые эффекты, чтобы улучшить ощущение игры; Вы можете найти звук, используемый в этом примере на Soungle.com, используя ключевое слово pop .


Мы будем использовать другой движок анимации движения, отличающийся от встроенного во Flash, по умолчанию, это повысит производительность и облегчит использование.

Вы можете скачать TweenNano с официального сайта .


Мы будем использовать полезную физическую библиотеку QuickBox2D для создания этой игры. Если вы не знакомы с ним, вы можете следовать серии Введение от Activetuts +.

Вы можете скачать QuickBox2D с официального сайта .



Мы сделаем наше приложение интерактивным, используя внешний класс. Добавьте его имя в поле « Класс» в разделе « Публикация » на панели « Свойства», чтобы связать FLA с классом основного документа .



Создайте новый (Cmd + N) класс ActionScript 3.0 и сохраните его как Main.as в папке вашего класса.


Создайте базовую структуру классов, чтобы начать писать код.

01
02
03
04
05
06
07
08
09
10
11
12
package
{
    import flash.display.Sprite;
      
    public class Main extends Sprite
    {
        public function Main():void
        {
            // constructor code
        }
    }
}

Это классы, которые нам нужно импортировать, чтобы наш класс работал; директива import делает внешние классы и пакеты доступными для вашего кода.

01
02
03
04
05
06
07
08
09
10
import flash.display.MovieClip;
import com.actionsnippet.qbox.*;
import com.greensock.TweenNano;
import com.greensock.easing.Expo;
import flash.events.MouseEvent;
  
import Box2D.Common.Math.*;
import flash.events.Event;
import flash.net.navigateToURL;
import flash.net.URLRequest;

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

01
02
03
04
05
06
07
08
09
10
private var titleView:TitleView = new TitleView();
private var credits:CreditsView;
private var world:QuickBox2D;
private var acorn:QuickObject;
private var acorns:Array = [];//stores the acorns thrown
private var contacts:QuickContacts;
private var balloons:Array = [];
private var yImpulse:Number = 0;
private var xImpulse:int = 3;
private var pop:Pop = new Pop();

Конструктор — это функция, которая запускается, когда объект создается из класса, этот код выполняется первым, когда вы создаете экземпляр объекта. Конструктор класса документа является особым случаем: он запускается в начале игры.

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

1
2
3
4
public final function Main():void
{
    //Code
}

Мы начнем с добавления TitleView из библиотеки на сцену.

1
2
addChild(titleView);
startButtonListeners();

Это добавит слушателей мыши к кнопкам в представлении заголовка, что приведет нас к экрану игры или кредитов.

01
02
03
04
05
06
07
08
09
10
11
12
13
private final function startButtonListeners(action:String = ‘add’):void
{
    if(action == ‘add’)
    {
        titleView.creditsBtn.addEventListener(MouseEvent.MOUSE_UP, showCredits);
        titleView.playBtn.addEventListener(MouseEvent.MOUSE_UP, showGameView);
    }
    else
    {
        titleView.creditsBtn.removeEventListener(MouseEvent.MOUSE_UP, showCredits);
        titleView.playBtn.removeEventListener(MouseEvent.MOUSE_UP, showGameView);
    }
}

Экран Credits отображается, когда пользователь нажимает кнопку Credits. Слушатель мыши добавляется в полный MovieClip, чтобы удалить его.

1
2
3
4
5
6
7
8
private final function showCredits(e:MouseEvent):void
{
    titleView.creditsBtn.visible = false;
    titleView.playBtn.visible = false;
    credits = new CreditsView();
    addChild(credits);
    TweenNano.from(credits, 0.3, {x:-credits.width, onComplete:function():void{credits.addEventListener(MouseEvent.MOUSE_UP, hideCredits);}});
}

Если щелкнуть экран « Кредиты», он вернется и будет удален со сцены.

01
02
03
04
05
06
07
08
09
10
11
12
13
private final function hideCredits(e:MouseEvent):void
{
    TweenNano.to(credits, 0.3, {
        x: -credits.width,
        onComplete: function (): void {
            titleView.creditsBtn.visible = true;
            titleView.playBtn.visible = true;
            credits.removeEventListener(MouseEvent.MOUSE_UP, hideCredits);
            removeChild(credits);
            credits = null;
        }
    });
}

Следующие строки удаляют титульный экран и оставляют экран игры видимым. Здесь мы также вызываем необходимые функции для запуска игры; эти функции объясняются в следующих шагах.

01
02
03
04
05
06
07
08
09
10
11
12
private final function showGameView(e:MouseEvent):void
{
    TweenNano.to(titleView, 0.3, {
        y: -titleView.height,
        onComplete: function (): void {
            startButtonListeners(‘rmv’);
            removeChild(titleView);
            titleView = null;
            startGame();
        }
    });
}

Остановимся здесь, чтобы сделать быстрый тест и убедиться, что наш игровой код работает:

Имейте в виду, что некоторые строки были закомментированы, так как некоторые функции еще не созданы.

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


Эта функция добавляет слушателей мыши, необходимых для выполнения съемки желудя.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
private final function gameListeners(action:String = ‘add’):void
{
    if(action == ‘add’)
    {
        bg.addEventListener(MouseEvent.MOUSE_DOWN, startCharge);
        bg.addEventListener(MouseEvent.MOUSE_UP, shot);
        restartBtn.addEventListener(MouseEvent.MOUSE_UP, restartLvl);
        stage.addEventListener(Event.ENTER_FRAME, update);
    }
    else
    {
        bg.removeEventListener(MouseEvent.MOUSE_DOWN, startCharge);
        bg.removeEventListener(MouseEvent.MOUSE_UP, shot);
        restartBtn.removeEventListener(MouseEvent.MOUSE_UP, restartLvl);
        stage.removeEventListener(Event.ENTER_FRAME, update);
    }
}

Здесь мы начинаем игру с создания мира Box2D и вызова функций, которые будут создавать воздушные шары и обрабатывать события мыши.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
private final function startGame():void
{
    /* Hide gCircle */
      
    gCircle.visible = false;
      
    /* New B2D world */
      
    world = new QuickBox2D(this, {debug:0});
    contacts = world.addContactListener();
    contacts.addEventListener(QuickContacts.ADD, onAdd);
      
    /* Create balloon function */
      
    gameListeners();
    createBalloons();
}

Для размещения воздушных шаров на сцене используются гнезда for петель. Эта функция будет использовать метод addBox addBox для создания нового объекта Box2D, который будет установлен как датчик — это означает, что не будет никакой физической реакции на столкновение (то есть желудь не отскочит от него), но столкновение все равно будет быть обнаруженным. Используя этот метод, мы можем уничтожить воздушный шар, но пусть желудь продолжит свой путь, как будто ничего не произошло.

Затем шарик добавляется в массив; это даст нам доступ ко всем шарам вне этой функции.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
private final function createBalloons(h:int = 5, v:int = 3):void
{
    for(var i:int = 0; i < h; i++)
    {
        for(var j:int = 0; j < v; j++)
        {
            var balloon:QuickObject = world.addBox({x:10 + (i * 0.66), y:4 + (j * 1), width: 0.66, height: 1, skin:Balloon, fixedRotation:true, draggable:false, density:0});
            balloon.shape.m_isSensor = true;
            balloons.push(balloon);
        }
    }
      
    /* Set balloon counter */
      
    targetTF.text = String(balloons.length);
      
    /* Start Physics */
      
    world.start();
}

Конечно, вам не нужно использовать вложенные циклы для позиционирования воздушных шаров; это самый простой способ расположить их в сетке, но вы можете расположить их вручную, если хотите.


Эта функция обрабатывает столкновение, упомянутое в шаге 26. Первое, что нужно сделать, — это просмотреть массив воздушных шаров, проверяя каждый из них на предмет столкновения с желудем.

1
2
3
4
5
6
private final function onAdd(e:Event):void
{
    for(var i:int = 0; i < balloons.length; i++)
    {
        if(contacts.isCurrentContact(balloons[i], acorn))
        {

Если столкновение истинно, мы вызываем метод destroy() всплывающего окна QuickObject и удаляем элемент из массива.

1
2
balloons[i].destroy();
balloons.splice(i, 1);

Затем мы играем звук, указывающий на удар, усиливающий ощущение игры.

1
pop.play();

Счетчики очков и целей обновляются в соответствии с всплывающими подсказками и оставленными шариками.

1
2
scoreTF.text = String(int(scoreTF.text) + 50);
targetTF.text = String(balloons.length);

Оповещение вызывается, когда все воздушные шары лопнут; мы увидим эту функцию позже в уроке.

1
2
3
4
if(targetTF.text == ‘0’)
{
    alert();
}

Этот код откроет указатель направления желудя, сбросит переменную y-impulse желудя и добавит прослушиватель энтерфрейма, который будет обрабатывать цель.

1
2
3
4
5
6
private final function startCharge(e:MouseEvent):void
{
    yImpulse = 0;
    gCircle.visible = true;
    gCircle.addEventListener(Event.ENTER_FRAME, charge);
}

Индикатор прицеливания поворачивается, чтобы показать направление, в котором будет выпущен желудь, и соответствующим образом корректирует переменную y-импульса. На направление выстрела влияют две переменные, xImpulse и yImpulse , которые позже объединяются, чтобы сформировать impulse вектор. xImpulse остается постоянным, а yImpulse изменяется, когда пользователь удерживает нажатой кнопку мыши.

01
02
03
04
05
06
07
08
09
10
11
12
private final function charge(e:Event):void
{
    gCircle.rotation -= 3;
    yImpulse -= 0.2;
  
    /* Prevent over-rotation */
    if(gCircle.rotation < -80)
    {
        yImpulse = -5.4;
        gCircle.rotation = -80;
    }
}

Следующие действия происходят, когда кнопка мыши нажата.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
private final function shot(e:MouseEvent):void
{
    /* Hide gCircle */
      
    gCircle.removeEventListener(Event.ENTER_FRAME, charge);
    gCircle.visible = false;
    gCircle.rotation = 0;
      
    /* Create new Acorn */
      
    acorn = world.addBox({x:2.76, y:7.33, width: 0.66, height: 0.53, skin:Acorn, fixedRotation:true, draggable:false, density:1});
    acorns.push(acorn);
      
    /* Shoot acorn */
      
    var impulse:b2Vec2 = new b2Vec2(xImpulse, yImpulse);
    acorn.body.ApplyImpulse(impulse, acorn.body.GetWorldCenter());
      
    /* Update Acorn counter */
      
    acornsTF.text = String(int(acornsTF.text) -1);
}

Остановимся здесь, чтобы сделать быстрый тест и убедиться, что наш игровой код работает:

Имейте в виду, что некоторые строки были закомментированы, так как эти функции еще не созданы.


Функция обновления выполнит серию операций EnterFrame. Давайте посмотрим эти действия в следующих шагах.

1
2
private final function update(e:Event):void
{

Следующие строки будут удалять все желуди, которые уходят со сцены.

1
2
3
4
5
6
7
8
/* Remove offstage acorns */
      
    for(var i:int = 0; i < acorns.length; i++)
    {
        if(acorns[i].y > 10.66)
        {
            acorns[i].destroy();
            acorns.splice(i, 1);

Игра заканчивается, когда у игрока заканчиваются желуди (или уничтожаются все воздушные шары, как упоминалось ранее).

1
2
3
4
5
6
7
8
9
/* Check for level failed */
      
            if(int(acornsTF.text) &lt;= 0)
            {
                alert(‘lose’);
            }
        }
    }
}

Этот код запускается при нажатии кнопки «Перезагрузить». Это сбросит необходимые переменные и слушатели, чтобы перезапустить уровень.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private final function restartLvl(e:MouseEvent):void
{
    /* Remove Listeners */
      
    gameListeners(‘rmv’);
      
    /* Destroy World */
      
    world = null;
      
    /* Destroy Balloons, reset score and acorns */
      
    for(var i:int = 0; i < balloons.length; i++)
    {
        balloons[i].destroy();
        scoreTF.text = ‘0’;
        acornsTF.text = ‘5’;
    }
      
    balloons = [];//clear balloons array
      
    startGame();
}

Эта функция остановит игру и покажет сообщение Game Over. Он также добавляет слушателя мыши для сброса игры при нажатии.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
private final function alert(gameState:String = ‘win’):void
{
    gameListeners(‘rmv’);
    world.stop();
      
    var alert:AlertView = new AlertView();
      
    alert.x = stage.stageWidth * 0.5;
    alert.y = stage.stageHeight * 0.5;
    alert.scoreTF.text = scoreTF.text;
    alert.addEventListener(MouseEvent.MOUSE_UP, restart);
      
    if(gameState == ‘lose’)
    {
        alert.titleTF.text = ‘Level Failed!’;
    }
      
    addChild(alert);
    TweenNano.from(alert, 0.6, {scaleX: 0.2, scaleY: 0.2, ease:Expo.easeOut});
}

Этот код перезагрузит SWF, восстановив все значения и вернувшись к начальному экрану.

1
2
3
4
private final function restart(e:MouseEvent):void
{
    navigateToURL(new URLRequest(stage.loaderInfo.url), ‘_level0’);
}

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

Надеюсь, вам понравился этот урок, спасибо за чтение!