Итак, с основным фишками разобрались, даже что-то удалось написать и это работало :) Пора браться за какую-нибудь серьезную задачу, чтобы получше освоиться в AS3. Думаю, лучше всего создать веселую игрушку. Например, такой вариант. Космическое пространство, планета, на планету летят астероиды и кометы (типа земля попала в полосу невезения :), твоя задача защитить планету от полного уничтожения. Можно ставить в любом месте защитные автоматические турели. Для начала два типа: 1 – лазерная, стреляет часто, но слабо. 2 – ракетная, разносит все в клочья в радиусе взрыва ракеты, но стреляет редко. Добавить еще большие кометы, которые дробятся на мелкие астероиды.
Создаем новую флешку, размером 800x400 (от балды), частота кадров 21 (в какой-то статье было доказано, что такая частота оптимальна).
Т.к. в игре будет достаточно картинок, звуков и анимации итоговый вес флешки будет приличным, необходимо отобразить процесс загрузки игры. Делаем мувик preloader который состоит из текстового поля (txt) и прогрессбара (progress - мувик состоящий из 100 кадров, будем позиционировать кадр в зависимости от того, сколько процентов флешки загрузилось). Мувиклипу прелоадера прописываем класс main.preloader со следующим кодом:
Обратите внимание, класс должен быть динамичным (dynamic) иначе компилятор будет ругаться:
Cannot create property txt on preloader.
Т.е. не может создать новое свойство txt (это наше вложенное текстовое поле) в нединамичном классе.
На первом фрейме флешки пишем
Создаем второй фрейм куда кладем большую картинку, чтобы протестировать процесс отображения загрузки.
Теперь нужно выяснить, как узнать, сколько процентов нашей флешки в данный момент загрузилось. Смотрим по таблице соответствий AS2-AS3 (http://livedocs.macromedia.com/flex/2/langref/migration.html) куда дели функцию getBytesLoaded(), нас отсылают к классу URLLoader.bytesLoaded, но этот класс используется для загрузки внешних мувиков и картинок, а нам надо узнать процент загрузки самого себя. После внимательного просмотра всех свойств видимых объектов (DisplayObject) обнаружил свойство loaderInfo, это ссылка на того, кто загружал этот объект. А у класса LoaderInfo есть свойства bytesLoaded и bytesTotal . Нам нужно узнать, сколько байт загрузилось у всей флешки, т.е. у stage. Тесты показали, что stage.loaderInfo.bytesLoaded правильно возвращает, сколько байт загрузилось, а вот stage.loaderInfo.bytesTotal стабильно возвращает ноль! Решив, что это глюк при локальной загрузке, залил флешку на сервер и убедился, что при загрузке с сайта bytesTotal нормально возвращает общий размер флешки. Спишем эти глюки на альфаверсию Flash 9.
С проверкой bytesTotal на ноль функция Update принимает следующий вид:
Локально увидеть процесс загрузки не удастся, но тесты через сервер показали, что все нормально отображается. Обратите внимание, после того, как прелоадер выполнил свою задачу нужно удалить себя из обработки ENTER_FRAME (функция removeEventListener), иначе Update продолжает вызываться и после перехода на второй кадр (хоть там уже нет нашего мувика, что весьма странно).
Игровое поле должно быть довольно большим, по нему можно перемещаться «таская» мышкой. В качестве фона на гугле найдем большую картинку звездного неба. Создаем новый MovieClip с именем background и вставляем в него картинку (размер картинки 2000x2000). В Linkage мувика ставим галочку «Export for ActionScript», класс main.background, и убираем галочку с «Export in first frame» (иначе этот мувик и все остальные, у которых будет стоять «Export in first frame», станут грузиться вместе с первым кадром флешки, и прелоадинга как такового не будет).
Напишем класс main.background, в котором реализуем его «таскание» мышкой. Делаем обычный drag:
При таком решении будет наблюдаться один маленький баг: нажать кнопку мыши на мувике, вывести мышку за пределы флешки, отпустить кнопку и провести курсор по флешке. Мувик будет продолжать таскаться при отпущенной кнопке мыши! Т.к. событие отпускание кнопки мыши за пределами флешки не обрабатывается и stopDrag() не сработал. Нужно ставить какую-то заглушку, вижу два варианта:
1. Отлавливать выход мышки за пределы флешки (есть такое новое событие mouseLeave в классе Stage)
2. Отлавливать перемещение мышки и если мы находимся в состоянии таскания, а кнопка мыши отпущена, принудительно сделать stopDrag()
Опробуем новые методы:
Интересно, что это событие срабатывает не тогда, когда реально мышка вышла за пределы флешки, а только тогда, когда отпустят кнопку мыши за пределами… но это уже мелочи.
И нужно задать пределы перетаскивания, а то можно утащить наше небо вообще за край. Для этого в startDrag задаем пределы перетаскивания:
Отлично, с перетаскиванием неба закончили.
Теперь необходимо создать базовый класс любого объекта, который будет в нашей игре. Т.к. в космосе в основном сферические объекты, то основными параметрами нашего объекта должны быть: координата и радиус. В качестве координаты используем x,y мувика. И нужна функция проверки столкновения двух объектов. Т.к. любой объект в игре будет иметь изображение и, скорее всего анимированное, то наследуемся от класса MovieClip (если нет анимации, то лучше наследоваться от класса Sprite).
Теперь из этого класса создадим первый статичный космический объект – класс static_object
Наверное, позже статичным объектам добавим какие-то свойства, например, гравитацию, а пока он пустой, инициализируем только радиус. Создадим мувик Earth, имя класса main.static_object (экспорт в первом фрейме не забываем отключать) и вставляем туда картинку нашей планеты (google рулит!). Если мувик с землей просто положить на сцену поверх мувика космоса, то они никак не будут взаимодействовать и при перетаскивании звездного неба земля остается на месте. Космических объектов будет много их необходимо перемещать, рассчитывать столкновения и т.п., поэтому необходимо создать базовый класс (мувиклип), в котором все и будет размещаться и рассчитываться. Создаем мувиклип sky, класс main.sky в него кладем мувиклип со звездным небом (назовем bg) и мувик с землей (назовем earth). Маленькая поправка в классе background (со звездным небом), т.к. двигаться должно не только небо, но и все объекты над ним, то startDrag делаем у родителя:
И аналогично stopDrag()
Запускаем, тестируем. Небо есть, земля есть, все нормально таскается мышкой.
Рис. 2
Пора создать первый астероид. Это будет продолжение нашего базового класса basic_object, движущийся объект moving_object. У него должно быть направление движения и скорость. Это лучше определить, как вектор. Не изобретая велосипед, берем готовый класс Vector из примера Macromedia, про рыбок Boids.
Создаем новый мувиклип asteroid, класс main.moving_object. В него вставляем несколько изображений астероидов по одному на каждый кадр (если все астероиды будут выглядеть одинаково, будет совсем некрасиво). При инициализации рандомно выбираем изображение астероида и делаем gotoAndStop() на выбранный кадр:
Бросаем мувик астероида внутрь нашего основного sky, запускаем… стоит астероид на месте, ошибок компиляции нет, что уже хорошо. Астероиды будут появляться рандомно за границей игрового поля и лететь в сторону земли. Если это будет полный рандом – не интересно, лучше если астероиды будут прилетать небольшой группой, поэтому делаем функцию drop, вбросить астероид рядом с указанной координатой и двигаться в указанном направлении:
Цифры констант поставлены от балды, когда астероиды реально полетят, то подгоним под нормальные значения. Для теста, попробуем вбросить десять астероидов в видимой области (200:200), код в главном классе sky будет следующий
Запускаем – пусто… Что не так? В мувике астероида убрана галочка «Export in first frame», т.е. мувик не грузится в первом кадре флешки, а будет загружаться в том кадре, в котором он поставлен на TimeLine. Я забыл добавить мувик астероида на TimeLine и соответственно он так и не был загружен вообще. Исправляюсь, бросаю его за пределами звездного поля, чтобы не был виден. Запускаем:
Рис. 3
Ура, астероиды появились, рандомно скучковались. То, что есть астероиды, которые пересекаются не страшно, у нас все равно будет проверка столкновений и отскоков, а вбрасываться астероиды будут за областью видимости и когда влетят в поле зрения, они уже растолкаются. Это даже хорошо, создаст дополнительный рандом в траекториях их движений.
Ну, пора уже заставить их летать! Для этого в главном классе sky нужно создать массив, в который будут заноситься все движущиеся объекты. Сделать функцию, которая вызывается по EnterFrame и поставить обход всего массива с вызовом функции move объектам. В классе moving_object пишем:
А главный класс sky приобретает следующий вид.
Летают! Сразу видны недочеты:
1. все летят строго в центр планеты. И в конце просто выстраиваются в одну прямую. Стоит при вбрасывании добавить рандом к x2:y2.
2.астероидам стоит придать небольшое вращение. Поскольку это не 3D объект, то просто будем поворачивать картинку вокруг своей оси.
При инициализации moving_object:
Можно посмотреть, что же получилось. Первый результат: нажать правой кнопкой мыши и выбрать play, должны появиться пролетающие астероиды. Небо можно "таскать" мышкой