В этом выпуске мы рассмотрим создание 3D-заставок с использованием Papervision3D. В этом процессе мы также рассмотрим использование реальной реализации шаблона Singleton и создадим аккуратный класс «CustomLoader», который позволит вам предварительно загружать и ставить в очередь изображения и звуки, а затем сразу отключать их все.
Все это завершается многоразовой и очень гибкой системой для создания 3D-заставок.
Шаг 1: Создайте новый проект
Откройте FlashDevelop и нажмите «Проект»> «Новый проект» …
Шаг 2: настройка
Выберите Actionscript 3> AS3 Project.
Для названия проекта положить в Intro3D.
Для определения местоположения щелкните и перейдите в папку, в которую вы хотите сохранить ее. Оставьте флажок «Создать каталог для проекта» установленным и нажмите «ОК».
Если вы хотите использовать Flash CS3 +, создайте новый файл Flash и установите ширину и высоту 600×350, установите черный цвет фона и частоту кадров 30. Назовите его intro3D.fla и сохраните в любом месте.
Шаг 3: Папка PV3Dassets
Для FlashDevelop откройте каталог проекта и скопируйте или перетащите папку PV3Dassets из исходной загрузки (ссылка вверху страницы) в папку \ bin \.
Для Flash скопируйте или перетащите папку PV3Dassets из исходной загрузки в ту же папку, где находится intro3D.fla.
Также давайте рассмотрим содержимое этой папки. У нас есть 8 изображений в формате Portable Network Graphics (PNG) и 4 MP3.
Шаг 4: Установите TweenLite и Papervision3D
Мы собираемся использовать TweenLite для анимации движения и Papervision для 3D. Оба пакета включены в исходный код загрузки. Для получения дополнительной информации, вы можете посетить их сайты на papervision и tweenlite .
Для FlashDevelop, скопируйте или перетащите greensock.swc и Papervision3D_2.1.932.swc из исходного кода в папку \ lib \ для этого проекта.
В FlashDevelop нажмите «Просмотр»> «Диспетчер проектов».
Шаг 5: Внешние библиотеки
Находясь в FlashDevelop, щелкните значок «+» слева от папки lib, чтобы развернуть ее.
Выберите оба файла SWC и щелкните правой кнопкой мыши, выберите «Добавить в библиотеку».
Для Flash скопируйте или перетащите папки \ com \, \ org \ и \ nochump \ из исходной загрузки в ту же папку, что и файл intro3D.fla.
Шаг 6: Создание класса Singleton CustomLoader
Давайте начнем работать с классом CustomLoader. Нам нужен класс, который упростит загрузку и доступ к типам внешних ресурсов, которые мы используем для этого проекта. Кроме того, нам необходимо иметь доступ к этим ресурсам из любой точки программы. Это означает, что в течение всего времени существования программы должен существовать только 1 экземпляр класса. Шаблон Singleton — это то, что нам нужно для этой работы. Для получения дополнительной информации о шаблоне, вы можете перейти сюда . Кроме того, Эдуардо Гонсалес, один из авторов Activetuts +, опубликовал статью о паттерне Singleton. Вы можете проверить это здесь .
ПРИМЕЧАНИЕ. Если вы используете Flash, просто следуйте инструкциям, чтобы понять ответственность этого класса, а затем перейдите к шагу 17.
Для FlashDevelop нажмите «Просмотр»> «Диспетчер проектов», щелкните правой кнопкой мыши папку \ src \ и выберите «Добавить»> «Новый класс».
Откроется окно New Actionscript Class. В качестве имени введите CustomLoader, для базового класса введите flash.events.EventDispatcher.
Нажмите «ОК», чтобы закончить.
Класс расширяет EventDispatcher, чтобы иметь возможность отправлять события, когда это необходимо.
Давайте теперь поработаем над структурой класса, чтобы он вел себя как синглтон.
Прямо под объявлением класса добавьте следующие статические переменные:
1
2
|
private static var _allowed:Boolean;
private static var _customLoader:CustomLoader;
|
Эти статические переменные будут гарантировать, что класс создает только 1 экземпляр класса CustomLoader и предоставят доступ к нему.
Шаг 7: Ответственность класса CustomLoader
Вот список того, что должен делать этот класс.
- Загрузка внешних активов (визуальные и звуковые активы).
- Выдать список имен всех активов, которые были загружены.
- Сообщите слушателю, когда все активы были успешно загружены.
- Предоставьте актив по запросу.
- Если что-то пойдет не так, отправьте ошибку.
Добавьте следующие строки кода после пробела ниже статической переменной _customLoader
.
1
2
3
4
5
|
private var _imageArray:Array;
private var _imageURLs:Array;
private var _loadCount:uint;
private var _soundURLs:Array;
private var _soundArray:Array;
|
Массив _imageArray
будет содержать пары имя = значение всех визуальных ресурсов, включенных в его загрузчик. Таким образом, не имеет значения, какой тип визуального актива (swf, bitmap), мы просто ссылаемся на его загрузчик и безопасное приведение при использовании. Подробнее об этом позже. Массив _imageURLs
будет содержать строки URL-адреса, которые будут передаваться каждый раз, когда визуальный актив запрашивается для загрузки. _loadCount
будет увеличиваться на 1 каждый раз, когда загрузка успешна. Массив _soundURLs
будет содержать строки URL-адреса, переданные каждый раз, когда звуковой актив запрашивается для загрузки. В массиве _soundArray
будут храниться пары «имя = значение» всех звуковых активов.
Нам нужна 1 открытая константа для отправки как пользовательское событие, когда все загрузки завершены. Над объявлением статической переменной _allowed
добавьте следующую строку кода:
1
|
public static const ALL_LOADS_COMPLETE:String = ‘allLoadsComplete’;
|
Это завершает свойства класса CustomLoader. Далее, метод конструктора.
Шаг 8: метод конструктора CustomLoader
Это будет немного отличаться от обычного конструктора. Здесь создание экземпляров предотвращается, если переменная _allowed
не установлена в значение true. Ошибка также выдается, когда этот метод вызывается ненадлежащим образом. С другой стороны, если для _allowed
установлено значение true, то вызывается метод init()
и создается экземпляр.
Добавьте следующие строки кода внутри конструктора:
1
2
3
4
5
6
|
if (! _allowed)
{
throw new Error (‘This is a Singleton, please use CustomLoader.getInstance ()’);
return;
}
init ();
|
Метод init ()
просто создает 4 массива. Под конструктором добавьте следующие строки кода:
1
2
3
4
5
6
7
|
private function init ():void
{
_imageArray = new Array;
_imageURLs = new Array;
_soundURLs = new Array;
_soundArray = new Array;
}
|
Шаг 9: метод getInstance () CustomLoader
Это единственный способ создать и получить доступ к экземпляру CustomLoader. Этот публичный статический метод обеспечивает полную доступность. Если _customLoader
еще не был назначен экземпляр, _allowed
устанавливается в значение true, а переменной _customLoader
назначается новый экземпляр, а затем возвращается. Если у _customLoader
уже есть экземпляр, он просто возвращается.
Добавьте следующие строки кода сразу после метода init ()
:
01
02
03
04
05
06
07
08
09
10
|
public static function getInstance ():CustomLoader
{
if (! _customLoader)
{
_allowed = true;
_customLoader = new CustomLoader;
_allowed = false;
}
return _customLoader;//happens either way
}
|
Шаг 10: CustomLoader Добавление визуальных и звуковых ресурсов в очередь
Поскольку у нас есть, по существу, 2 типа ресурсов для загрузки (визуальные активы и звуковые активы), я создал 2 метода для обработки этих двух типов. Все, что им нужно сделать, это продолжать добавлять URL в массивы _imageURLs
и _soundURLs
. Поэтому, если у вас есть ресурсы для загрузки, просто продолжайте вызывать соответствующий метод и передавайте URL ресурса, который вы хотите загрузить, и они будут храниться в соответствующем массиве. Метод addItem ()
добавляет URL-адрес визуального ресурса в массив _imageURLs
а метод addSound ()
добавляет URL-адрес звукового ресурса в массив _soundURLs
.
Добавьте следующие строки кода после метода getInstance ()
:
1
2
3
4
5
6
7
8
9
|
public function addItem ($url:String):void
{
_imageURLs.push ($url);
}
public function addSound ($url:String):void
{
_soundURLs.push ($url);
}
|
Шаг 11: CustomLoader метод startLoading ()
Мы вызываем этот публичный метод, как только мы назначим все активы, которые хотим загрузить. Сначала он _imageURLs
массив _imageURLs
, создает экземпляр Loader
для хранения визуального актива, а затем назначает _imageArray
имя = значение. Имя обрабатывается с помощью assignShortName ()
который будет создан и вскоре будет assignShortName ()
. Как я уже упоминал ранее, мы используем Loader
чтобы избежать проблем приведения типа визуального актива. Вы увидите, как получить доступ к активам, когда мы доберемся до класса Intro3D
. IOErrorEvent.IO_ERROR
Event.COMPLETE
и IOErrorEvent.IO_ERROR
затем назначаются для прослушивания, когда загрузка завершается или завершается неудачей. Наконец, мы загружаем актив.
Затем другой цикл повторяется в массиве _soundURLs
для обработки загрузки всех звуковых ресурсов. Процесс загрузки звуковых ресурсов очень похож на загрузку визуальных активов. Во втором цикле создается экземпляр Sound
, назначаемый в виде пары имя = значение в _soundArray
, присоединяемые прослушиватели для загрузки результатов и последующей загрузки.
Добавьте следующие строки кода после addSound ()
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public function startLoading ():void
{
for (var i:uint = 0; i < _imageURLs.length; i++)
{
var loader:Loader = new Loader
_imageArray[assignShortName (_imageURLs[i])] = loader;
loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onLoadComplete);
loader.contentLoaderInfo.addEventListener (IOErrorEvent.IO_ERROR, onLoadError);
loader.load (new URLRequest (_imageURLs[i]));
}
for (i = 0; i <
_soundURLs.length;
{
var sound:Sound = new Sound;
_soundArray[assignShortName (_soundURLs[i])] = sound;
sound.addEventListener (Event.COMPLETE, onLoadComplete);
sound.addEventListener (IOErrorEvent.IO_ERROR, onLoadError);
sound.load (new URLRequest (_soundURLs[i]));
}
}
|
Шаг 12: CustomLoader Извлечение короткого имени
Теперь давайте займемся извлечением короткого имени из URL-адреса загружаемого ресурса. Помните, что это будет работать только с активами, которые находятся внутри папки, которая находится в том же месте, что и сгенерированный файл SWF. В этом конкретном случае, если вы используете FlashDevelop, папка PV3Dassets должна находиться в папке \ bin \. Для Flash он должен находиться в той же папке, что и ваш файл intro3D.fla.
Этот метод просто удаляет имя папки, а затем сокращает расширение файла. Для иллюстрации, с URL «PV3Dassets / dot0.png», «PV3Dassets» удаляется, затем «.png» обрезается, оставляя короткое имя «dot0».
Добавьте следующие строки кода после startLoading ()
:
1
2
3
4
|
private function assignShortName($url:String):String
{
return $url.split (‘/’)[1].split(‘.’)[0];
}
|
Шаг 13: CustomLoader отправляет событие ALL_LOADS_COMPLETE
Метод onLoadComplete ()
вызывается при каждой успешной загрузке визуального или звукового ресурса. Все, что он делает — это предварительно увеличивает _loadCount
на 1 каждый раз, когда загрузка завершается, затем проверяет, соответствуют ли длины и _imageURLs
и _soundURLs
_loadCount
. Если это так, CustomLoader.ALL_LOADS_COMPLETE
событие CustomLoader.ALL_LOADS_COMPLETE
.
Добавьте следующие строки кода после assignShortName ()
:
1
2
3
4
5
6
7
|
private function onLoadComplete (e:Event):void
{
if (_imageURLs.length + _soundURLs.length == ++_loadCount)
{
dispatchEvent (new Event (ALL_LOADS_COMPLETE));
}
}
|
Шаг 14: CustomLoader прослушивает ошибки
Метод onLoadError ()
вызывается всякий раз, когда происходит сбой загрузки визуального или звукового ресурса. При этом вы узнаете, останавливается ли программа из-за ошибок при загрузке.
Добавьте следующие строки кода после onLoadErrorComplete ()
:
1
2
3
4
5
|
private function onLoadError(e:IOErrorEvent):void
{
//internal use
throw new Error (e);
}
|
Шаг 15: CustomLoader Доступ к активам для использования
Мы можем начать использовать ресурсы, когда CustomLoader.ALL_LOADS_COMPLETE
событие CustomLoader.ALL_LOADS_COMPLETE
. Чтобы получить визуальный актив, мы вызываем метод getItem ()
передавая в качестве параметра короткое имя (в формате String). Чтобы получить звуковой актив, мы вызываем метод getSound ()
также передавая короткое имя звука.
Добавьте следующие строки кода после onLoadError ()
:
1
2
3
4
5
6
7
8
9
|
public function getItem ($name:String):Loader
{
return _imageArray[$name];
}
public function getSound ($name:String):Sound
{
return _soundArray[$name];
}
|
Шаг 16: CustomLoader, показывающий список имен
У нас есть 1 последний способ добавить. Его цель — вернуть массив всех имен активов, которые в данный момент сохранены в массивах _imageArray
и _soundArray
экземпляра _soundArray
.
Добавьте следующие строки кода после getSound ()
:
1
2
3
4
5
6
7
8
|
public function get names ():Array
{
var tempArray:Array = new Array;
for (var name:String in _imageArray) tempArray.push (name);
for (name in _soundArray) tempArray.push (name);
return tempArray;
}
|
Шаг 17: Веха
Хорошо! Прежде чем перейти к основному документу, дважды проверьте, чтобы в вашем классе CustomLoader ничего не пропало. Сравните это с полным кодом ниже:
Кроме того, если вы используете Flash, создайте новый класс в той же папке с помощью intro3D.fla, назовите его «CustomLoader» и скопируйте в него приведенный ниже код.
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
|
package
{
import flash.display.Loader;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.media.Sound;
import flash.net.URLRequest;
public class CustomLoader extends EventDispatcher
{
public static const ALL_LOADS_COMPLETE:String = ‘allLoadsComplete’;
private static var _allowed:Boolean;
private static var _customLoader:CustomLoader;
private var _imageArray:Array;//associative
private var _imageURLs:Array;
private var _loadCount:uint;
private var _soundURLs:Array;
private var _soundArray:Array;//associative
public function CustomLoader ()
{
if (! _allowed)
{
throw new Error (‘This is a Singleton, please use CustomLoader.getInstance ()’);
return;
}
init ();
}
private function init ():void
{
_imageArray = new Array;
_imageURLs = new Array;
_soundURLs = new Array;
_soundArray = new Array;
}
public static function getInstance ():CustomLoader
{
if (! _customLoader)
{
_allowed = true;
_customLoader = new CustomLoader;
_allowed = false;
}
return _customLoader;//happens either way
}
public function addItem ($url:String):void
{
_imageURLs.push ($url);
}
public function addSound ($url:String):void
{
_soundURLs.push ($url);
}
public function startLoading ():void
{
for (var i:uint = 0; i < _imageURLs.length; i++)
{
var loader:Loader = new Loader
_imageArray[assignShortName (_imageURLs[i])] = loader;
loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onLoadComplete);
loader.contentLoaderInfo.addEventListener (IOErrorEvent.IO_ERROR, onLoadError);
loader.load (new URLRequest (_imageURLs[i]));
}
for (i = 0; i < _soundURLs.length; i++)
{
var sound:Sound = new Sound;
_soundArray[assignShortName (_soundURLs[i])] = sound;
sound.addEventListener (Event.COMPLETE, onLoadComplete);
sound.addEventListener (IOErrorEvent.IO_ERROR, onLoadError);
sound.load (new URLRequest (_soundURLs[i]));
}
}
private function assignShortName($url:String):String
{
return $url.split (‘/’)[1].split(‘.’)[0];
}
private function onLoadComplete (e:Event):void
{
if (_imageURLs.length + _soundURLs.length == ++_loadCount)
{
dispatchEvent (new Event (ALL_LOADS_COMPLETE));
}
}
private function onLoadError(e:IOErrorEvent):void
{
//internal use
throw new Error (e);
}
public function getItem ($name:String):Loader
{
return _imageArray[$name];
}
public function getSound ($name:String):Sound
{
return _soundArray[$name];
}
public function get names ():Array
{
var tempArray:Array = new Array;
for (var name:String in _imageArray) tempArray.push (name);
for (name in _soundArray) tempArray.push (name);
return tempArray;
}
}
}
|
Шаг 18: Настройка класса документа
Для FlashDevelop снова откройте менеджер проекта (см. Шаг 4), разверните папку \ src \ и дважды щелкните Main.as.
Под импортом и прямо над определением класса добавьте следующий тег метаданных, чтобы настроить свойства этапа.
1
|
[SWF (frameRate = 30, width = 600, height = 350, backgroundColor = 0)]
|
Прямо под объявлением класса добавьте следующие переменные экземпляра:
1
2
3
|
private var _customLoader:CustomLoader;
private var _introArray:Array;
private var _currentIntro:uint;
|
Переменная _customLoader
будет содержать ссылку на экземпляр CustomLoader. Переменная _introArray
будет содержать ссылки на все экземпляры Intro3D, созданные позже. _currentIntro
будет увеличиваться на 1 каждый раз, когда экземпляр Intro3D отправляет событие Intro3D.INTRO_COMPLETE
которое будет использоваться для вызова следующего Intro3D, добавления его на сцену и начала рендеринга.
Замечания:
Если вы используете Flash, перейдите к шагу 19 и вернитесь сюда.
OK. Давайте сделаем несколько тестов с классом CustomLoader
. Внутри метода init()
после того, как он говорит «точка входа», добавьте следующие строки кода:
1
|
_customLoader = new CustomLoader;
|
Нажмите CTRL + ENTER, чтобы запустить программу.
Это должно генерировать сообщение об ошибке, в котором говорится, что вам нужно использовать CustomLoader.getInstance ().
Далее, давайте попробуем загрузить 1 визуальный актив и 1 звуковой актив. Удалите ваш последний ввод и добавьте следующие строки кода:
1
2
3
4
5
6
7
|
_customLoader = CustomLoader.getInstance ();
_customLoader.addEventListener (CustomLoader.ALL_LOADS_COMPLETE, onLoadComplete);
_customLoader.addItem (‘PV3Dassets/dot0.png’);//image
_customLoader.addSound (‘PV3Dassets/Explosion_hifi.mp3’);//sound
_customLoader.startLoading ();
|
Прямо под методом init ()
добавьте onLoadComplete ()
вызов onLoadComplete ()
.
1
2
3
4
5
6
7
8
9
|
private function onLoadComplete (e:Event):void
{
//remember, all visual assets are saved within their containing Loader which are also DisplayObjects.
addChild (_customLoader.getItem (‘dot0’));
_customLoader.getSound (‘Explosion_hifi’).play ();
trace (_customLoader.names);
}
|
Запустите программу, на этот раз на сцене должна присутствовать небольшая точка со звуком взрыва. Кроме того, вы увидите массив коротких имен всех ресурсов, загруженных в экземпляр CustomLoader
напечатанных на панели вывода. CustomLoader работает!
Шаг 19: Ответственность за класс документов
(Пользователи Flash: перейдите ко второй половине этого шага.)
Здесь мы загрузим все внешние ресурсы, настроим все 3 Intro3D и подождем, пока пользователь щелкнет по сцене, чтобы запустить анимацию. Ниже перечислены обязанности Главного класса:
- Создайте экземпляр CustomLoader и попросите его загрузить все внешние ресурсы, которые мы будем использовать для этого приложения.
- Инициализируйте 3 экземпляра Intro3D и сохраните их в
_introArray
. - Прослушайте
MouseEvent.CLICK
на сцене, чтобы вызвать анимацию. - При щелчке по сцене воспроизводите все Intro3D последовательно, добавляя следующий на сцену и удаляя только что законченный.
Идите дальше и вставьте следующие строки кода изнутри init ()
прямо под ним, где написано «точка входа».
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
_customLoader = CustomLoader.getInstance ();
_customLoader.addEventListener (CustomLoader.ALL_LOADS_COMPLETE, onLoadComplete);
for (var i:uint = 0; i < 6; i++)
{
_customLoader.addItem (‘PV3Dassets/splat’ + String (i) + ‘.png’);
}
_customLoader.addItem (‘PV3Dassets/cross0.png’);
_customLoader.addItem (‘PV3Dassets/dot0.png’);
_customLoader.addSound (‘PV3Dassets/Swoosh1.mp3’);
_customLoader.addSound (‘PV3Dassets/Swoosh3.mp3’);
_customLoader.addSound (‘PV3Dassets/Explosion_hifi.mp3’);
_customLoader.addSound (‘PV3Dassets/FastBeat_hifi.mp3’);
_customLoader.startLoading ();
|
После назначения прослушивателя _customLoader
экземпляру _customLoader
мы _customLoader
6 раз, чтобы загрузить все внешние изображения с именем, начинающимся с «splat». Затем он загружает другие активы индивидуально, так как они имеют уникальные имена. Всегда хорошо называть ваши активы одинаково, чтобы упростить загрузку.
Удалите весь код внутри onLoadComplete ()
. Мы пока оставим это поле пустым и начнем заполнять его, когда будем разрабатывать 3 класса Intro3D.
Для Flash создайте новый класс из той же папки, что и ваш intro3D.fla. Назовите его Main.as и назначьте в качестве класса документа для файла intro3D.fla. Скопируйте и вставьте приведенный ниже код в класс.
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
|
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.media.Sound;
[SWF (frameRate = 30, width = 600, height = 350, backgroundColor = 0)]
public class Main extends Sprite
{
private var _customLoader:CustomLoader;
private var _introArray:Array;
private var _currentIntro:uint;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init)
}
private function init(e:Event = null):void
{
removeEventListener (Event.ADDED_TO_STAGE, init);
_customLoader = CustomLoader.getInstance ();
_customLoader.addEventListener (CustomLoader.ALL_LOADS_COMPLETE, onLoadComplete);
for (var i:uint = 0; i < 6; i++)
{
_customLoader.addItem (‘PV3Dassets/splat’ + String (i) + ‘.png’);
}
_customLoader.addItem (‘PV3Dassets/cross0.png’);
_customLoader.addItem (‘PV3Dassets/dot0.png’);
_customLoader.addSound (‘PV3Dassets/Swoosh1.mp3’);
_customLoader.addSound (‘PV3Dassets/Swoosh3.mp3’);
_customLoader.addSound (‘PV3Dassets/Explosion_hifi.mp3’);
_customLoader.addSound (‘PV3Dassets/FastBeat_hifi.mp3’);
_customLoader.startLoading ();
}
private function onLoadComplete (e:Event):void
{
//leave this blank for now
}
}
}
|
Сохраните, прежде чем двигаться вперед.
Шаг 20: Ответственность класса Intro3D
Класс Intro3D
наследуется от BasicView
который, в свою очередь, наследуется от flash.display.Sprite
. BasicView является частью пакета Papervision3D. Это быстрая настройка для базового проекта Papervision.
Мы объявляем защищенным свойства и методы, которые также будут использоваться подклассами. Intro3D будет расширено двумя другими вступлениями, которые мы будем называть SubIntro3D1 и SubIntro3D2. Когда вы видели анимацию, это 1-ая последовательность, а 2 других — подклассы.
Его список обязанностей:
- Настройте камеру, ее масштаб, цель и т. Д.
- Создайте фон и добавьте его в сцену.
- Создайте частицы и добавьте их в сцену.
- Добавьте 3D текст в сцену.
- Анимируйте камеру.
- Анимировать частицы.
- Анимируйте трехмерные тексты.
- Сообщите слушателю, когда анимация закончится.
Создайте новый класс и назовите его Intro3D ;; для его базового класса выберите org.papervision3d.view.BasicView
и нажмите OK, чтобы завершить процесс. Обратитесь к шагу 6, если вы новичок в FlashDevelop.
Добавьте следующие строки кода внутри объявления класса перед конструктором:
01
02
03
04
05
06
07
08
09
10
11
12
|
public static const INTRO_COMPLETE:String = ‘introComplete’;
protected var _backgroundHolder:Sprite;
protected var _customLoader:CustomLoader;
protected var _text3DArray:Array;
protected var _particles:Particles;
protected var _easeOut:Number = .003;
protected var _reachX:Number = .1;
protected var _reachY:Number = .1;
protected var _reachZ:Number = .5;
protected var _xDist:Number = 0;
protected var _yDist:Number = 0;
|
Статическая константа INTRO_COMPLETE
будет использоваться как пользовательское событие, которое отправляется после завершения анимации этого вступления. _backgroundHolder
будет содержать изображение, созданное для фона. _customLoader
будет иметь ссылку на экземпляр CustomLoader для загрузки изображений, которые будут использоваться для частиц. _text3DArray
будет содержать все экземпляры Text3D, которые мы создадим позже. _particles
будут содержать все частицы. Остальные будут использоваться для наложения небольшого контроля на камеру во время воспроизведения анимации, чтобы дать ощущение реального времени, когда мышь перемещается внутри сцены. Мы рассмотрим эти переменные подробнее, когда позже перейдем к onRenderTick ()
.
Шаг 21: Конструктор Intro3D
Добавьте следующие строки кода внутри конструктора:
1
2
3
4
5
6
|
_text3DArray = [];
_customLoader = CustomLoader.getInstance ();
addEventListener (Event.ADDED_TO_STAGE, onAddedToStage);
init ();
|
Здесь _text3DArray
экземпляр _text3DArray
. Затем _customLoader
присваивается ссылка на 1 экземпляр CustomLoader
, именно здесь применяется шаблон Singleton. Обратите внимание, что до тех пор, CustomLoader
класс CustomLoader
доступен, независимо от того, откуда к нему обращаются, все равно остается один и тот же экземпляр, который отвечает. Мы можем загрузить все активы из 1 класса и получить доступ к любому или всем активам практически из любого места. Далее слушатель, когда на Intro3D
добавляется Intro3D
класса Intro3D
который будет использоваться для запуска анимации. init ()
вызывается до конца метода.
Шаг 22: метод onAddedToStage ()
Добавьте код после пробела ниже метода конструктора:
1
2
3
4
5
6
7
8
9
|
private function onAddedToStage (e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
addEventListener (Event.REMOVED_FROM_STAGE, onRemovedFromStage);
startRendering ();
TweenLite.delayedCall (.2, animateText);
}
|
Слушатель onAddedToStage
удаляется, поскольку он будет использоваться только один раз. Затем мы назначаем слушателя для проверки, когда экземпляр Intro3D удаляется со сцены, чтобы остановить рендеринг 3D-движка, когда он больше не нужен. Затем startRendering ()
и запускается движок Papervisions3D. animateText ()
метода animateText ()
установлен на 200 миллисекунд, чтобы избежать засорения конвейера Flash, что может привести к его зависанию.
Шаг 23: метод init ()
Вызывается последним, как только создается экземпляр Intro3D
, этот метод подготавливает все компоненты для анимации перед добавлением экземпляра на сцену. Я объясню подробнее о каждом методе, вызываемом при его создании.
Добавьте строки ниже сразу после метода onAddedToStage
:
1
2
3
4
5
6
7
|
protected function init():void
{
setUpCamera ();
createBackground ();
createParticles ();
addText ();
}
|
Шаг 24: Настройка камеры
Добавьте это после метода init ()
:
1
2
3
4
5
|
protected function setUpCamera ():void
{
camera.zoom = 50;
camera.target = null;
}
|
Все, что относится к камере, должно быть решено здесь. Мы устанавливаем свойство масштабирования камеры на 50, а его цель — ноль.
Шаг 25: Создание фона
Здесь мы создаем векторное изображение, имеющее цвет фона светло-серый с белым радиальным свечением вокруг его центра. Это будет использоваться в качестве фона для первой «сцены» вступления. _backgroundHolder
экземпляр _backgroundHolder
, доступ к его графическому свойству и рисование прямоугольника с градиентной заливкой. Вот ссылка для получения дополнительной информации, если вы не знакомы с методом Graphics.beginGradientFill ()
.
Добавьте следующие строки кода после метода init()
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
protected function createBackground ():void
{
_backgroundHolder = new Sprite;
var g:Graphics = _backgroundHolder.graphics;
var fillType:String = GradientType.RADIAL;
var colors:Array = [0xFFFFFF, 0xC0C0C0];
var alphas:Array = [1, 1];
var ratios:Array = [0x88, 0xFF];
var matr:Matrix = new Matrix();
matr.createGradientBox(600, 600, 0, 40, 0);
var spreadMethod:String = SpreadMethod.PAD;
g.beginGradientFill(fillType, colors, alphas, ratios, matr, spreadMethod);
g.drawRect (0, 0, 600, 350);
addChildAt (_backgroundHolder, 0);
}
|
Шаг 26: Система частиц
Теперь прибывает самый большой метод для этого класса. Метод createParticles ()
.
Добавьте следующие строки кода после createBackground ()
:
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
|
protected function createParticles
(
$numParticles:Number = 150,
$name:String = ‘splat’,
$randomColors:Array = null,
$randomX:Array = null,
$randomY:Array = null,
$randomZ:Array = null,
$size:Number = 3
)
:void
{
var particleArray:Array = new Array;
for each(var name:String in _customLoader.names)
{
if (name.indexOf ($name) > -1)
{
particleArray.push (name);
}
}
var randomColors:Array = $randomColors == null ?
var randomX:Array = $randomX == null ?
var randomY:Array = $randomY == null ?
var randomZ:Array = $randomZ == null ?
_particles = new Particles;
scene.addChild (_particles);
for (var i:uint = 0; i < $numParticles; i++)
{
var randomIndex:uint = uint (Math.random () * particleArray.length);
var loader:Loader = _customLoader.getItem (particleArray[randomIndex]);
var bitmapData:BitmapData = new BitmapData (loader.width, loader.height, true, 0);
bitmapData.draw (loader);
randomIndex = uint (Math.random () * randomColors.length);
var red:uint = getColorComponent (randomColors[randomIndex]).RED;
var green:uint = getColorComponent (randomColors[randomIndex]).GREEN;
var blue:uint = getColorComponent (randomColors[randomIndex]).BLUE;
var colorTransform:ColorTransform = new ColorTransform (0, 0, 0, 1, red, green, blue);
bitmapData.colorTransform (bitmapData.rect, colorTransform);
var particleMaterial:BitmapParticleMaterial = new BitmapParticleMaterial (bitmapData, 1, loader.width * -.5, loader.height * -.5);
particleMaterial.smooth = true;
var particle:Particle = new Particle (particleMaterial, $size, getRandomInRange ( randomX[0], randomX[1]), getRandomInRange ( randomY[0], randomY[1]), getRandomInRange ( randomZ[0], randomZ[1]));
particle.rotationZ = Math.random () * 360;
_particles.addParticle (particle);
}
}
|
Давайте рассмотрим детали того, что здесь происходит.
Во-первых, как вы заметили, метод уже имеет встроенные параметры. У нас это так, чтобы подклассы могли просто отправлять свой собственный набор параметров, чтобы вносить изменения по умолчанию. Вы увидите, когда мы пройдем 2 подкласса позже.
Параметры:
-
$numParticles
— по умолчанию 150, это количество частиц, которое вы хотите иметь в системе. -
$name
— по умолчанию «splat», мы передаем короткое имя String изображения (загруженного ранее через CustomLoader), которое мы хотим использовать в качестве материала для частиц. -
$randomColors
— по умолчанию null, массив цветов, используемых для частиц (случайным образом распределенных по всем частицам). -
$randomX
— по умолчанию используется нулевой двумерный массив минимального и максимального местоположения «x» для частиц. -
$randomY
— по умолчанию$randomY
нулю, так же, как $ randomX, но для местоположений «y». -
$randomZ
— по умолчанию$randomZ
нулю, так же, как $ randomX, но для местоположений «z». -
$size
— по умолчанию 3, это относится к масштабу каждой частицы по сравнению с исходным размером изображения.
Как только этот метод вызван, создается экземпляр локальной переменной CustomLoader
, он перебирает все имена, хранящиеся в данный момент в экземпляре CustomLoader
. Каждый раз, когда параметр $name
совпадает с именем внутри _customLoader.names
, он добавляется в particleArray
_customLoader.names
. Так как мы используем «splat» в качестве изображения, все имена от «splat0» до «splat5» будут собраны вicleArray. $randomColors
проверяется, является ли оно нулевым или нет. Если randomColors
равно null, присваивается локальная переменная с именем randomColors
[0x666666, 0x000000, 0x851616]. Если нет, как в случае с 2 подклассами, он присваивается randomColors
. Тот же метод используется для $randomX
, randomY
и $randomZ
. _particles
затем создаются и добавляются на сцену. Проще говоря, для тех, кто не знает, что такое Particles в PV3D, это контейнер для всех объектов Particle. Частица — это двухмерное изображение, которое постоянно обращено к камере.
$numParticles
проходит $numParticles
для создания частиц. Во время каждой итерации создается локальная переменная с именем randomIndex
типа uint путем выбора между 0 и 5. В свою очередь, локальной переменной с именем loader типа Loader назначается соответствующий экземпляр Loader
который был сохранен внутри _imageArray одного экземпляра CustomLoader
. Если вам нужен CustomLoader
, вернитесь и посетите класс CustomLoader
мы создали ранее. Затем bitmapData
локальная переменная bitmapData
с высотой и шириной Loader
. Важно отметить, что для прозрачного параметра BitmapData установлено значение true. Свойство fillColor имеет значение Black. Если вы посмотрите на любое из импортированных изображений, вы заметите, что они просто белые. У меня есть изображения в формате PNG, чтобы сохранить прозрачность при сохранении низкого размера файла. Loader
затем рисуется в bitmapData
. Пока что изображение все еще бесцветное. С помощью класса ColorTransform
мы можем изменить цвет этого растрового изображения на цвета массива randomColors
. Для этого снова используется randomIndex, на этот раз любое целое число от 0 randomColors
длины randomColors
. С выбранным цветом для извлечения его компонентов Red, Green и Blue используется специальная функция getColorComponent
. Затем локальная переменная colorTransform istantiated. Всем colorMultipliers присваивается «0», альфа устанавливается в «1», а colorOffsets назначаются производные компоненты цвета. Наконец, bitmapData
для colorTransform
назначается colorTransform
. Мы передаем bitmapData.rect
чтобы применить colorTransform
ко всему изображению.
Затем создается локальная переменнаяicleMaterial с bitmapData в качестве 1-го параметра, «1» для его масштаба и loader.width * -.5
loader.height * -.5
и loader.height * -.5
материала. Это исправление, которое мне пришлось применить, поскольку, если вы оставите параметры по умолчанию «0» для параметров offSet, все частицы, которые касаются края экрана, по какой-то причине исчезают. Свойство particleMaterial
дляичастика particleMaterial
имеет значение true. Это предотвращает пикселизацию частицы, когда она приближается к камере.
После того, как particleMaterial
частицМатериала готово, создается фактическая частица. Каждая частица создается путем передачи particleMaterial
, $size
, затем случайных позиций x, y & z. Случайное вращение применяется к каждой частице перед ее добавлением в _particles
.
Шаг 27: Извлечение цветовых компонентов
Этот метод принимает параметр цвета в шестнадцатеричном формате и разбивает его на 3 компонента. Затем объект создается и возвращается с компонентами, назначенными в качестве его свойств RED, GREEN и BLUE.
Добавьте следующие строки кода после createParticles ()
:
1
2
3
4
5
6
7
8
9
|
private function getColorComponent ($color:uint):Object
{
var colorObject:Object = new Object;
colorObject.RED = $color >> 16;
colorObject.GREEN = $color >> 8 & 0xFF;
colorObject.BLUE = $color & 0xFF;
return colorObject;
}
|
Шаг 28: получение случайного числа в диапазоне
Добавьте следующие строки кода в самом низу класса:
1
2
3
4
5
|
protected function getRandomInRange ($min:Number, $max:Number, $rounded:Boolean = true):Number
{
if ($rounded) return Math.round (Math.random () * ($max — $min) + $min);
else return Math.random () * ($max — $min) + $min;
}
|
(См. Также этот Быстрый совет и обсуждение в комментариях.)
Шаг 29: Добавление 3D текста
Этот метод также имеет параметры по умолчанию. Как и метод createParticles ()
, он настроен таким образом, чтобы легко изменять свойства трехмерного текста.
Добавьте это после getColorComponent ()
:
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
|
protected function addText
(
$text:String = ‘wanna learn \n actionscript?’,
$fillColor:uint = 0x660000,
$fillAlpha:Number = 1,
$lineThickness:Number = 1,
$lineColor:uint = 0x660000,
$lineAlpha:Number = 1,
$font3D:Font3D = null,
$rotationX:Number = 0,
$rotationY:Number = -45,
$rotationZ:Number = 5,
$scale:Number = 2,
$align:String = ‘left’,
$letterSpacing:Number = -2,
$lineSpacing:Number = -30,
$x:Number = -550,
$y:Number = 100,
$z:Number =-990
):void
{
var material:Letter3DMaterial = new Letter3DMaterial ($fillColor, $fillAlpha);
material.lineThickness = $lineThickness;
material.lineColor = $lineColor;
material.lineAlpha = $lineAlpha;
var font3D:Font3D = $font3D == null ?
var text3D:Text3D = new Text3D ($text, font3D, material);
text3D.localRotationX = $rotationX;
text3D.localRotationY = $rotationY;
text3D.localRotationZ = $rotationZ;
text3D.x = $x;
text3D.y = $y;
text3D.z = $z;
text3D.scale = $scale;
text3D.align = $align;
text3D.letterSpacing = $letterSpacing;
text3D.lineSpacing = $lineSpacing;
_text3DArray.push (text3D);
scene.addChild (text3D);
}
|
Параметры:
-
$text
— по умолчанию «хочешь выучить ActionScript?», текст для твоего Text3D. -
$fillColor
— по умолчанию темно-красный цвет, служит цветом заливки Text3D. -
$fillAlpha
— по умолчанию «.1», устанавливает альфа-прозрачность заливки Text3D. -
$lineThickness
— по умолчанию «1», задает толщину границы Text3D. -
$lineColor
— также по умолчанию темно-красный, это цвет границы Text3D. -
$lineAlpha
— по умолчанию «1», альфа-прозрачность границы Text3D. -
$font3D
— По умолчанию равно нулю, что эквивалентно назначению встроенного Font3D HelveticaBold. -
$rotationX
— По умолчанию «0» градусов, это будет начальный localRotationX Text3D при добавлении в сцену. -
$rotationY
— По умолчанию «-45» градусов, начиная с localRotationY Text3D. -
$rotationZ
— По умолчанию «5» градусов, начиная с localRotationZ Text3D. -
$scale
— По умолчанию «2», применяется к шкале Text3D. -
$align
— По умолчанию «влево», функция выравнивания Text3D. -
$letterSpacing
— По умолчанию «-2», пробел между символами. -
$lineSpacing
— По умолчанию «30», пробел между каждой строкой текста, если Text3D многострочный (как в нашем примере). -
$x
— По умолчанию «-550», начальная позиция x, когда Text3D добавляется к сцене. -
$y
— По умолчанию «100», начальная позиция y, когда Text3D добавляется к сцене. -
$z
— По умолчанию «-990», начальная позиция z, когда Text3D добавляется к сцене.
Этот класс может показаться пугающим на первый взгляд, но как только вы ознакомитесь с ним, вы начнете понимать, насколько легко им пользоваться. Теперь давайте узнаем, что происходит, когда вызывается этот метод.
Во-первых, создается экземпляр локальной переменной material
типа, Letter3DMaterial
передавая $fillColor
и $fillAlpha
. В material
«ы thickness
, lineColor
и lineAlpha
свойство присваивается соответствующий параметр. Затем создается локальная переменная font3D
типа Font3D
со значением, переданным из $font3D
параметра. Если переданное значение равно «null», используется новый HelveticaBold Font3D
. Теперь, когда Font3D
и Letter3DMaterial
сделаны, и мы можем создать экземпляр Text3D
. Конкретизация осуществляется путем передачи $text
, font3D
и в material
качестве параметров. После создания экземпляра вращение устанавливается по осям x, y и z, а затем по позициям x, y и z. Последние параметры мы относим такие scale
, align
, letterSpacing
, иlineSpacing
, И это делает это! Мы храним ссылку для каждого Text3D
экземпляра внутри _text3DArray
для последующего доступа и добавляем ее на сцену.
Шаг 30: метод onRenderTick ()
Добавьте это после addText ()
метода:
01
02
03
04
05
06
07
08
09
10
|
override protected function onRenderTick (e:Event = null ): void {
animateParticles (); animateCamera (); _xDist = mouseX - stage.stageWidth * . 5 ; _yDist = mouseY - stage.stageHeight * . 5 ; super .onRenderTick (e); }
|
Вызывается при каждом EnterFrame
событии, он обрабатывает движение camera
и _particles
. Также _xDist
и _yDist
рассчитываются здесь.
Шаг 31: Анимация частиц
Добавьте это после onRenderTick ()
метода:
1
2
3
4
|
protected function animateParticles (): void {
_particles.z -= 20 ; }
|
Здесь вы можете контролировать все способы _particles
анимации. Он просто перемещается _particles
ближе к каждому onRenderTick
событию, поскольку камера направлена вдоль оси Z. Смотри, как брызги краски приближаются !?
Шаг 32: метод animateCamera ()
Добавьте это после animateParticles ()
метода:
1
2
3
4
5
|
protected function animateCamera (): void {
camera.x += (_xDist - camera.x * _reachX) * _easeOut; camera.y += (_yDist - camera.y * _reachY) * _easeOut; }
|
Немного под влиянием движения мыши (попробуйте в демоверсии), это дает сцене ощущение в реальном времени.
Шаг 33: Анимация Text3D с помощью TweenLite
Добавьте это ниже animateCamera ()
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
protected function animateText (): void {
var sound:Sound = _customLoader.getSound ( 'Swoosh3' ); TweenLite.to (
_text3DArray[ 0 ], 1.2 , {
z: 100 , localRotationY:- 22.5 , onStart:playSound, onStartParams:[sound, 0 , 0 , new SoundTransform ( 3 )], onComplete:end }
);
}
|
Срабатывает через 200 миллисекунд после добавления экземпляра Intro3D на сцену. Здесь с помощью TweenLite трехмерный текст изменяется с начальной позиции z (-990) до 100 в течение 1,2 секунды. Также вращение Y исправлено так, чтобы оно заканчивалось параллельно экрану.
Остальные параметры следующие:
-
onStart
— Это срабатывает, когда TweenLite запускает эту анимацию. Он используется здесь для вызоваplaySound
метода, который мы добавим позже для воспроизведения звуковых эффектов для всехIntro3D
s. -
onStartParams
— Контейнер массива для всех параметров, которые мы должны передать вplaySound
метод. Я рассмотрю детали этого метода чуть позже. -
onComplete
— Мы передаем метод, который необходимо вызвать, когда заканчивается эта анимация. Он назначенend
(также создан и обсужден позже).
И это то, что заставляет 3D-текст перемещаться из-за камеры в центр сцены.
Шаг 34: Добавление звуковых эффектов
Добавьте это после animateText ()
метода:
1
2
3
4
5
|
protected function playSound ($sound:Sound, $startTime: Number = 0 , $loops: Number = 0 , $soundTransform:SoundTransform = null ): void {
var soundTransform:SoundTransform = $soundTransform == null ? new SoundTransform () : $soundTransform; $sound.play ($startTime, $loops, soundTransform); }
|
При вызове этому методу передается звук для воспроизведения, начальная позиция времени для звука, количество циклов и SoundTransform
экземпляр. Это простой и эффективный элемент управления для воспроизведения звука.
Шаг 35: В конце вступления
Добавьте это после playSound ()
метода:
1
2
3
4
|
protected function end ($delayInSeconds: Number = 1 ): void {
TweenLite.delayedCall ($delayInSeconds, dispatchEvent, [ new Event (Intro3D.INTRO_COMPLETE)]); }
|
Это ждет 1 секунду, а затем отправляет Intro3D.INTRO_COMPLETE
событие.
Шаг 36: После удаления со сцены
Добавьте это после checkStatus ()
метода:
1
2
3
4
5
|
private function onRemovedFromStage(e:Event): void {
removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage); stopRendering (); }
|
После удаления со сцены, он останавливает движок рендеринга PV3D и экономит некоторую вычислительную мощность. Это завершает Базовый класс Intro3D.
Шаг 37: Веха
Из-за размера класса Intro3D я воздержался от публикации здесь. Вы можете сравнить свой код с классом Intro3D.as, включенным в исходную загрузку; нам не нужно больше добавлять код к нему.
Шаг 38: Тестирование Intro3D
Давайте вернемся к основному классу.
Внутри onLoadComplete ()
метода добавьте следующие строки кода:
1
2
3
|
var intro:Intro3D = new Intro3D; intro.addEventListener (Intro3D.INTRO_COMPLETE, onIntroComplete); addChild (intro); |
Добавьте onIntroComplete ()
метод ниже onLoadComplete
:
1
2
3
4
|
private function onIntroComplete(e:Event): void {
removeChild (getChildAt ( 0 )); }
|
Запустите программу.
Если все прошло хорошо, вы бы видели анимацию вместе с ее звуковым эффектом.
Шаг 39: Создание подкласса SubIntro3D1
Создайте новый класс в той же папке, где вы сохранили Intro3D.as. Обратитесь к шагу 6.
В качестве имени введите «SubIntro3D1», в качестве базового класса укажите его расширение Intro3D
.
Внутри package
объявления добавьте следующий импорт следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
package
{
import com.greensock.TweenLite;
import flash.events.Event;
import flash.media.Sound;
import flash.media.SoundTransform;
import org.papervision3d.core.geom.Particles; import org.papervision3d.core.geom.renderables.Particle; import org.papervision3d.materials.special.BitmapParticleMaterial; import org.papervision3d.materials.special.Letter3DMaterial; import org.papervision3d.typography.Font3D; import org.papervision3d.typography.Text3D; public class SubIntro3D1 extends Intro3D {
public function SubIntro3D1 () {
super ();
}
}
}
|
Внутри конструктора это вызывает super ()
. Это эквивалентно вызову Intro3D
метода конструктора, поэтому обратитесь к шагу 20.
Теперь давайте проверим это. Вернитесь в основной класс и измените код с: var intro:Intro3D = new Intro3D;
на:var intro:Intro3D = new SubIntro3D1;
Запустите его, и вы увидите точную копию Intro3D
анимации. На самом деле, вы можете даже удалить весь импорт, и он все равно должен работать. Кроме того, нам не придется изменять объявление типа вступления, поскольку все они будут Intro3D.
Оставьте Основной класс как есть и двигайтесь вперед.
Шаг 40: изменение настроек для SubIntro3D1
В этом подклассе мы все меняем. В этом Intro3D 5 3D текстов будут перемещаться из разных углов, чтобы выразить «вы попали в нужное место!». Кроме того, частицы вместо этого будут вращаться вокруг своей оси х. Давайте начнем с изменения материала, используемого в качестве частиц, и добавления большего объема трехмерного текста. Если вернуться к Intro3D, вы увидите , что createParticles ()
и addText ()
методы вызываются из init ()
метода. Чтобы внести изменения, мы должны переопределить это.
Добавьте следующие строки кода после конструктора:
01
02
03
04
05
06
07
08
09
10
11
12
|
override protected function init(): void {
setUpCamera (); //same createBackground (); //same createParticles ( 1000 , 'dot0' , [ 0x80FFFF , 0xF7C582 , 0xFFFFFF , 0xA40052 ], null , null , null , 2 ); addText ( 'you\'ve' , 0x00FFFF , 1 , 0 , 0 , 1 , new AdelleBasicRgBold, 0 , 0 , - 5 , 2 , 'right' , - 2 , - 30 , - 2000 , 100 , 100 ); addText ( 'come' , 0x00FFFF , 1 , 0 , 0 , 1 , new AdelleBasicRgBold, 0 , 0 , - 5 , 2 , 'right' , - 2 , - 30 , - 450 , 1000 , 100 ); addText ( 'to the' , 0x00FFFF , 1 , 0 , 0 , 1 , new AdelleBasicRgBold, 0 , 0 , - 5 , 2 , 'right' , - 2 , - 30 , - 1050 , - 3000 , 100 ); addText ( 'right' , 0x00FFFF , 1 , 0 , 0 , 1 , new AdelleBasicRgBold, 0 , 0 , - 5 , 2 , 'right' , - 2 , - 30 , 2000 , - 70 , 100 ); addText ( 'place!' , 0x00FFFF , 1 , 0 , 0 , 1 , new AdelleBasicRgBold, 0 , 0 , - 5 , 2 , 'right' , - 2 , - 30 , - 1000 , - 300 , - 2000 ); }
|
Мы передаем другой набор параметров методу createParticles, чтобы внести изменения. Затем мы вызываем метод addText 5 раз, чтобы создать сообщение «Вы попали в нужное место!». Это делает 3D-тексты независимыми друг от друга. См. Шаг 28, чтобы узнать, что происходит в этом методе. Я расскажу, как создать пользовательский Font3D — AdelleBasicRgBold, который мы используем здесь, когда закончим этот класс. Стоит отметить, что координаты x, y и z для 3D-текстов, которые мы визуально откалибровали (заняли 5 минут).
Шаг 41: Изменение фона
Если мы не переопределим этот метод, фон будет таким же, как Intro3D
и у. Давайте просто использовать фон сцены.
Добавьте следующие строки кода после init()
метода:
1
|
override protected function createBackground (): void { /*do nothing*/ } |
Здесь мы ничего не делаем. И так как мы перекрывая Intro3D
«s createBackground ()
метода, он не будет применен.
Шаг 42: изменение анимации частиц
Хорошо, вернемся к шагу 30. Ведь Intro3D
частицы движутся к камере. Для этого SubIntro3D1 это заботится о том, чтобы частицы катились по их осям X.
Добавьте следующие строки кода после createBackground ()
метода:
1
|
override protected function animateParticles (): void {_particles.localRotationX += . 3 ;} |
Шаг 43: Анимация 5 Text3D в сцене
Трехмерные тексты начинают последовательно перемещаться в правильные позиции. Мы назначаем SoundTransform
экземпляр со значением громкости 3, поскольку используемый нами звуковой эффект имеет меньшую громкость, чем другие. Последняя анимация также вызывает end
метод.
Добавьте следующие строки кода после animateParticles ()
метода:
01
02
03
04
05
06
07
08
09
10
|
override protected function animateText(): void {
var sound:Sound = _customLoader.getSound ( 'Swoosh1' ); TweenLite.to (_text3DArray[ 0 ], . 4 , {x:- 1000 , y: 100 , z: 100 , delay: 0 , onStart:playSound, onStartParams:[sound, 0 , 0 , new SoundTransform ( 3 )]}); TweenLite.to (_text3DArray[ 1 ], . 4 , {x:- 450 , y: 150 , z: 100 , delay: . 2 , onStart:playSound, onStartParams:[sound, 0 , 0 , new SoundTransform ( 3 )]}); TweenLite.to (_text3DArray[ 2 ], . 4 , {x:- 1050 , y:- 120 , z: 100 , delay: . 4 , onStart:playSound, onStartParams:[sound, 0 , 0 , new SoundTransform ( 3 )]}); TweenLite.to (_text3DArray[ 3 ], . 4 , {x:- 520 , y:- 70 , z: 100 , delay: . 6 , onStart:playSound, onStartParams:[sound, 0 , 0 , new SoundTransform ( 3 )]}); TweenLite.to (_text3DArray[ 4 ], . 4 , {x:- 1000 , y:- 300 , z: 100 , delay: . 8 , onStart:playSound, onStartParams:[sound, 0 , 0 , new SoundTransform ( 3 )], onComplete:end}); }
|
Это подводит итог класса SubIntro3D1.
Шаг 44: Веха
Просмотрите свой класс и сравните его с классом SubIntro3D.as, также включенным в загрузку исходного кода.
Перед запуском теста пройдите шаг 45.
Когда вы запускаете тест. Вы увидите 2-ю часть анимации из превью в верхней части страницы. Мы сейчас на 2/3 закончили с проектом.
Шаг 45: Создание Font3D
Если вы хотите пропустить это, просто скачайте сопровождающий файл класса ActionScript AdelleBasicRgBold.as из исходной загрузки и поместите его в ту же папку, в которой вы все время использовали, и запустите тест.
Матье Бадимон имеет отличный инструмент для создания Font3D. Вы можете узнать больше об этом и FIVe3D (векторный 3D-движок) здесь . Я также включил zip-пакет для его «make typography file» с загрузкой Source.
Вот шаги для установки для пользователей Vista / Windows7:
- Введите «appdata» в строку поиска Windows, нажмите на нее, когда найдете.
- Перейдите к «\ Local \ Adobe \ YOUR_FLASH_VERSION_HERE \ en_US \ Configuration \ WindowSWF».
- Как только вы окажетесь в папке WindowsSWF, извлеките из нее файл Make typography file.swf.
- Установите шрифт AdelleBasic_bold.otf (он находится в исходном загрузке).
- Откройте Flash, создайте новый файл и назовите его vText. Сохраните его в той же папке, где у вас есть intro3D.fla.
- Щелкните панель «Окно» изнутри Flash, затем нажмите «Другие панели», после чего вы можете нажать «Создать новый типографский файл».
- Когда он откроется, выберите Adelle Basic Rg, щелкните значок Bold, оставьте остальные как есть. Имя файла теперь должно отображаться как «AdelleBasicRgBold.as».
- Хит генерировать. После создания файл должен находиться в той же папке, что и остальные классы, над которыми мы работали.
- Откройте класс AdelleBasicRgBold.as и добавьте класс Font3D. Кроме того, поскольку мы не используем пакеты для этого проекта, удалите имя пакета из верхней части документа. Будьте осторожны, чтобы не удалить объявление «package».
- Перейдите в конец класса перед закрывающей скобкой и вставьте следующие 3 метода перед сохранением и закрытием файла. Если у вас возникли проблемы, сравните класс с 1, который я включил в исходную загрузку.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
override public function get motifs(): Object {
if (!__initialized)initialize(); return __motifs; }
override public function get widths(): Object {
if (!__initialized)initialize(); return __widths; }
override public function get height(): Number {
if (!__initialized)initialize(); return __heights; }
|
Это оно!
Обратитесь к инструкциям.pdf, включенным в FIVe3D_make_typography_v2.0.zip, если вы не используете Vista / Windows7.
Шаг 46: 2-й подкласс — SubIntro3D2
В целом, этот класс будет только немного больше, чем SubIntro3D1. У нас есть несколько изменений в его анимации, поэтому мы добавляем пару новых методов.
Создайте новый класс и назовите его «SubIntro3D2»; для его базового класса, расширить Intro3D
.
Добавьте импорт, а также вызовите super ()
конструктор, как вы это сделали с SubIntro3D1
:
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
|
package
{
import com.greensock.easing.Linear; import com.greensock.easing.Strong;
import com.greensock.TweenLite;
import flash.display.GradientType;
import flash.display.Graphics;
import flash.display.SpreadMethod; import flash.display.Sprite;
import flash.events.Event;
import flash.filters.BevelFilter; import flash.geom.Matrix;
import flash.media.Sound;
import flash.media.SoundTransform;
import org.papervision3d.materials.special.Letter3DMaterial; import org.papervision3d.typography.Font3D; import org.papervision3d.typography.Text3D; import org.papervision3d.view.layer.ViewportLayer; public class SubIntro3D2 extends Intro3D {
public function SubIntro3D2 () {
super ();
}
}
}
|
Опять давайте проверим. Вернитесь в основной класс и измените код: var intro:Intro3D = new SubIntro3D1;
на:var intro:Intro3D = new SubIntro3D2;
Когда вы запускаете программу, SubIntro3D2
реплицирует Intro3D
. Если вы хотите SubIntro3D2
выполнить репликацию SubIntro3D1
, вернитесь к объявлению класса и SubIntro3D2
продолжите SubIntro3D1
. Если вы протестируете это время, анимация должна выглядеть как SubIntro3D1
анимация. В любом случае будет работать. Но так как мы SubIntro3D2
также отличаемся от двух других, мы снова переопределим те же методы и даже добавим некоторые новые. Мы хотим, чтобы SubIntro3D2 делал так, чтобы «активный текст» 3D-текста летал сзади сцены, как в Intro3D. За исключением того, что без вращения у меня есть изменения. Затем, когда «активные точки» достигают точки назначения z, мы хотим, чтобы камера сфокусировалась на нем в течение 2,5 секунд, а затем поверните вправо, чтобы показать «безумные навыки!».
Шаг 47: изменение настроек для SubIntro3D2
Хорошо, мы меняем текст, его свойства и материал для частиц. Итак, перейдем к init ()
методу.
Добавьте это ниже конструктора:
01
02
03
04
05
06
07
08
09
10
11
|
override protected function init(): void {
setUpCamera (); createBackground (); createParticles ( 500 , 'cross' , [ 0xD56A00 , 0xBE1410 , 0xFFFFFF ], null , null , null , 1 ); addText ( 'active tuts' , 0xFFFFFF , 1 , 1 , 0xE87400 , 1 , new LubalGraphBdBTBold, 0 , 0 , 0 , 2 , 'right' , - 2 , - 30 , - 2000 , 0 , - 1100 ); addText ( 'mad skills!' , 0x80FF00 , 1 , 0 , 0x80FF00 , 1 , new LubalGraphBdBTBold, 0 , 0 , 0 , 2 , 'right' , - 2 , - 30 , 2100 , - 1100 , 1000 ); embossText (); }
|
К этому времени вы должны быть знакомы с этим методом. Все то же самое , пока мы не начнем подключение различных наборов параметров для createParticles
и addText
методов. На addText
этот раз мы звоним только дважды, чтобы добавить 2 3D текста на сцену. Затем мы добавим embossText
. Этот метод позаботится о тиснении трехмерных текстов. Вы заметили этот эффект в последнем из 3 вступлений, когда впервые увидели превью? Это заботится о начальной настройке.
Шаг 48: Добавление функциональности в setUpCamera
Здесь super.setUpCamera
вызывается первым, чтобы установить масштаб камеры на 50, а его цель — ноль. Затем он перемещает камеру в положение х -1500. Благодаря этой настройке зрители получат приятные трехмерные визуальные впечатления, когда камера повернет вправо, чтобы посмотреть на «безумные навыки!» 3D текст.
Добавьте это после init ()
метода:
1
2
3
4
5
|
override protected function setUpCamera(): void {
super .setUpCamera(); camera.x = - 1500 ; }
|
Шаг 49: Добавление фона для SubIntro3D2
Вы, ребята, наверное, задаетесь вопросом, почему этот метод не был настроен с параметрами. Это не ограничивать создание фона с помощью внутренней графики. Вы также можете использовать импортированные изображения.
Добавьте это после init ()
метода:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
override protected function createBackground (): void {
_backgroundHolder = new Sprite; var g:Graphics = _backgroundHolder.graphics; var fillType: String = GradientType.RADIAL; var colors: Array = [ 0x9C3301 , 0x820000 ]; var alphas: Array = [ 1 , 1 ]; var ratios: Array = [ 0x00 , 0xFF ]; var matr:Matrix = new Matrix();
matr.createGradientBox( 500 , 500 , 0 , 100 , 0 ); var spreadMethod: String = SpreadMethod.PAD; g.beginGradientFill(fillType, colors, alphas, ratios, matr, spreadMethod); g.drawRect ( 0 , 0 , 600 , 350 ); addChildAt (_backgroundHolder, 0 ); }
|
Шаг 50: тиснение Text3D
Тиснение трехмерных текстов напрямую не даст никакого эффекта, вам нужно применить его к тому, ViewportLayer
что содержит трехмерный текст. Для этого вы получаете доступ к слою с помощью viewport.getChildLayer
метода и передаете трехмерный текст, как показано ниже.
Добавьте это после init ()
метода:
1
2
3
4
5
6
7
8
|
protected function embossText (): void {
for each ( var text3D:Text3D in _text3DArray) {
var layer:ViewportLayer = viewport.getChildLayer (text3D); layer.filters = [ new BevelFilter ( 1 )]; }
}
|
Шаг 51: Анимационная последовательность 1
Трехмерный текст «активные фрагменты» перемещается из задней части сцены. TweenLite перемещает 3D-текст с -1100 до 1000 за 1,5 секунды. Звук также воспроизводится, как только начинается анимация. Как только анимация завершается, она вызывает фокус.
Добавьте это после embossText ()
метода:
1
2
3
4
5
|
override protected function animateText (): void {
var sound:Sound = _customLoader.getSound ( 'Swoosh1' ); TweenLite.to (_text3DArray[ 0 ], 1.5 , { z: 1000 , onStart:playSound, onStartParams:[sound, 0 , 0 , new SoundTransform ( 5 )], onComplete:focus}); }
|
Шаг 52: Последовательность анимации 2 и 3
Это та часть, где камера приближается, чтобы посмотреть на 3D-текст «активных роликов». Мы передаем в позиции «x» -1550, так как мы устанавливаем позицию «x» активного текста «x» на -2000. Для простоты мы используем Linear.easeNone
устойчивый подход, который происходит в течение 100 миллисекунд. Звук взрыва также играет здесь. Когда воспроизводится звук, его начальная позиция устанавливается равной 400 миллисекундам, поэтому звук делается наполовину. Затем для камеры назначается другая анимация. Это позаботится о перемещении камеры вправо, чтобы посмотреть на «безумные навыки!» 3D текст. Он перемещает камеру из положения «х» от -1550 до 2500 и положения «у» от 0 до -1000 за 1 секунду. 2 анимации предотвращают переопределение друг друга, устанавливая для их свойств перезаписи значение false. Эта анимация происходит после 2.5 секунд, когда этот метод вызывается и когда он завершается, он вызываетend
проходит за 4 секунды до отправки события Intro3D.INTRO_COMPLETE.
Добавьте это после animateText ()
метода:
1
2
3
4
5
6
7
8
|
private function focus (): void {
var sound1:Sound = _customLoader.getSound ( 'Explosion_hifi' ); TweenLite.to (camera, . 1 , { x: - 1550 , y: 0 , z: 0 , ease:Linear.easeNone, overwrite: false , onStart:playSound, onStartParams:[sound1, 400 , 0 , new SoundTransform ( 1 )]} ); var sound2:Sound = _customLoader.getSound ( 'Swoosh3' ); TweenLite.to (camera, 1 , { x: 2500 , y: - 1000 , ease:Strong.easeInOut, overwrite: false , onStart:playSound, onStartParams:[sound2, 0 , 0 , new SoundTransform ( 3 )], delay: 2.5 , onComplete:end, onCompleteParams:[ 4 ]} ); }
|
Шаг 53: Анимация частиц
Наконец, последний метод для этого подкласса!
Мы просто хотим, чтобы частицы двигались к камере гораздо медленнее.
Добавьте это после всего остального:
1
|
override protected function animateParticles (): void {_particles.z -= 2 ;} |
Шаг 54: Веха
Перед тестированием проверьте свой код на соответствие SubIntro3D2.as при загрузке исходного кода. Кроме того, обязательно перетащите файл LubalGraphBdBTBold.as из исходной загрузки в ту же папку, что и все классы, которые мы создали.
Примечание. К сожалению, в LubalGraphBdBTBold.as есть только те символы, которые пишут «активные действия» и «безумные навыки!». Вы не сможете использовать его для чего-либо еще из-за лицензионных ограничений.
Запустите программу и посмотрите анимацию.
Шаг 55: собирать вещи вместе
Вернуться к основному документу.
Измените onLoadComplete
метод, как показано ниже:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
private function onLoadComplete (e:Event): void {
_introArray = []; var intro:Intro3D = new Intro3D; intro.addEventListener (Intro3D.INTRO_COMPLETE, onIntroComplete); var intro1:Intro3D = new SubIntro3D1; intro1.addEventListener (Intro3D.INTRO_COMPLETE, onIntroComplete); var intro2:Intro3D = new SubIntro3D2; intro2.addEventListener (Intro3D.INTRO_COMPLETE, onIntroComplete); _introArray.push (intro); _introArray.push (intro1); _introArray.push (intro2); stage.addEventListener (MouseEvent.CLICK, onStageClick); }
|
Все 3 Intro3D создаются и назначаются слушателем для Intro3D.INTRO_COMPLETE. Мы сохраняем ссылку для каждого экземпляра Intro3D в _introArray
массиве для последующего доступа. Затем он слушает, как пользователь нажимает на сцену, чтобы запустить анимацию.
Шаг 56: Начало вступления
После щелчка по сцене мы удаляем его слушателя, чтобы предотвратить повторное воспроизведение вступлений. 1-й Intro3D
изнутри _introArray
добавляется на сцену. Помните, как мы настроили Event.ADDED_TO_STAGE
запуск движка рендеринга PV3D и анимацию трехмерного текста? Музыка также запускается, чтобы играть здесь.
Добавьте код после onLoadComplete
:
1
2
3
4
5
6
7
8
|
private function onStageClick(e:MouseEvent): void {
stage.removeEventListener (MouseEvent.CLICK, onStageClick); addChild (_introArray[ 0 ]); var sound:Sound = _customLoader.getSound ( 'FastBeat_hifi' ); sound.play (); }
|
Шаг 57: Когда вступление заканчивается
Каждый раз, когда заканчивается Intro3D, _currentIntro предварительно увеличивает на 1. Затем проверяется _introArray, чтобы увидеть, есть ли внутри него Intro3D по значению _currentIntro. Если есть Intro3D, он добавляется на сцену. Затем готовый Intro3D удаляется в любом случае.
Измените onIntroComlete
метод, как показано ниже:
1
2
3
4
5
6
7
|
private function onIntroComplete(e:Event): void {
var intro:Intro3D = _introArray [++_currentIntro]; if (intro != null ) addChild (intro); removeChild (getChildAt ( 0 )); }
|
Запустите его и наслаждайтесь фильмом!
Вы, безусловно, заслуживаете этого после всего этого кода !!! знак равно
Вывод
Теперь у вас есть базовые знания по использованию класса Intro3D. Помните, чтобы не изменять его. Вместо этого создайте подкласс и измените все, что вы хотите оттуда. Это должно послужить быстрой настройкой для 3D-анимации.
Вы также можете добавлять видео между вступлениями, чтобы улучшить их еще больше.
Как всегда, для любых комментариев, предложений или проблем, пожалуйста, оставьте примечание в разделе комментариев.
Спасибо за прочтение!