Это первый день рождения ActiveTuts +! Давайте праздновать, создав музыкальную трехмерную открытку с использованием Papervision3D и TweenMax.
Шаг 1: Настройка файлов
Начните с создания новой папки (это будет корневая папка вашего проекта) и создайте в этой папке новый FLA AS3, который называется Main.fla. Он будет содержать весь интерфейс, который нам нужен для создания карты.
Для этого урока нам понадобятся две популярные библиотеки Flash: Papervision3D и TweenMax. Загрузите Papervision (я использую версию 2.1.932) и извлеките папки com и nochump из zip- файла в корневую папку вашего проекта. Загрузите TweenMax (я использую версию 11) и распакуйте zip-файл в корневую папку вашего проекта.
Теперь создайте пустой файл AS; сохраните его как «CardViewport.as» в корневой папке вашего проекта. Это будет окно просмотра papervision3d, содержащее карту. Создайте еще один пустой файл AS в той же папке с именем «Main.as.» Это будет ваш класс документов. (Не знаете, как использовать класс документа? Прочтите это краткое введение .)
Структура вашей папки должна выглядеть так:
Шаг 2: Настройка этапа
Откройте Main.fla и отредактируйте сцену, сделав ее 500×440 с частотой кадров 30 кадров в секунду. Установите класс документа в Main:
Шаг 3: Настройка слоев
Нам нужны только два слоя для этого урока:
- Контейнер для карт, который будет заполнен нашим papervision
- Слой кнопок, который вызовет действие открытия / закрытия на карте
Шаг 4: Настройка видового экрана
В слое области просмотра создайте прямоугольную форму. Увеличьте его до размера сцены и переместите в положение 0,0. Нажмите F8, чтобы преобразовать форму в символ MovieClip. Установите флажок для экспорта в ActionScript и добавьте имя класса CardViewport. Он подключится к классу, который мы создадим позже.
Теперь нажмите на мувиклип области просмотра и присвойте ему имя экземпляра «область просмотра».
Шаг 5: Фон области просмотра
Откройте символ клипа области просмотра и создайте любой фон, который вам нравится. Это то, что я сделал: пара градиентных фигур, одна для неба и одна для земли и логотип ActiveTuts + с центром в небе.
Шаг 6: Настройка кнопки
На кнопочном слое создайте прямоугольную форму. Преобразуйте его в символ клипа и назовите его «open_mc»; убедитесь, что вы даете ему то же имя экземпляра.
Внутри open_mc создайте текстовое поле. Установите его как динамический, присвойте ему имя экземпляра label_txt и внедрите шрифты, нажав «Внедрение символов» и выбрав алфавит, который вы хотите использовать.
Сделай так, как хочешь. Я построил мой с градиентом и поперечными диагональными линиями:
ПРИМЕЧАНИЕ: я не имею права распространять стандартный 07_66 , шрифт, который я использую в этом проекте. Простите за это.
Шаг 7: Активы
Время фотошопа: мы построим нашу карту так, чтобы четыре плоскости (плоские прямоугольники) были обращены друг к другу. Для этого нам нужно четыре разных файла изображения для отображения в этих плоскостях.
Наши самолеты будут иметь размер 700×900, поэтому наши четыре изображения также будут такого размера. Причина этого размера в том, что самолеты будут плавать в трехмерном пространстве на некотором расстоянии от камеры; они должны быть большими, чтобы мы могли их видеть. Назовите изображения «page_1_front.jpg», «page_1_back.jpg», «page_2_front.jpg», «page_2_back.jpg» и поместите их в корневую папку вашего проекта.
Вот мои изображения:
Эти изображения включены в основной исходный zip, но вы также можете загрузить их напрямую, если хотите.
Сделайте то же самое для звука, если хотите добавить его. Скотт Уиллс из audiojungle был достаточно любезен, чтобы собрать для нас этот фанк-трек .
Шаг 8: CardViewport.as Импорт
Откройте CardViewport.as. Я буду использовать FlashDevelop для написания кода, но вы можете использовать Flash, если хотите.
Создайте пакет и импортируйте нужные нам классы:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
package
{
//basic classes
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
//papervision classes
import org.papervision3d.objects.primitives.Plane;
import org.papervision3d.materials.BitmapFileMaterial;
import org.papervision3d.view.BasicView;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.render.QuadrantRenderEngine;
//tweening engine
import com.greensock.TweenMax;
|
Шаг 9: CardViewport.as Частные переменные
Установите приватные переменные, которые нам понадобятся для CardViewport:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
public class CardViewport extends BasicView //BasicView its a class that includes a basic viewport setup for our scene
{
//Creates 4 planes
private var front_cover:Plane;
private var front_inside:Plane;
private var back_cover:Plane;
private var back_inside:Plane;
//Creates 4 materials
private var front_cover_img:BitmapFileMaterial;
private var front_inside_img:BitmapFileMaterial;
private var back_cover_img:BitmapFileMaterial;
private var back_inside_img:BitmapFileMaterial;
//Creates the front page container, that will nest 2 planes
private var front_container:DisplayObject3D;
//Creates the back page container, that will nest the other 2 planes
private var back_container:DisplayObject3D;
//Creates a card container that will nest the front container and the back container
private var card_container:DisplayObject3D;
}
|
Шаг 10: Конструктор CardViewport.as
Вот функция, которая будет запускаться при создании CardViewport:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
public function CardViewport ()
{
super();
//to get rid of a few errors about how z-depth is calculated in our scene
//we need to change the render type to one that can correct it
setRenderType();
//Instantiates the materials and sets its properties
setMaterials();
//Instantiates the planes, adds the materials to the planes, adds the planes to the wrappers (containers)
setPlanes();
//renders the camera every frame
stage.addEventListener(Event.ENTER_FRAME, render);
//repositions the planes based on mouse’s position
stage.addEventListener(MouseEvent.MOUSE_MOVE, positionPlanes);
}
|
Шаг 11: CardViewport.as Тип рендеринга
Чтобы избавиться от нескольких ошибок о том, как z-глубина вычисляется в нашей сцене, нам нужно изменить тип рендеринга на тот, который можно исправить. QuadrantRenderEngine принимает один параметр: тип коррекции. На этот раз мы будем исправлять z-фильтр, используйте это с умом, поскольку он может перегружать ваш процессор в сложных ситуациях.
1
2
3
4
|
private function setRenderType()
{
this.renderer = new QuadrantRenderEngine(QuadrantRenderEngine.CORRECT_Z_FILTER)
}
|
Шаг 12: Настройка материалов CardViewport.as
Несмотря на то, что мы не видим четвертый самолет (оборотная сторона карты), я все равно решил добавить его на тот случай, если вы захотите поиграть со сценой.
Мы будем использовать BitmapFileMaterial, установив «точное» в true, я улучшаю общее качество, но я также использую больше ресурсов процессора.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
private function setMaterials():void
{
//Front Cover Page
front_cover_img = new BitmapFileMaterial(«page_1_front.jpg»,true);
front_cover_img.doubleSided = false;
front_cover_img.fillAlpha = 1.0;
//Front Inside Page
front_inside_img = new BitmapFileMaterial(«page_1_back.jpg»,true);
front_inside_img.doubleSided = false;
front_inside_img.fillAlpha = 1.0;
//Back Inside Page
back_inside_img = new BitmapFileMaterial(«page_2_front.jpg»,true);
back_inside_img.doubleSided = false;
back_inside_img.fillAlpha = 1.0;
//Back Cover Page
back_cover_img = new BitmapFileMaterial(«page_2_back.jpg»);
back_cover_img.doubleSided = false;
back_cover_img.fillAlpha = 1.0;
}
|
Шаг 13: CardViewport.as Настройка самолетов
Здесь мы создаем четыре самолета, которые составляют нашу карту, упорядочивая их в пару контейнеров, чтобы они выглядели как две страницы.
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
|
private function setPlanes():void
{
//Creates the front Plane Cover
front_cover = new Plane( front_cover_img, 700, 900, 3, 3 );
front_cover.z = 0;
front_cover.x = 350//this offset will be used later so we can open the card
//Creates the inside of the front Plane
front_inside = new Plane( front_inside_img, 700, 900, 3, 3 );
front_inside.z = 0;
front_inside.rotationY = 180;//rotated 180 degrees so we can see it from the inside
front_inside.x = 350//its exactly half the width of the plane
//Creates a wrapper object so we can rotate the front page from a different axis
//that of the pages.
//coordinates and we can just offset it.
front_container = new DisplayObject3D();
front_container.addChild(front_cover);
front_container.addChild(front_inside);
front_container.x-=350//here we are offsetting it
//Repeat the process for the second page
back_inside = new Plane( back_inside_img, 700, 900, 3, 3 );
back_inside.z = 0.1;
back_inside.x = 350
back_cover = new Plane( back_cover_img, 700, 900, 3, 3 );
back_cover.z = 0.1;
back_cover.rotationY = 180;
back_cover.x = 350
back_container = new DisplayObject3D();
back_container.addChild(back_inside);
back_container.addChild(back_cover);
back_container.x -= 350
//And after everything add the front and back containers to the main wrapper and add the wrapper to the scene.
card_container = new DisplayObject3D();
card_container.addChild(front_container)
card_container.addChild(back_container)
scene.addChild( card_container );
}
|
Шаг 14: CardViewport.as openCard ()
Обратите внимание, что это открытая функция, поэтому мы можем получить к ней доступ через класс основного документа, когда нажмем кнопку:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
public function openCard()
{
//When we open the card we need to remove the mouse listeners from stage because
//when we mouse move we rotate stuff, sometimes the containers sometimes the planes themselves,
//therefore we cannot rotate both simultaneously as we will end up with animation errors
stage.removeEventListener(MouseEvent.MOUSE_MOVE, positionPlanes);
//we need to reset the planes’ positions inside the containers
resetPlanesPosition();
//we rotate the front container 180 degrees and set the x to 0,
//because we offset the planes earlier it now rotates accordingly.
TweenMax.to(front_container, 1.4, { rotationY:180, x:0,onComplete:function(){ stage.addEventListener(MouseEvent.MOUSE_MOVE, positionContainer); } } );
TweenMax.to(back_container, 1.4, { x:0 } );
//after the rotation we add a new listener to the mouse.
}
|
Шаг 15: CardViewport.as closeCard ()
То же самое для закрытия карты:
01
02
03
04
05
06
07
08
09
10
11
|
public function closeCard()
{
//when we close the card the steps are very similar to when we open.
stage.removeEventListener(MouseEvent.MOUSE_MOVE, positionContainer);
//difference is where we reset the main container’s rotation
card_container.rotationY = card_container.rotationX = 0
//we reset the front and back containers’ x and rotationY properties
TweenMax.to(front_container, 1.4, { rotationY:0, x:-350, onComplete:function(){ stage.addEventListener(MouseEvent.MOUSE_MOVE, positionPlanes); } } );
TweenMax.to(back_container, 1.4, { x: -350 } );
//and after the animation we add the previous mouse move event action to position the planes
}
|
Шаг 16: CardViewport.as Позиционные плоскости
Это вызывается всякий раз, когда мышь перемещают, когда карта закрыта:
1
|
private function positionPlanes(event:Event):void { //it rotates between -25º and 25º depending on the mouse position front_cover.rotationY = back_inside.rotationY = (stage.mouseX / stage.stageWidth * 50)-25 front_cover.rotationX = front_inside.rotationX = back_cover.rotationX = back_inside.rotationX = (stage.mouseY / stage.stageHeight * 50) — 25 //we only need to add 180 to the faces that are supposed to be against us front_inside.rotationY = back_cover.rotationY = ((stage.mouseX / stage.stageWidth * 50) — 25) + 180 }
|
Шаг 17: CardViewport.as Позиционный контейнер
Это вызывается всякий раз, когда мышь перемещается, когда карта открыта:
1
2
3
4
5
6
|
private function positionContainer(event:Event):void
{
//just like the planes.
card_container.rotationY = (stage.mouseX / stage.stageWidth * 50)-25
card_container.rotationX = (stage.mouseY / stage.stageHeight * 50) — 25
}
|
Шаг 18: CardViewport.as Сбросить плоскости
Это вызвано, когда карта нажата, чтобы открыть:
1
2
3
4
5
6
|
private function resetPlanesPosition()
{
//the function name sais it all, it rotates the planes back to its original created position
front_inside.rotationY = back_cover.rotationY = 180
front_cover.rotationY = back_inside.rotationY = front_cover.rotationX = front_inside.rotationX = back_cover.rotationX = back_inside.rotationX =0
}
|
Шаг 19: Визуализация CardViewport.as
Последний шаг — это визуализация области просмотра, после чего мы переходим к классу документа.
1
2
3
4
5
|
private function render(event:Event):void
{
//singleRender is a BasicView function that activates the render in that given time.
singleRender();
}
|
Это конец класса. Не забудьте добавить закрывающие фигурные скобки.
Шаг 20: CardViewport.as Полный код
Мы ничего не изменим в классе CardViewport, поэтому не стесняйтесь получить исходный код из zip-файла и сравнить его с вашим собственным.
Шаг 21: Main.as Импорт
Этот шаг довольно прост, нам просто нужно связать открытую карту и закрыть действия карты с кнопкой. Перед этим давайте импортируем следующие классы в наш пакет:
1
2
3
4
5
6
7
|
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.media.Sound;
import flash.net.URLRequest;
|
Шаг 22: Main.as Конструктор
Опять же, ничего особенного, он расширяет MovieClip и создает объект Sound:
1
2
3
4
|
public class Main extends MovieClip
{
private var birthday_song:Sound
}
|
Шаг 23: Main.as Основная функция
Вот небольшой совет для вас, ребята: для предотвращения пустых ошибок инициализируйте ваши команды только после того, как класс был добавлен на сцену. Таким образом, вы уверены, что все, к чему вы пытаетесь получить доступ, присутствует.
1
2
3
|
public function Main():void {
addEventListener(Event.ADDED_TO_STAGE,init)
}
|
Шаг 24: Функция инициализации Main.as
… и эта функция будет запущена, когда класс документа будет добавлен на сцену:
1
2
3
4
5
6
7
8
|
private function init(event:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, init) //we don’t need this anymore
open_mc.label_txt.text = «_!OPEN CARD!_» //Labels the button
open_mc.buttonMode = true;
open_mc.mouseChildren = false;
open_mc.addEventListener(MouseEvent.CLICK, openCard) //Adds an event listener to the mouse click
}
|
Шаг 25: Main.as Нажмите, чтобы открыть обработчик
Эта функция будет запущена при нажатии карты, если она закрыта:
1
2
3
4
5
6
7
8
9
|
private function openCard(event:MouseEvent):void
{
open_mc.removeEventListener(MouseEvent.CLICK, openCard);
viewport.openCard();
open_mc.label_txt.text = «_!CLOSE CARD!_» // changes the label
open_mc.addEventListener(MouseEvent.CLICK, closeCard) //adds a listener to close the card on mouse click
birthday_song = new Sound(new URLRequest(«birthday.mp3»));
birthday_song.play();
}
|
Шаг 26: Main.as Нажмите, чтобы закрыть обработчик
Это в основном то же самое, что и openCard (), но в обратном порядке. 😉
1
2
3
4
5
6
7
|
private function closeCard(event:MouseEvent):void
{
open_mc.removeEventListener(MouseEvent.CLICK, closeCard)
viewport.closeCard();
open_mc.label_txt.text = «_!OPEN CARD!_»
open_mc.addEventListener(MouseEvent.CLICK, openCard)
}
|
Шаг 27: Завершить Main.as
Законченный. Нет секретов в этом классе документов, это довольно просто. Не забудьте добавить закрывающие фигурные скобки.
Вывод
Я хотел бы, чтобы вы развились из этого урока, взяв несколько небольших советов, которые я вам дал, от ADDED_TO_STAGE до оболочки displayObject3d, до использования класса анимации движения для вращения и перемещения трехмерного объекта. Возьми эту карту и сделай ее своей.
С Днем Рождения Activetuts +! Надеюсь, вам понравился этот урок, спасибо за чтение!