Статьи

Создание Frogger с Flixel: основы игры и спрайты

Это первая часть из двух руководств, в которых подробно рассказывается, как использовать Fixel для создания Frogger для Интернета и AIR на Android.


Добро пожаловать в мою серию из двух частей о том, как собрать Frogger для Интернета и AIR на Android. Как только я начал играть с Flash на Android, я начал создавать игры, это казалось самым логичным выбором. Обычно создание игры является монументальной задачей, но мы собираемся использовать отличный игровой фреймворк Flixel, чтобы быстро начать работу.

Flixel идеально подходит для ретро-8-битных игр, поскольку он использует растровые изображения под названием Sprites (не путать с классом Sprite) для всей игровой графики. Блиттинг на рабочем столе / в Интернете (рисование растровых изображений на дисплее) невероятно быстр и является одним из лучших методов для достижения максимальной производительности. На Flash Mobile это медленнее, чем вы можете ожидать. Чтобы справиться с этим, я расскажу о некоторых методах оптимизации, которые помогут добиться высокой производительности на любой целевой платформе Давайте начнем!


Для этого урока я собираюсь использовать FDT, который является отличным редактором AS3 на основе Eclipse и похож на Flash Builder. В настоящее время вы можете получить 30-дневную пробную версию или расширенный предварительный просмотр FDT 4 . Чтобы сделать вещи более привлекательными, FDT pure очень доступен.

Этот проект также будет работать в FlashBuilder или любом другом редакторе, поддерживающем запуск ANT. Одна из причин, по которой я выбрал FDT, заключается в том, что его редактор AS3 на несколько лет опережает Flash Builder или Flash IDE, что делает его идеальным для проектов только для AS3, таких как игры. И если вы знакомы с Flash Builder, переключение на FDT должно произойти само собой.

fdt4

Вот предварительный просмотр того, что мы будем строить в этом уроке:

Мы расскажем, как построить различные состояния в Flixel и создать полный уровень для игры. Давайте начнем.


Я уже создал для нас простой проект, вы можете скачать его по ссылке на источник в верхней части страницы. Не беспокойтесь, если вы не знакомы с тем, как работает ANT, я покажу вам , как именно настроить этот проект в FDT, чтобы помочь вам освоиться с ANT.

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

Давайте FlxFroggerTutorial его FlxFroggerTutorial .

Теперь вы должны увидеть следующий проект и все необходимые ресурсы.

project_folder

Поначалу муравей может показаться пугающим, но я взяла на себя все догадки. Этот проект является модифицированной версией моего шаблона ANTPile, который вы можете получить на GitHub здесь . Он разработан, чтобы помочь вам за считанные минуты начать работу в любом редакторе, поддерживающем ANT.

Первое, что нам нужно сделать, это скопировать файл build.template.properties и переименовать его в build.properties . Это основной файл, который содержит всю конфигурацию для вашей сборки. Давайте откроем это и посмотрим, что нам нужно настроить.

rename_prop_file

Чтобы дать вам ориентир, я оставил здесь свои настройки конфигурации. Первое, на что стоит обратить внимание — это FLEX_HOME . Убедитесь, что он указывает на Flex SDK на вашем компьютере. У меня есть копия FlashBuilder на моем компьютере, поэтому я указываю на это. Если у вас нет FlashBuilder, вы можете скачать SDK отсюда и поместить его в любое место на своем компьютере, а затем указать этот путь. Если вы находитесь на окнах, вы должны сделать все пути вперед.

Далее мы хотим проверить правильный браузер, ищем переменную «browser». Как вы можете видеть на Mac, я настроил его для Safari

1
browser = Safari

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

1
browser = C:/Program Files/Mozilla Firefox/firefox.exe

Последнее, что вы можете сделать, это настроить путь для Android SDK. Вы можете скачать его отсюда , как вы видите, я храню свою копию в /Users/jfreeman/Documents/AndroidDev/ . Я также назвал мой на основе версии Android, для которой я создаю. В этом случае я использую 2.2. Вы можете пропустить этот шаг прямо сейчас, так как я подробнее расскажу во второй части о том, как создать AIR для Android с помощью ANT.

Итак, теперь у вас есть все пути, давайте посмотрим, как это запустить. Настройка сборки Ant очень проста в FDT. Просто щелкните правой кнопкой мыши на build.xml . Выберите «Run as Ant Build …», и вы увидите следующее окно.

run_as_ant

Как видите, FDT автоматически все настроил для вас. Все, что вам нужно сделать, это выбрать запустить; вы увидите, как Ant начнет сборку, и ваш браузер должен отобразить следующий файл swf:

FlxFrogger-привет-мир

Это экран по умолчанию Ant Pile. Поздравляю, это была, вероятно, самая трудная часть всего урока. Если у вас возникли проблемы со сборкой, убедитесь, что вы указали правильный путь к FLEX_HOME и вашему браузеру. Если вы новичок в Ant, вы можете подумать, что это много работы, и в некоторых случаях вы правы. Этот вид настройки используется в очень больших проектах, но знание того, как использовать ANT, может облегчить вашу жизнь. Эта сборка делает много вещей, которые IDE обычно не делает для вас. Его можно настроить для автоматической генерации ASDocs, перемещения файлов, и, как вы увидите позже, он будет создавать swf и apk (приложение для Android) одним щелчком мыши.

Нам просто нужно сделать еще одну вещь, прежде чем мы сможем сделать нашу первую игру, нам нужно сообщить FDT, где находится Flixel SWC. Чтобы упростить задачу, я включил сборку Flixel в папку build/libs , куда вы должны поместить все свои библиотеки swc для своего проекта. ANT Build автоматически ищет в этой папке эти библиотеки, но FDT не имеет представления. Щелкните правой кнопкой мыши по вашему проекту и выберите «Свойства» в контекстном меню. Затем выберите FDT Build Path и нажмите на вкладку Library. Отсюда вы можете выбрать Add SWCs … справа и найти flixel.swc в нашей папке libs.

add_swcs

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


Прежде чем мы сможем что-то сделать с Flixel, нам нужно создать государство. Состояние похоже на экран или сцену в вашей игре. У вас может быть начальное, конечное и кредитное состояние, а также вы можете создавать состояния для каждого уровня вашей игры. Давайте сделаем стартовое состояние, чтобы мы могли настроить Flixel. Щелкните правой кнопкой мыши папку src и выберите « New AS Class . Вы захотите заполнить все так:

configure_start_state

Теперь мы можем заполнить основы нашего стартового экрана. Давайте скопируем и вставим следующий код в:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.flashartofwar.frogger.states
{
     
    import flash.events.MouseEvent;
 
    import org.flixel.FlxG;
    import org.flixel.FlxSprite;
    import org.flixel.FlxState;
    import org.flixel.FlxText;
 
    public class StartState extends FlxState
    {
         
        /**
         * This is the first game state the player sees.
         */
        public function StartState()
        {
            super();
        }
 
        /**
         * Goes through and creates the graphics needed to display the start message
         */
        override public function create():void
        {
            var sprite:FlxSprite = new FlxSprite();
            sprite.createGraphic(FlxG.width, FlxG.height / 2, 0xff000047);
            add(sprite);
 
            stage.addEventListener(MouseEvent.CLICK, onClick);
 
            add(new FlxText(0, 200, FlxG.width, «PUSH»).setFormat(null, 18, 0xffffffff, «center»));
            add(new FlxText(0, 300, FlxG.width, «ANYWHERE TO START»).setFormat(null, 18, 0xd33bd1, «center»));
        }
 
        /**
         * Handles when the user clicks and changes to the PlayState.
         * @param event MouseEvent
         */
        private function onClick(event:MouseEvent):void
        {
        }
 
        /**
         * This removed the click listener.
         */
        override public function destroy():void
        {
            stage.removeEventListener(MouseEvent.CLICK, onClick);
            super.destroy();
        }
 
    }
}

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

Как только у нас будет наше первое состояние, давайте перейдем к основному классу FlxFrogger и заменим все на это:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
package
{
    import com.flashartofwar.frogger.states.StartState;
 
    import org.flixel.FlxGame;
 
    [SWF(width=»480″, height=»800″, backgroundColor=»#000000″)]
    [Frame(factoryClass=»Preloader»)]
 
    public class FlxFrogger extends FlxGame
    {
        /**
         * This is the main game constructor.
         */
        public function FlxFrogger()
        {
            // Create Flixel Game.
            super(480, 800, StartState, 1);
        }
    }
}

Это весь код, который нам нужен для запуска Flixel и начала нашей игры. Как видите, мы просто расширяем FlxGame и передаем размеры и наш StartState до супер. Последнее значение 1 представляет режим масштабирования. Flixel может «улучшить» вашу игру, чтобы помочь получить крутой ретро пиксельный вид. Мы не собираемся использовать это в этой игре, поскольку исходные изображения достаточно пикселированы.

Вам также нужно будет создать класс Preloader по умолчанию. Создайте новый класс с именем Preloader и настройте его следующим образом:

configure_preloader

Затем скопируйте этот код в него:

01
02
03
04
05
06
07
08
09
10
11
12
13
package
{
    import org.flixel.*;
 
    public class Preloader extends FlxPreloader
    {
        public function Preloader()
        {
            className = «FlxFrogger»;
            super();
        }
    }
}

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

Теперь давайте запустим сборку ANT, чтобы увидеть наш стартовый экран. У вас все хорошо, если вы видите это:

preview_start_state

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


В прошлом вы, возможно, помещали все свои активы в FLA и использовали временную шкалу. В этом проекте мы собираемся сделать все через код. Поскольку Flixel обрабатывает анимацию через листы Sprite, нам не нужна временная шкала или мувиклип. Давайте создадим новый класс с именем GameAssets и GameAssets его так:

create_game_assets

Если вы загляните в нашу папку build/assets вы увидите, что все наши изображения готовы для импорта.

Примечание: оригинальная графика и изображения Frogger от Konami

game_assets

Поскольку у нас нет библиотеки при использовании Flex SDK, нам нужно будет использовать Embed Tag . Вот пример того, как будет выглядеть один из наших активов, когда мы его встраиваем. Добавьте это в класс GameAssets .

1
2
[Embed(source=»../../../../../build/assets/frogger_title.gif»)]
public static var TitleSprite:Class;

Как видите, нам нужно указать путь к графике и дать ему имя переменной. Это похоже на добавление идентификатора связи в библиотеку SWF. Путь всегда зависит от местоположения вашего класса в проекте. Поскольку этот класс находится в нескольких пакетах, вы заметите ../ означающий, что компилятор должен выглядеть на уровень выше текущего местоположения. Давайте добавим это в наш класс GameAssets . И последнее, на что нужно обратить внимание: переменная является статической. Мы будем использовать этот класс во всем приложении, чтобы получить доступ к ссылкам на классы активов. Как только вы добавите и сохраните этот актив, давайте откроем наш StartState и добавим заголовок.

После строки с stage.addEventListener в stage.addEventListener create() добавьте следующие строки кода:

1
2
3
var title:FlxSprite = new FlxSprite(0, 100, GameAssets.TitleSprite);
title.x = (FlxG.width * .5) — (title.width * .5);
add(title);

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

1
import com.flashartofwar.frogger.sprites.GameAssets;

FDT может помочь вам управлять импортом и должен был предложить вам добавить его. Вы можете нажать Command 1 на Mac, чтобы выскочило диалоговое окно быстрого исправления. Теперь давайте запустим сборку ANT и посмотрим название нашей игры:

preview_game_title

Отлично, вы только что узнали, как импортировать растровое изображение в ваше приложение и как отображать его в Flixel. Давайте вернемся к нашему классу GameAssets и заполните остальную графику, которая нам понадобится:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
[Embed(source=»../../../../../build/assets/background.png»)]
public static var LevelSprite:Class;
 
[Embed(source=»../../../../../build/assets/lives.png»)]
public static var LivesSprite:Class;
 
[Embed(source=»../../../../../build/assets/alligator_sprites.png»)]
public static var AlligatorSprite:Class;
 
[Embed(source=»../../../../../build/assets/car_sprites.png»)]
public static var CarSpriteImage:Class;
 
[Embed(source=»../../../../../build/assets/frog_sprites.png»)]
public static var FrogSpriteImage:Class;
 
[Embed(source=»../../../../../build/assets/bonus_sprites.png»)]
public static var HomeSpriteImage:Class;
 
[Embed(source=»../../../../../build/assets/tree_1.png»)]
public static var LogSpriteImage1:Class;
 
[Embed(source=»../../../../../build/assets/tree_2.png»)]
public static var LogSpriteImage2:Class;
 
[Embed(source=»../../../../../build/assets/tree_3.png»)]
public static var LogSpriteImage3:Class;
 
[Embed(source=»../../../../../build/assets/truck.png»)]
public static var TruckSpriteImage:Class;
 
[Embed(source=»../../../../../build/assets/turtle_2_sprites.png»)]
public static var TurtlesSpriteImage:Class;
 
[Embed(source=»../../../../../build/assets/turtle_3_sprites.png»)]
public static var TurtlesBSpriteImage:Class;

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


Встраивание звуков непосредственно в класс — это беспроигрышная ситуация. Это один из случаев, когда я на самом деле использую Flash IDE, чтобы облегчить свою жизнь. В другой раз я использую его для встраивания шрифтов, но, к счастью, у Flixel есть все шрифты, которые нам нужны уже в рамках фреймворка. Чтобы встроить звуковой файл, нам нужно добавить его в библиотеку FLA и добавить идентификатор связи. Я уже создал SWF для нас в папке активов под названием frogger_sounds . Если вы хотите посмотреть, как я это сделал, я включил FLA в папку build/flas . Давайте добавим несколько звуков в наш класс GameAssets .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
[Embed(source=»../../../../../build/assets/frogger_sounds.swf», symbol=»FroggerExtraSound»)]
public static var FroggerExtraSound:Class;
 
[Embed(source=»../../../../../build/assets/frogger_sounds.swf», symbol=»FroggerPlunkSound»)]
public static var FroggerPlunkSound:Class;
 
[Embed(source=»../../../../../build/assets/frogger_sounds.swf», symbol=»FroggerSquashSound»)]
public static var FroggerSquashSound:Class;
 
[Embed(source=»../../../../../build/assets/frogger_sounds.swf», symbol=»FroggerTimeSound»)]
public static var FroggerTimeSound:Class;
 
[Embed(source=»../../../../../build/assets/frogger_sounds.swf», symbol=»FroggerHopSound»)]
public static var FroggerHopSound:Class;
 
[Embed(source=»../../../../../build/assets/frogger_sounds.swf», symbol=»FroggerThemeSound»)]
public static var FroggerThemeSound:Class;

Так что это работает аналогично тому, как мы встраиваем изображение, но, как вы можете видеть, все наши звуки исходят от нашего SWF. Также мы ссылаемся на идентификатор связи в качестве значения symbol . Теперь, когда они у вас есть, давайте попробуем. Откройте наш класс StartState и найдите метод onClick() . Добавьте следующую строку кода:

1
2
// Sound is played after the state switch to keep it from being destroyed
FlxG.play(GameAssets.FroggerThemeSound);

Flixel делает воспроизведение звука невероятно легким. Вы просто просите FlxG , который является синглтоном в фреймворке, воспроизвести и передать ему ссылку на класс звука. Мы можем проверить это, запустив сборку ANT и щелкнув в любом месте экрана.

Теперь мы готовы добавить наш PlayState чтобы мы могли что-то сделать, когда пользователь пытается запустить игру.


Раньше, когда мы создавали наше StartState я как бы замалчивал то, что происходило под капотом. Давайте на этот раз немного медленнее, чтобы вы могли лучше понять, как работают государства в Flixel. Создайте новый класс с именем PlayState и настройте его следующим образом:

configure_play_state

Затем добавьте код заглушки:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.flashartofwar.frogger.states
{
    import com.flashartofwar.frogger.sprites.GameAssets;
 
    import org.flixel.FlxSprite;
    import org.flixel.FlxState;
 
    public class PlayState extends FlxState
    {
         
        /**
         * This is the main level of Frogger.
         */
        public function PlayState()
        {
            super();
        }
 
        /**
         * This is the main method responsible for creating all of the game pieces and layout out the level.
         */
        override public function create():void
        {
            // Create the BG sprite
            var bg:FlxSprite = new FlxSprite(0, 0, GameAssets.LevelSprite);
            add(bg);
        }
 
    }
}

Итак, здесь у нас есть два метода, наш конструктор, который ничего не делает, и переопределенный метод create() . В Flixel у класса FlxState , который мы расширяем, есть этот метод по умолчанию, называемый «create». Это где вся наша логика инициализации идет. Думайте об этом как об инициации. Как вы видите, мы создаем фоновое изображение для нашего уровня игры. Еще одна вещь, на которую следует обратить внимание, это вызов add() когда мы хотим прикрепить спрайты к средству визуализации. Это похоже на то, как работает addChild() но в Flixel, поскольку все наши элементы отображения выводятся на экран во время каждого «цикла рендеринга», нам нечего добавить в список отображения.

Прежде чем мы увидим это, нам понадобится способ перейти в это состояние. Давайте перейдем к нашему классу StartState и добавим следующее в обработчик onClick :

1
FlxG.state = new PlayState();

Вот как мы меняемся между состояниями в Flixel. Это действительно легко перейти от штата к штату. Как только вы сообщаете FlxG его новый класс состояний, дисплей автоматически отображает его. Существуют способы анимации между состояниями, но это выходит за рамки данного руководства. Давайте запустим демо, и когда вы нажмете, чтобы начать, вы увидите следующий пустой уровень.

preview_empty_play_state

Там выглядит действительно пусто, давайте добавим несколько символов.


В Frogger есть 3 основных «актера»:

  • Игрок: это лягушка, он может двигаться вверх, вниз, влево и вправо. На суше он не может пройти мимо нижней, левой и правой границ. В воде, если он уходит с экрана, он умирает.
  • Обертывающие объекты: это автомобили, грузовики, бревна и черепахи. Все движущиеся объекты в игре можно «обернуть». Это означает, что когда они уходят с экрана, они появляются на противоположной стороне и продолжают двигаться в том же направлении. Движущиеся объекты могут идти влево или вправо.
  • Объекты таймера: это объекты, которые перемещаются или, в случае домашних баз, не перемещаются и находятся на таймере. Когда таймер включен, они меняют состояние. Черепахи уходят под воду, а дома показывают бонус или аллигатора.

А сейчас давайте сосредоточимся на упаковке объектов. Создайте новый класс с именем WrappingSprite и настройте его следующим образом:

create_wrapping_sprite

И вот код для этого класса:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package com.flashartofwar.frogger.sprites.core
{
    import com.flashartofwar.frogger.enum.GameStates;
    import com.flashartofwar.frogger.states.PlayState;
 
    import org.flixel.FlxG;
    import org.flixel.FlxSprite;
 
    public class WrappingSprite extends FlxSprite
    {
 
        protected var leftBounds:int;
        protected var rightBounds:int;
        protected var state:PlayState;
 
        public var speed:int;
 
        /**
         * This is a base class for any sprite that needs to wrap around the screen when it goes out of
         * bounds.
         * the opposite site based on it’s direction.
         *
         * @param X start X
         * @param Y start Y
         * @param SimpleGraphic Use for sprites with no animations
         * @param dir Direction, supports Right (1) and Left (0)
         * @param speed how many pixel sprite will move each update.
         */
        public function WrappingSprite(X:Number = 0, Y:Number = 0, SimpleGraphic:Class = null, dir:uint = RIGHT, speed:int = 1)
        {
            super(X, Y, SimpleGraphic);
            this.leftBounds = 0;
            this.rightBounds = FlxG.width;
 
            this.speed = speed;
 
            facing = dir;
 
            state = FlxG.state as PlayState;
        }
 
        /**
         * This update methods analyzes the direction and x position of the instance to see if it should
         * be repositioned to the opposite side of the screen.
         * on the left of the screen.
         */
        override public function update():void
        {
 
            // Make sure the game state is Playing.
            if (state.gameState != GameStates.PLAYING)
            {
                return;
            }
            else
            {
                // Add speed to instance’s x based on direction
                x += (facing == LEFT) ?
 
                // Check to see if instance is out of bounds.
                if (x > (rightBounds))
                {
 
                    if (facing == RIGHT)
                    {
                        x = leftBounds — frameWidth;
                    }
 
                }
                else if (x < (leftBounds — frameWidth))
                {
 
                    {
                        x = rightBounds + frameWidth;
                    }
                }
 
            }
 
            // Call update
            super.update();
        }
    }
}

Я не собираюсь останавливаться на всей логике, но хочу выделить метод update() . Все FlxSprites имеют метод update() . Flixel использует то, что называется Game Loop. Это означает, что все в структуре синхронизируется до одного цикла для выполнения всех своих команд. Это может быть рендеринг инструкций, предварительные расчеты или просто игровая логика. В этом методе обновления мы проверяем состояние игры, подробнее об этом за секунду, если мы играем, то можно безопасно перемещать Объект.

Наша движущаяся логика проверяет наше направление и движется вдоль своей оси X. Если мы достигнем наших границ, экземпляр переместится на противоположную сторону экрана. Это может выглядеть много, но логика очень проста. Это будет иметь больше смысла, когда мы создадим наш первый WrappingSprite. Давайте сначала установим константы нашего игрового состояния.

Создайте новый класс с именем GameStates и настройте его следующим образом:

create_game_state

Вот наши штаты:

1
2
3
4
5
6
public static const PLAYING:uint = 0;
public static const COLLISION:uint = 1;
public static const RESTART:uint = 2;
public static const GAME_OVER:uint = 3;
public static const DEATH_OVER:uint = 4;
public static const LEVEL_OVER:uint = 5;

Нам также нужно будет добавить место для хранения состояния игры в нашем PlayState . Добавьте следующее свойство и оператор импорта:

1
public var gameState:uint;

Теперь наш PlayState может отслеживать глобальное состояние всей игры. Мы будем использовать это, чтобы разрешить / отключить анимацию, когда в игре происходят важные события. Наконец, давайте добавим правильное состояние в наш метод create() :

1
2
// Activate game by setting the correct state
gameState = GameStates.PLAYING;

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


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

create_car_class

И вот наш код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.flashartofwar.frogger.sprites
{
    import com.flashartofwar.frogger.sprites.core.WrappingSprite;
 
    public class Car extends WrappingSprite
    {
        public static const SPRITE_WIDTH:int = 40;
        public static const SPRITE_HEIGHT:int = 40;
 
        public static const TYPE_A:int = 0;
        public static const TYPE_B:int = 1;
        public static const TYPE_C:int = 2;
        public static const TYPE_D:int = 3;
 
        /**
         * Simple sprite to represent a car.
         * _C, and _D constant.
         *
         * @param x start X
         * @param y start Y
         * @param type type of car to use.
         * @param direction the direction the sprite will move in
         * @param speed the speed in pixels in which the sprite will move on update
         */
        public function Car(x:Number, y:Number, type:int, direction:int, speed:int)
        {
            super(x, y, null, direction, speed);
 
            loadGraphic(GameAssets.CarSpriteImage, false, false, SPRITE_WIDTH, SPRITE_HEIGHT);
 
            frame = type;
        }
    }
}

Как вы можете видеть, мы просто расширяем WrappingSprite здесь и за пределами хранения нескольких значений, мы просто определяем графику, используемую для спрайта Car. Как видите, есть 3 типа автомобилей. У нас также есть константа для ширины и высоты автомобиля, которую вы будете использовать, чтобы помочь выложить ее при настройке уровня. Прежде чем мы продолжим, давайте поговорим о том, как работает loadGraphic() .

Как я уже упоминал ранее, Flixel использует собственный класс для представления визуальных элементов вашей игры. Вам нужно загрузить графику, чтобы FlxSprite знал, как визуализировать себя. Когда дело доходит до простых спрайтов, таких как этот автомобиль, у которого нет анимации, его относительно легко настроить. Мы передаем ссылку на класс графического объекта, устанавливаем анимацию в false, устанавливаем реверс в false и предоставляем его ширину и высоту. В следующей строке мы устанавливаем тип рамы автомобиля. Это небольшой трюк, который вы можете сделать со спрайтами, чтобы сократить количество ресурсов для ввода. Взгляните на машину спрайта:

car_sprites

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


Давайте перейдем к нашему PlayState и добавим следующие методы:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
/**
 * Helper function to find the X position of a column on the game’s grid
 * @param value column number
 * @return returns number based on the value * TILE_SIZE
 */
public function calculateColumn(value:int):int
{
    return value * TILE_SIZE;
}
 
/**
 * Helper function to find the Y position of a row on the game’s grid
 * @param value row number
 * @return returns number based on the value * TILE_SIZE
 */
public function calculateRow(value:int):int
{
    return calculateColumn(value);
}

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

Frogger-фон

Каждая плитка размером 40 х 40 и состоит из 12 столбцов по 16 строк. В нашем фоне только 15 строк, потому что последняя строка, где начинается лягушка, черная, и нет смысла добавлять дополнительную строку в png, чтобы увеличить размер файла.

Вы также хотите, чтобы спрайты были как можно меньше, так как Flixel отобразит весь этот растровый рисунок на дисплее, прежде чем он сделает что-либо еще. Чем больше ваш фон, тем больше времени требуется для его рендеринга и всех других FlxSprites. Мы могли бы разбить это изображение еще больше, но чтобы сделать этот урок легким для восприятия, я сохранил фон как одно большое изображение.

Поскольку мы знаем размеры плитки, давайте добавим константу в наш класс PlayState .

1
private const TILE_SIZE:int = 40;

Теперь мы готовы начать добавлять автомобили на наш уровень. Перейдите к методу create() и добавьте следующие строки выше, где мы устанавливаем переменную состояния.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
// Create Cars
carGroup = add(new FlxGroup()) as FlxGroup;
 
carGroup.add(new Car(0, calculateRow(10), Car.TYPE_C, FlxSprite.RIGHT, 1));
carGroup.add(new Car(270, calculateRow(10), Car.TYPE_C, FlxSprite.RIGHT, 1));
 
carGroup.add(new Car(0, calculateRow(11), Car.TYPE_D, FlxSprite.LEFT, 1));
carGroup.add(new Car(270, calculateRow(11), Car.TYPE_D, FlxSprite.LEFT, 1));
 
 
carGroup.add(new Car(0, calculateRow(12), Car.TYPE_B, FlxSprite.RIGHT, 1));
carGroup.add(new Car((Car.SPRITE_WIDTH + 138) * 1, calculateRow(12), Car.TYPE_B, FlxSprite.RIGHT, 1));
carGroup.add(new Car((Car.SPRITE_WIDTH + 138) * 2, calculateRow(12), Car.TYPE_B, FlxSprite.RIGHT, 1));
 
carGroup.add(new Car(0, calculateRow(13), Car.TYPE_A, FlxSprite.LEFT, 1));
carGroup.add(new Car((Car.SPRITE_WIDTH + 138) * 1, calculateRow(13), Car.TYPE_A, FlxSprite.LEFT, 1));
carGroup.add(new Car((Car.SPRITE_WIDTH + 138) * 2, calculateRow(13), Car.TYPE_A, FlxSprite.LEFT, 1));

Теперь мы добавили все наши автомобили. Там много кода, но за ним должно быть легко следовать. Мы создаем то, что называется FlxGroup . Это отличный способ сгруппировать сходные спрайты вместе, и он пригодится, когда мы начнем обнаружение столкновений во второй части этого урока. Каждый автомобиль добавляется в нашу carGroup и он получает старт X, Y, тип, направление и скорость. Поскольку мы хотим, чтобы все наши автомобили всегда были правильно выстроены в ряды, мы используем метод calculatRow чтобы помочь расположить его в нужном месте.

Вам нужно будет импортировать классы FlxGroup и Car, а затем добавить следующее свойство:

1
private var carGroup:FlxGroup;

Вам также нужно будет импортировать классы Car и FlxGroup.

1
2
import com.flashartofwar.frogger.sprites.Car;
import org.flixel.FlxGroup;

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

preview_cars

Давайте добавим в некоторые грузовики.


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

create_truck_class

И вот код для класса:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
package com.flashartofwar.frogger.sprites
{
    import com.flashartofwar.frogger.sprites.core.WrappingSprite;
 
    public class Truck extends WrappingSprite
    {
        /**
         * This is a simple sprite which represents the Truck.
         *
         * @param X start X
         * @param Y start Y
         * @param dir direction the sprite will move in
         * @param speed speed in pixels the sprite will move on update
         */
        public function Truck(x:Number, y:Number, direction:uint, velocity:int)
        {
            super(x, y, GameAssets.TruckSpriteImage, direction, velocity);
        }
    }
}

Видишь как легко это было? Поскольку у нас нет анимации и есть только один тип грузовика, мы можем сделать его простым спрайтом и передать конструктору ссылку на актив Truck.

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

1
2
carGroup.add(new Truck(0, calculateRow(9), FlxSprite.LEFT, 1));
carGroup.add(new Truck(270, calculateRow(9), FlxSprite.LEFT, 1));

Если вы запустите игру, то увидите, что все наши грузовики и машины проносятся мимо.

preview_trucks

Журналы так же легко добавить, как наши грузовики. Давайте создадим новый класс Trucks и настроим его следующим образом:

create_logs

Вот код для класса Log:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.flashartofwar.frogger.sprites
{
    import com.flashartofwar.frogger.sprites.core.WrappingSprite;
 
    public class Log extends WrappingSprite
    {
        public static const TYPE_A:int = 0;
        public static const TYPE_B:int = 1;
        public static const TYPE_C:int = 2;
 
        public static const TYPE_A_WIDTH:int = 95;
        public static const TYPE_B_WIDTH:int = 196;
        public static const TYPE_C_WIDTH:int = 127;
 
        /**
         * Simple sprite to represent a log.
         * _C constant.
         *
         * @param x start X
         * @param y start Y
         * @param type type of car to use.
         * @param direction the direction the sprite will move in
         * @param speed the speed in pixels in which the sprite will move on update
         */
        public function Log(x:Number, y:Number, type:int, dir:int, velocity:int)
        {
 
            var graphicClass:Class;
 
            switch (type)
            {
                case TYPE_A:
                    graphicClass = GameAssets.LogSpriteImage1;
                    break;
                case TYPE_B:
                    graphicClass = GameAssets.LogSpriteImage2;
                    break;
                case TYPE_C:
                    graphicClass = GameAssets.LogSpriteImage3;
                    break;
            }
 
            super(x, y, graphicClass, dir, velocity);
 
        }
    }
}

И мы можем добавить наши журналы в PlayState выше, где мы создали наши автомобили и грузовики.

01
02
03
04
05
06
07
08
09
10
11
12
13
// Create logs
logGroup = add(new FlxGroup()) as FlxGroup;
 
logGroup.add(new Log(0, calculateRow(3), Log.TYPE_C, FlxSprite.RIGHT, 1));
logGroup.add(new Log(Log.TYPE_C_WIDTH + 77, calculateRow(3), Log.TYPE_C, FlxSprite.RIGHT, 1));
logGroup.add(new Log((Log.TYPE_C_WIDTH + 77) * 2, calculateRow(3), Log.TYPE_C, FlxSprite.RIGHT, 1));
 
logGroup.add(new Log(50, calculateRow(5), Log.TYPE_B, FlxSprite.RIGHT, 1));
logGroup.add(new Log(Log.TYPE_B_WIDTH + 120, calculateRow(5), Log.TYPE_B, FlxSprite.RIGHT, 1));
 
logGroup.add(new Log(0, calculateRow(6), Log.TYPE_A, FlxSprite.RIGHT, 1));
logGroup.add(new Log(Log.TYPE_A_WIDTH + 77, calculateRow(6), Log.TYPE_A, FlxSprite.RIGHT, 1));
logGroup.add(new Log((Log.TYPE_A_WIDTH + 77) * 2, calculateRow(6), Log.TYPE_A, FlxSprite.RIGHT, 1));

Вам также нужно будет создать новое свойство logGroup .

1
private var logGroup:FlxGroup;

Теперь вы можете запустить сборку ANT, чтобы увидеть журналы, плавающие в верхней части экрана.

Предварительный просмотр бревна

Как вы можете видеть, мы потратили большую часть нашего времени на создание базовых классов для нашей игры, поэтому добавить новые спрайты было бы очень просто. Также Flixel справляется со многими сложными вещами для вас, поэтому вы можете сосредоточиться на создании отличных Flash-игр.


Теперь мы готовы создать наш второй тип игрового объекта, TimerSprite . Давайте создадим новый класс с именем TimerSprite и настроим его так:

create_timersprite

Вот код для спрайта:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
+015
016
+017
018
019
020
021
022
023
024
025
026
027
028
029
+030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
+055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
package com.flashartofwar.frogger.sprites.core {
    import com.flashartofwar.frogger.enum.GameStates;
 
    import org.flixel.FlxG;
 
    public class TimerSprite extends WrappingSprite
    {
 
        public static const DEFAULT_TIME:int = 400;
 
        protected var timer:int;
        protected var hideTimer:int;
        protected var _active:Boolean = true;
 
        /**
         * The TimerSprite allows you to change states from active to inactive based on an internal timer.
         * This is useful for sprites that need to hide/show themselves at certain intervals.
         * to disable the internal timer, simply pass in -1 for the start time.
         *
         * @param x start x
         * @param y start y
         * @param SimpleGraphic used for sprites that don’t need to show an animation
         * @param delay this represents the delay between switching states
         * @param startTime this is the time in which the timer starts.
         * @param dir This represents the direction the sprite will be facing
         * @param speed This is the speed in pixels the sprite will move on update
         */
        public function TimerSprite(x:Number, y:Number, SimpleGraphic:Class = null, delay:int = DEFAULT_TIME, startTime:int = DEFAULT_TIME, dir:uint = RIGHT, speed:int = 1)
        {
 
            super(x, y, SimpleGraphic, dir, speed);
 
            this.hideTimer = delay;
            timer = startTime;
        }
 
        /**
         * This updates the internal timer and triggers toggle when equal to 0
         */
        override public function update():void
        {
 
            if (state.gameState == GameStates.PLAYING)
            {
                if (timer > 0)
                    timer -= FlxG.elapsed;
 
                if (timer == 0)
                {
                    toggle();
                }
            }
 
            super.update();
 
        }
 
        /**
         * Getter returns if the instance is active or not.
         *
         * @return a boolean, true is active and false is inactive
         */
        public function get isActive():Boolean
        {
            return _active;
        }
 
        /**
         * This is a simple toggle between active and deactivated states.
         */
        protected function toggle():void
        {
            if (!isActive)
            {
                onActivate();
            }
            else
            {
                onDeactivate();
            }
 
            timer = hideTimer;
        }
 
        /**
         * Toggles the _activate variable signaling that it is no longer active.
         */
        protected function onDeactivate():void
        {
            _active = false;
        }
 
        /**
         * Toggles the _activate variable signaling that it is now active.
         */
        protected function onActivate():void
        {
            _active = true;
        }
    }
}

Как вы можете видеть, мы расширяем наши возможности, WrappingSpriteчтобы TimerSpriteможно было оборачивать их, а также добавляли логику для включения / выключения. В этом update()методе вы также заметите, что для отслеживания того, сколько времени прошло, мы полагаемся на внутренние часы Flixel. Ваш первый инстинкт, возможно, должен был сделать:

1
timer --;

Но при работе с Flixel вы хотите, чтобы ваше время всегда было синхронизировано с основным игровым циклом. Вот почему FlxGделает elapsedдоступным геттер.

Когда таймер достигает 0, мы вызываем, toggle()и начинается какое-то действие. Этот класс является AbstractClassпросто и имеет достаточно кода, чтобы помочь настроить дочерние классы, которые расширяют его. Дочерние классы отвечают за переопределение предоставленных методов своей собственной логикой. Также важно отметить, что если вы установите значение таймера на -1, таймер не будет отсчитывать, и вся логика таймера будет игнорироваться. Это отличный способ отключить TimerSprite. Давайте посмотрим, как мы можем использовать этот класс, добавляя черепах.


Теперь мы готовы создавать наших черепах. Ничего нового здесь, это так же, как наши другие спрайты. Создайте новый TurtlesAкласс и настройте его следующим образом:

create_turtles_a

Причина, по которой мы дали этому классу суффикс «А», заключается в том, что в нашей игре есть два типа черепах; те, которые плавают как бревна, и те, которые могут уйти под воду. Это основная черепаха, поэтому мы можем сохранить логику простой. Нам просто нужно знать, сколько черепашек визуализировать, и это делается аналогично тому, как мы настраиваем наши машины. Вот код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.flashartofwar.frogger.sprites
{
    import com.flashartofwar.frogger.sprites.core.TimerSprite;
 
    public class TurtlesA extends TimerSprite
    {
         
        public static const SPRITE_WIDTH:int = 65;
        public static const SPRITE_HEIGHT:int = 40;
        public static const DEFAULT_TIME:int = 300;
 
        /**
         * This represents the Turtles the player can land on.
         *
         * @param x start X
         * @param y start Y
         * @param delay This represents the amount of time before toggling active/deactivate
         * @param startTime where the timer should start. Pass in -1 to disable the timer.
         * @param speed speed in pixels the turtle will move in
         */
        public function TurtlesA(x:Number, y:Number, delay:int = DEFAULT_TIME, startTime:int = DEFAULT_TIME, dir:uint = RIGHT, speed:int = 1)
        {
            super(x, y, null, delay, startTime, dir, speed);
 
            loadGraphic(GameAssets.TurtlesSpriteImage, true, false, SPRITE_WIDTH, SPRITE_HEIGHT);
 
            addAnimation("idle", [0], 0, false);
            addAnimation("hide", [1, 2, 3], 3, false);
            addAnimation("show", [3, 2, 1, 0], 3, false);
        }
 
        /**
         * Checks to see what frame the turtle is on and can be used to see if turtle is underwater or not.
         * @return if frog is totally underwater it will return false, if not true
         */
        override public function get isActive():Boolean
        {
            false : true;
        }
 
        /**
         * Makes turtle appear out of water.
         */
        override protected function onActivate():void
        {
            super.onActivate();
            play("show");
        }
 
        /**
         * Makes turtle go underwater
         */
        override protected function onDeactivate():void
        {
            super.onDeactivate();
            play("hide");
        }
 
    }
}

Наконец-то у нас появилась анимация для настройки. Используя addAnimation()метод, встроенный в Flixel, мы можем указать игровому движку, какие кадры играть, основываясь на состоянии Sprite. Давайте посмотрим на черепаху спрайт.

turtle_2_sprites

Здесь вы увидите, что у нас есть несколько кадров для анимации нашей черепахи. Анимации привязаны к метке, здесь мы видим простоя, прячемся и показываем. Мы также сообщаем Flixel, в каком порядке анимировать кадры и на какой скорости. Мы можем воспроизводить анимацию в любое время, позвонив play()и предоставив название анимации. Если вы заметите в нашем, onActivate()и onDeactivateмы запустим анимацию показать / скрыть, чтобы черепаха могла уйти под воду.

Теперь давайте добавим несколько черепах к нашему PlayState. Поместите этот код прямо над кодом logGroup.

1
2
3
4
5
6
// Create turtles
turtleGroup = add(new FlxGroup()) as FlxGroup;
 
turtleGroup.add(new TurtlesA(0, calculateRow(4), -1, -1, FlxSprite.LEFT, 1));
turtleGroup.add(new TurtlesA((TurtlesA.SPRITE_WIDTH + 123) * 1, calculateRow(4), TurtlesA.DEFAULT_TIME, 200, FlxSprite.LEFT, 1));
turtleGroup.add(new TurtlesA((TurtlesA.SPRITE_WIDTH + 123) * 2, calculateRow(4), -1, -1, FlxSprite.LEFT, 1));

Вам также нужно будет импортировать TurtlesAкласс и добавить следующее свойство.

1
private var turtleGroup:FlxGroup;

Если вы запустите сборку ANT, вы увидите наших черепах и сможете наблюдать за их погружением под воду.

preview_turtles

Далее мы добавим 3 спрайта Черепах.


Теперь пришло время добавить еще один набор Черепах. Это группа из 3 черепах, которая будет работать точно так же, как наша группа из двух черепах. Давайте создадим новый класс TurtlesBи настроим его так:

create_turtles_b

Теперь добавьте следующий код.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.flashartofwar.frogger.sprites
{
    public class TurtlesB extends TurtlesA
    {
         
        public static const SPRITE_WIDTH:int = 99;
        public static const SPRITE_HEIGHT:int = 40;
        public static const DEFAULT_TIME:int = 300;
 
        /**
         * This represents the Turtles the player can land on.
         *
         * @param x start X
         * @param y start Y
         * @param delay This represents the amount of time before toggling active/deactivate
         * @param startTime where the timer should start. Pass in -1 to disable the timer.
         * @param speed speed in pixels the turtle will move in
         */
        public function TurtlesB(x:Number, y:Number, hideTimer:int = DEFAULT_TIME, startTime:int = DEFAULT_TIME, dir:uint = RIGHT, velocity:int = 40)
        {
            super(x, y, hideTimer, startTime, dir, velocity);
 
            loadGraphic(GameAssets.TurtlesBSpriteImage, true, false, SPRITE_WIDTH, SPRITE_HEIGHT);
 
        }
 
    }
}

Поскольку у нас TurtlesAесть вся основная логика, необходимая нам для запуска черепахи, мы просто меняем графику на наш 3 черепахи. Все наши наборы анимации также будут сохранены. Добавьте следующий код в ваш PlayStateкласс под TurtleAссылками, которые мы добавили на последнем шаге.

1
2
3
turtleGroup.add(new TurtlesB(0, calculateRow(7), TurtlesA.DEFAULT_TIME, 0, FlxSprite.LEFT, 1));
turtleGroup.add(new TurtlesB((TurtlesB.SPRITE_WIDTH + 95) * 1, calculateRow(7), -1, -1, FlxSprite.LEFT, 1));
turtleGroup.add(new TurtlesB((TurtlesB.SPRITE_WIDTH + 95) * 2, calculateRow(7), -1, -1, FlxSprite.LEFT, 1));

После того, как вы импортировали TurtlesBкласс, вы можете запустить сборку ANT и увидеть всех черепах.

preview_turtles_b

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

bonus_sprites

Давайте создадим Homeкласс и настроим его так:

create_home
001
002
003
004
005
006
007
008
009
010
011
012
013
014
+015
016
+017
018
019
020
021
022
023
024
025
026
027
028
029
+030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
+055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package com.flashartofwar.frogger.sprites
{
    import com.flashartofwar.frogger.sprites.core.TimerSprite;
 
    public class Home extends TimerSprite
    {
 
        public static const SPRITE_WIDTH:int = 40;
        public static const SPRITE_HEIGHT:int = 40;
        public static const BONUS:int = 0;
        public static const NO_BONUS:int = 1;
        public static const SUCCESS:int = 2;
        public static const EMPTY:int = 3;
        public var mode:uint;
        public var odds:uint;
 
        /**
         * Home represents the sprite the player lands on to score points and help complete a level.
         * The home has 4 states Empty, Success, No Bonus, and Bonus
         *
         * @param x start X
         * @param y start Y
         * @param delay This represents the amount of time before toggling active/deactivate
         * @param startTime where the timer should start. Pass in -1 to disable the timer.
         * @param odds the randomness that one of the 3 states will be reached (empty, bonus, or no bonus)
         */
        public function Home(x:Number, y:Number, delay:int = TimerSprite.DEFAULT_TIME, startTime:int = TimerSprite.DEFAULT_TIME, odds:int = 10)
        {
            super(x, y, null, delay, startTime, 0, 0);
 
            this.odds = odds;
 
            loadGraphic(GameAssets.HomeSpriteImage, false, false, SPRITE_WIDTH, SPRITE_HEIGHT);
            addAnimation("empty", [EMPTY], 0, false);
            addAnimation("bonus", [BONUS], 0, false);
            addAnimation("noBonus", [NO_BONUS], 0, false);
            addAnimation("success", [SUCCESS], 0, false);
 
            play("empty");
 
        }
 
        override protected function onDeactivate():void
        {
            super.onDeactivate();
            showEmpty();
        }
 
        /**
         * On active draw a random number based on the odds and see what state should be shown.
         */
        override protected function onActivate():void
        {
            super.onActivate();
 
            var id:uint = Math.random() * odds;
 
            switch (id)
            {
                case(BONUS):
                    showBonus();
                    break;
                case(NO_BONUS):
                    showNoBonus();
                    break;
                default:
                    showEmpty();
                    break;
            }
        }
 
        /**
         * Shows empty state
         */
        private function showEmpty():void
        {
            play("empty");
        }
 
        /**
         * Shows no bonus state
         */
        private function showNoBonus():void
        {
            play("noBonus");
        }
 
        /**
         * Show bonus state
         */
        private function showBonus():void
        {
            play("bonus");
        }
 
        /**
         * Show success state
         */
        public function success():void
        {
            play("success");
            timer = -1;
        }
 
        /**
         * Reset the sprite to the empty state and restart the timer.
         */
        public function empty():void
        {
            setMode(EMPTY, "empty");
            timer = hideTimer;
        }
 
        /**
         * private method to set the state of the sprite.
         *
         * @param mode what mode should the sprite be in Empty, Bonus, No Bonus or Success
         * @param animationSet What animation set should it use to display the state
         */
        protected function setMode(mode:int, animationSet:String):void
        {
            //TODO This should be consolidated to use the same mode int
            this.mode = mode;
            play(animationSet);
        }
 
    }
}

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

1
2
3
4
5
6
7
8
9
// Create home bases sprites and an array to store references to them
bases = new Array();
homeBaseGroup = new FlxGroup();
add(homeBaseGroup);
bases.push(homeBaseGroup.add(new Home(calculateColumn(0) + 15, calculateRow(2), 200, 200)));
bases.push(homeBaseGroup.add(new Home(calculateColumn(3) - 5, calculateRow(2), 200, 200)));
bases.push(homeBaseGroup.add(new Home(calculateColumn(5) + 20, calculateRow(2), 200, 200)));
bases.push(homeBaseGroup.add(new Home(calculateColumn(8), calculateRow(2), 200, 200)));
bases.push(homeBaseGroup.add(new Home(calculateColumn(11) - 15, calculateRow(2), 200, 200)));

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

1
2
private var bases:Array;
private var homeBaseGroup:FlxGroup;

Теперь запустите ANT Build, и вы увидите, что верхние строки заполнены случайной базовой графикой.

preview_home

Итак, мы многое рассмотрели в этом уроке! Вы узнали, как запускать Flixel, создавать и переключаться между игровыми состояниями, и, наконец, основы создания новых спрайтов и привязывания их к уровню. В следующем уроке мы расскажем, как создать игрока, переместить его, добавить обнаружение столкновений и многое другое. Если у вас нет терпения ждать следующей части ( редактор: мы говорим только неделю, Джесси!), Вы всегда можете проверить полный исходный код FlxFrogger из GitHub .