Статьи

Создание 3D-заставок с Papervision3D

В этом выпуске мы рассмотрим создание 3D-заставок с использованием Papervision3D. В этом процессе мы также рассмотрим использование реальной реализации шаблона Singleton и создадим аккуратный класс «CustomLoader», который позволит вам предварительно загружать и ставить в очередь изображения и звуки, а затем сразу отключать их все.

Все это завершается многоразовой и очень гибкой системой для создания 3D-заставок.


Откройте FlashDevelop и нажмите «Проект»> «Новый проект» …



Выберите Actionscript 3> AS3 Project.

Для названия проекта положить в Intro3D.

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


Если вы хотите использовать Flash CS3 +, создайте новый файл Flash и установите ширину и высоту 600×350, установите черный цвет фона и частоту кадров 30. Назовите его intro3D.fla и сохраните в любом месте.


Для FlashDevelop откройте каталог проекта и скопируйте или перетащите папку PV3Dassets из исходной загрузки (ссылка вверху страницы) в папку \ bin \.

Для Flash скопируйте или перетащите папку PV3Dassets из исходной загрузки в ту же папку, где находится intro3D.fla.

Также давайте рассмотрим содержимое этой папки. У нас есть 8 изображений в формате Portable Network Graphics (PNG) и 4 MP3.



Мы собираемся использовать TweenLite для анимации движения и Papervision для 3D. Оба пакета включены в исходный код загрузки. Для получения дополнительной информации, вы можете посетить их сайты на papervision и tweenlite .

Для FlashDevelop, скопируйте или перетащите greensock.swc и Papervision3D_2.1.932.swc из исходного кода в папку \ lib \ для этого проекта.

В FlashDevelop нажмите «Просмотр»> «Диспетчер проектов».



Находясь в FlashDevelop, щелкните значок «+» слева от папки lib, чтобы развернуть ее.

Выберите оба файла SWC и щелкните правой кнопкой мыши, выберите «Добавить в библиотеку».


Для Flash скопируйте или перетащите папки \ com \, \ org \ и \ nochump \ из исходной загрузки в ту же папку, что и файл intro3D.fla.


Давайте начнем работать с классом 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 и предоставят доступ к нему.


Вот список того, что должен делать этот класс.

  1. Загрузка внешних активов (визуальные и звуковые активы).
  2. Выдать список имен всех активов, которые были загружены.
  3. Сообщите слушателю, когда все активы были успешно загружены.
  4. Предоставьте актив по запросу.
  5. Если что-то пойдет не так, отправьте ошибку.

Добавьте следующие строки кода после пробела ниже статической переменной _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. Далее, метод конструктора.


Это будет немного отличаться от обычного конструктора. Здесь создание экземпляров предотвращается, если переменная _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;
}

Это единственный способ создать и получить доступ к экземпляру 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
}

Поскольку у нас есть, по существу, 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);
}

Мы вызываем этот публичный метод, как только мы назначим все активы, которые хотим загрузить. Сначала он _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]));
    }
}

Теперь давайте займемся извлечением короткого имени из 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];
}

Метод 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));
    }
}

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

Добавьте следующие строки кода после onLoadErrorComplete () :

1
2
3
4
5
private function onLoadError(e:IOErrorEvent):void
{
    //internal use
    throw new Error (e);
}

Мы можем начать использовать ресурсы, когда 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];
}

У нас есть 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;
}

Хорошо! Прежде чем перейти к основному документу, дважды проверьте, чтобы в вашем классе 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;
        }
    }
}

Для 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 работает!


(Пользователи Flash: перейдите ко второй половине этого шага.)

Здесь мы загрузим все внешние ресурсы, настроим все 3 Intro3D и подождем, пока пользователь щелкнет по сцене, чтобы запустить анимацию. Ниже перечислены обязанности Главного класса:

  1. Создайте экземпляр CustomLoader и попросите его загрузить все внешние ресурсы, которые мы будем использовать для этого приложения.
  2. Инициализируйте 3 экземпляра Intro3D и сохраните их в _introArray .
  3. Прослушайте MouseEvent.CLICK на сцене, чтобы вызвать анимацию.
  4. При щелчке по сцене воспроизводите все 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
        }
    }
}

Сохраните, прежде чем двигаться вперед.


Класс Intro3D наследуется от BasicView который, в свою очередь, наследуется от flash.display.Sprite . BasicView является частью пакета Papervision3D. Это быстрая настройка для базового проекта Papervision.

Мы объявляем защищенным свойства и методы, которые также будут использоваться подклассами. Intro3D будет расширено двумя другими вступлениями, которые мы будем называть SubIntro3D1 и SubIntro3D2. Когда вы видели анимацию, это 1-ая последовательность, а 2 других — подклассы.

Его список обязанностей:

  1. Настройте камеру, ее масштаб, цель и т. Д.
  2. Создайте фон и добавьте его в сцену.
  3. Создайте частицы и добавьте их в сцену.
  4. Добавьте 3D текст в сцену.
  5. Анимируйте камеру.
  6. Анимировать частицы.
  7. Анимируйте трехмерные тексты.
  8. Сообщите слушателю, когда анимация закончится.

Создайте новый класс и назовите его 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 () .


Добавьте следующие строки кода внутри конструктора:

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 () вызывается до конца метода.


Добавьте код после пробела ниже метода конструктора:

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, что может привести к его зависанию.


Вызывается последним, как только создается экземпляр Intro3D , этот метод подготавливает все компоненты для анимации перед добавлением экземпляра на сцену. Я объясню подробнее о каждом методе, вызываемом при его создании.

Добавьте строки ниже сразу после метода onAddedToStage :

1
2
3
4
5
6
7
protected function init():void
{
    setUpCamera ();
    createBackground ();
    createParticles ();
    addText ();
}

Добавьте это после метода init () :

1
2
3
4
5
protected function setUpCamera ():void
{
    camera.zoom = 50;
    camera.target = null;
}

Все, что относится к камере, должно быть решено здесь. Мы устанавливаем свойство масштабирования камеры на 50, а его цель — ноль.


Здесь мы создаем векторное изображение, имеющее цвет фона светло-серый с белым радиальным свечением вокруг его центра. Это будет использоваться в качестве фона для первой «сцены» вступления. _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);
}

Теперь прибывает самый большой метод для этого класса. Метод 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 подкласса позже.

Параметры:

  1. $numParticles — по умолчанию 150, это количество частиц, которое вы хотите иметь в системе.
  2. $name — по умолчанию «splat», мы передаем короткое имя String изображения (загруженного ранее через CustomLoader), которое мы хотим использовать в качестве материала для частиц.
  3. $randomColors — по умолчанию null, массив цветов, используемых для частиц (случайным образом распределенных по всем частицам).
  4. $randomX — по умолчанию используется нулевой двумерный массив минимального и максимального местоположения «x» для частиц.
  5. $randomY — по умолчанию $randomY нулю, так же, как $ randomX, но для местоположений «y».
  6. $randomZ — по умолчанию $randomZ нулю, так же, как $ randomX, но для местоположений «z».
  7. $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 .


Этот метод принимает параметр цвета в шестнадцатеричном формате и разбивает его на 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;
}

Добавьте следующие строки кода в самом низу класса:

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;
}

(См. Также этот Быстрый совет и обсуждение в комментариях.)


Этот метод также имеет параметры по умолчанию. Как и метод 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);
}

Параметры:

  1. $text — по умолчанию «хочешь выучить ActionScript?», текст для твоего Text3D.
  2. $fillColor — по умолчанию темно-красный цвет, служит цветом заливки Text3D.
  3. $fillAlpha — по умолчанию «.1», устанавливает альфа-прозрачность заливки Text3D.
  4. $lineThickness — по умолчанию «1», задает толщину границы Text3D.
  5. $lineColor — также по умолчанию темно-красный, это цвет границы Text3D.
  6. $lineAlpha — по умолчанию «1», альфа-прозрачность границы Text3D.
  7. $font3D — По умолчанию равно нулю, что эквивалентно назначению встроенного Font3D HelveticaBold.
  8. $rotationX — По умолчанию «0» градусов, это будет начальный localRotationX Text3D при добавлении в сцену.
  9. $rotationY — По умолчанию «-45» градусов, начиная с localRotationY Text3D.
  10. $rotationZ — По умолчанию «5» градусов, начиная с localRotationZ Text3D.
  11. $scale — По умолчанию «2», применяется к шкале Text3D.
  12. $align — По умолчанию «влево», функция выравнивания Text3D.
  13. $letterSpacing — По умолчанию «-2», пробел между символами.
  14. $lineSpacing — По умолчанию «30», пробел между каждой строкой текста, если Text3D многострочный (как в нашем примере).
  15. $x — По умолчанию «-550», начальная позиция x, когда Text3D добавляется к сцене.
  16. $y — По умолчанию «100», начальная позиция y, когда Text3D добавляется к сцене.
  17. $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для последующего доступа и добавляем ее на сцену.


Добавьте это после 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рассчитываются здесь.


Добавьте это после onRenderTick ()метода:

1
2
3
4
protected function animateParticles ():void
{
    _particles.z -= 20;
}

Здесь вы можете контролировать все способы _particlesанимации. Он просто перемещается _particlesближе к каждому onRenderTickсобытию, поскольку камера направлена ​​вдоль оси Z. Смотри, как брызги краски приближаются !?


Добавьте это после animateParticles ()метода:

1
2
3
4
5
protected function animateCamera ():void
{
    camera.x += (_xDist - camera.x * _reachX) * _easeOut;
    camera.y += (_yDist - camera.y * _reachY) * _easeOut;
}

Немного под влиянием движения мыши (попробуйте в демоверсии), это дает сцене ощущение в реальном времени.


Добавьте это ниже 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 исправлено так, чтобы оно заканчивалось параллельно экрану.

Остальные параметры следующие:

  1. onStart— Это срабатывает, когда TweenLite запускает эту анимацию. Он используется здесь для вызова playSoundметода, который мы добавим позже для воспроизведения звуковых эффектов для всех Intro3Ds.
  2. onStartParams— Контейнер массива для всех параметров, которые мы должны передать в playSoundметод. Я рассмотрю детали этого метода чуть позже.
  3. onComplete— Мы передаем метод, который необходимо вызвать, когда заканчивается эта анимация. Он назначен end(также создан и обсужден позже).

И это то, что заставляет 3D-текст перемещаться из-за камеры в центр сцены.


Добавьте это после 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экземпляр. Это простой и эффективный элемент управления для воспроизведения звука.


Добавьте это после 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событие.


Добавьте это после checkStatus ()метода:

1
2
3
4
5
private function onRemovedFromStage(e:Event):void
{
    removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
    stopRendering ();
}

После удаления со сцены, он останавливает движок рендеринга PV3D и экономит некоторую вычислительную мощность. Это завершает Базовый класс Intro3D.


Из-за размера класса Intro3D я воздержался от публикации здесь. Вы можете сравнить свой код с классом Intro3D.as, включенным в исходную загрузку; нам не нужно больше добавлять код к нему.


Давайте вернемся к основному классу.

Внутри 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));
}

Запустите программу.

Если все прошло хорошо, вы бы видели анимацию вместе с ее звуковым эффектом.


Создайте новый класс в той же папке, где вы сохранили 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.

Оставьте Основной класс как есть и двигайтесь вперед.


В этом подклассе мы все меняем. В этом 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 минут).


Если мы не переопределим этот метод, фон будет таким же, как Intro3Dи у. Давайте просто использовать фон сцены.

Добавьте следующие строки кода после init()метода:

1
override protected function createBackground ():void {/*do nothing*/}

Здесь мы ничего не делаем. И так как мы перекрывая Intro3D«s createBackground ()метода, он не будет применен.


Хорошо, вернемся к шагу 30. Ведь Intro3Dчастицы движутся к камере. Для этого SubIntro3D1 это заботится о том, чтобы частицы катились по их осям X.

Добавьте следующие строки кода после createBackground ()метода:

1
override protected function animateParticles ():void {_particles.localRotationX += .3;}

Трехмерные тексты начинают последовательно перемещаться в правильные позиции. Мы назначаем 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.


Просмотрите свой класс и сравните его с классом SubIntro3D.as, также включенным в загрузку исходного кода.

Перед запуском теста пройдите шаг 45.

Когда вы запускаете тест. Вы увидите 2-ю часть анимации из превью в верхней части страницы. Мы сейчас на 2/3 закончили с проектом.


Если вы хотите пропустить это, просто скачайте сопровождающий файл класса ActionScript AdelleBasicRgBold.as из исходной загрузки и поместите его в ту же папку, в которой вы все время использовали, и запустите тест.

Матье Бадимон имеет отличный инструмент для создания Font3D. Вы можете узнать больше об этом и FIVe3D (векторный 3D-движок) здесь . Я также включил zip-пакет для его «make typography file» с загрузкой Source.

Вот шаги для установки для пользователей Vista / Windows7:

  1. Введите «appdata» в строку поиска Windows, нажмите на нее, когда найдете.
  2. Перейдите к «\ Local \ Adobe \ YOUR_FLASH_VERSION_HERE \ en_US \ Configuration \ WindowSWF».
  3. Как только вы окажетесь в папке WindowsSWF, извлеките из нее файл Make typography file.swf.
  4. Установите шрифт AdelleBasic_bold.otf (он находится в исходном загрузке).
  5. Откройте Flash, создайте новый файл и назовите его vText. Сохраните его в той же папке, где у вас есть intro3D.fla.
  6. Щелкните панель «Окно» изнутри Flash, затем нажмите «Другие панели», после чего вы можете нажать «Создать новый типографский файл».
  7. Когда он откроется, выберите Adelle Basic Rg, щелкните значок Bold, оставьте остальные как есть. Имя файла теперь должно отображаться как «AdelleBasicRgBold.as».
  8. Хит генерировать. После создания файл должен находиться в той же папке, что и остальные классы, над которыми мы работали.
  9. Откройте класс AdelleBasicRgBold.as и добавьте класс Font3D. Кроме того, поскольку мы не используем пакеты для этого проекта, удалите имя пакета из верхней части документа. Будьте осторожны, чтобы не удалить объявление «package».
  10. Перейдите в конец класса перед закрывающей скобкой и вставьте следующие 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.


В целом, этот класс будет только немного больше, чем 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 секунд, а затем поверните вправо, чтобы показать «безумные навыки!».


Хорошо, мы меняем текст, его свойства и материал для частиц. Итак, перейдем к 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 вступлений, когда впервые увидели превью? Это заботится о начальной настройке.


Здесь super.setUpCameraвызывается первым, чтобы установить масштаб камеры на 50, а его цель — ноль. Затем он перемещает камеру в положение х -1500. Благодаря этой настройке зрители получат приятные трехмерные визуальные впечатления, когда камера повернет вправо, чтобы посмотреть на «безумные навыки!» 3D текст.

Добавьте это после init ()метода:

1
2
3
4
5
override protected function setUpCamera():void
{
    super.setUpCamera();
    camera.x = -1500;
}

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

Добавьте это после 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);
}

Тиснение трехмерных текстов напрямую не даст никакого эффекта, вам нужно применить его к тому, 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)];
    }
}

Трехмерный текст «активные фрагменты» перемещается из задней части сцены. 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});
}

Это та часть, где камера приближается, чтобы посмотреть на 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]} );
}

Наконец, последний метод для этого подкласса!

Мы просто хотим, чтобы частицы двигались к камере гораздо медленнее.

Добавьте это после всего остального:

1
override protected function animateParticles ():void {_particles.z -= 2;}

Перед тестированием проверьте свой код на соответствие SubIntro3D2.as при загрузке исходного кода. Кроме того, обязательно перетащите файл LubalGraphBdBTBold.as из исходной загрузки в ту же папку, что и все классы, которые мы создали.

Примечание. К сожалению, в LubalGraphBdBTBold.as есть только те символы, которые пишут «активные действия» и «безумные навыки!». Вы не сможете использовать его для чего-либо еще из-за лицензионных ограничений.

Запустите программу и посмотрите анимацию.


Вернуться к основному документу.

Измените 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массиве для последующего доступа. Затем он слушает, как пользователь нажимает на сцену, чтобы запустить анимацию.


После щелчка по сцене мы удаляем его слушателя, чтобы предотвратить повторное воспроизведение вступлений. 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 ();
}

Каждый раз, когда заканчивается 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-анимации.

Вы также можете добавлять видео между вступлениями, чтобы улучшить их еще больше.

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

Спасибо за прочтение!