Во второй и последней части этого урока мы дополним наш интерфейс трехмерного меню специальными эффектами и подменю, включая трехмерные компоненты, такие как переключатели.
Продолжение части 1: Структура …
Также доступно в этой серии:
- Создайте стильный 3D-интерфейс с Papervision3D: структура
- Создайте стильный 3D-интерфейс с Papervision3D: эффекты и подменю
Шаг 38: Создание пользовательского эффекта искажения в 3D
Вернитесь к ссылке предварительного просмотра и посмотрите на MainMenu3D в течение нескольких секунд, чтобы увидеть этот эффект в действии. Этот класс будет применять искажение ко всем DisplayObject3D внутри MainMenu3D. Его список обязанностей:
- создать новый пользовательский растровый рисунок для использования в качестве DisplacementMapFilter для каждого цикла таймера
- добавить случайный таймер, который зацикливается и применяет фильтр к назначенному массиву ViewportLayers
- воспроизводить звук каждый раз, когда применяется эффект
- обеспечить внешний доступ для активации и деактивации эффекта
Этот класс будет выполнять свою работу без необходимости добавления в список отображения. Это также не расширяет любой другой класс.
Создайте новый класс, назовите его DistortionEffect3D и сохраните его вместе с остальными классами. Вставьте код ниже в это:
пакет { import com.greensock.TweenLite; импорт flash.display.Bitmap; импортировать flash.display.BitmapData; import flash.display.BitmapDataChannel; импорт flash.display.Shape; импорт flash.events.TimerEvent; импорт flash.filters.BitmapFilter; импорт flash.filters.BlurFilter; импортировать flash.filters.DisplacementMapFilter; импортировать flash.filters.DisplacementMapFilterMode; импорт flash.geom.Point; импорт flash.media.Sound; импорт flash.media.SoundTransform; импорт flash.utils.Timer; import org.papervision3d.view.layer.ViewportLayer; открытый класс DistortionEffect3D { private var _vieportLayerArray: Array; // присваиваем массив ViewportLayers, переданный из конструктора приватная переменная _map: BitmapData; // BitmapData, который рисуется объектом Shape частный var mapBitmap: Bitmap; // Растровое изображение, используемое в качестве mapBitmap для DisplacementMapFilter приватная переменная _filter: DisplacementMapFilter; // фильтр, используемый для эффекта частный случай _ Таймер: Таймер; // таймер от 5 до 20 секунд для генерации эффекта private var _active: Boolean; // включает или выключает эффект частный звук: звук; // звуковой эффект, используемый каждый раз, когда применяется фильтр частный var _shape: Shape; // используется как быстрый инструмент рисования для создания горизонтальных линий открытая функция DistortionEffect3D ($ vieportLayerArray: Array) { //Начни здесь } } }
Опять же, см. Комментарии рядом с каждым свойством для краткого описания.
Шаг 39: конструктор DistortionEffect3D
Добавьте код ниже внутри метода конструктора:
_vieportLayerArray = $ vieportLayerArray; _shape = новая форма (); var customLoader: CustomLoader = CustomLoader.getInstance (); _sound = customLoader.getSound ('staticNoise3'); createDistortion ();
Здесь необходимые свойства назначаются и сохраняются для справки позже, чем вызывается метод createDistortion ().
Шаг 40: петля эффектов, часть 1 — подготовка инструментов
Этот метод также будет вызываться каждый раз при завершении случайного таймера. Добавьте код ниже после конструктора:
защищенная функция createDistortion (): void {_shape.graphics.clear (); _shape.graphics.beginFill (0x888888); var randomColor: uint = 0; var divCount: uint = uint (400 / Main.getRandomInRange (1, 5)); // каждый раз назначаем немного другой рисунок для (var i: uint = 0; i <divCount; i ++) // рисуем от 80 до 400 линий на объекте Shape {_shape.graphics.drawRect (0, 400 / divCount * i , 400, 400 * DivideCount); // настроить толщину каждой линии, чтобы иметь одинаковое покрытие randomColor = randomColor == 0? 0xFFFFFF: 0; // если цвет белый, сделать его черным _shape.graphics.beginFill (randomColor); // применить цвет} _shape.graphics.endFill (); _map = new BitmapData (600 600, false, 0); // убедитесь, что эффект искажения достаточно велик, чтобы охватить все MainMenu3D _map.draw (_shape); var blurFilter: BlurFilter = новый BlurFilter (15,15); // применить размытие, чтобы эффект не был слишком неровным _map.applyFilter (_map, _map.rect, new Point (), blurFilter); // применить фильтр к BitmapData mapBitmap = new Bitmap (_map); // сделать растровое изображение _filter = new DisplacementMapFilter (); _filter.mapBitmap = _map; // используем изображение для DisplacementMapFilter _filter.componentX = BitmapDataChannel.RED; _filter.componentY = BitmapDataChannel.BLUE; _filter.scaleX = 0; _filter.scaleY = 0; _filter.mode = DisplacementMapFilterMode.CLAMP; _timer = новый таймер (Main.getRandomInRange (5000, 20000), 1); // создаем новый таймер _timer.addEventListener (TimerEvent.TIMER_COMPLETE, onTimerComplete); _timer.start (); }
Каждый раз, когда вызывается этот метод, из объекта Shape создается новое изображение BitmapData. Затем эти BitmapData применяются к растровому изображению, которое затем используется в качестве базового изображения для эффекта искажения. В конце метода таймеру назначается другая длительность от 5 до 20 секунд, и он повторяется только один раз.
Шаг 41: петля эффектов, часть 2 — применение
По завершении работы таймера TweenLite используется для применения эффекта, воспроизведения звука, а после завершения вызывает метод createDistortion (), чтобы начать все заново. Добавьте код ниже:
приватная функция onTimerComplete (e: TimerEvent): void { if (_active) // если активирован { var tempScaleX: Number = Main.getRandomInRange (50, 100); // случайное значение между 50 и 100 - также помогает сделать изображение фильтра уникальным каждый раз, когда оно воссоздается // используем TweenLite для анимации scaleX и scaleY в DisplacementMapFilter TweenLite.to ( _filter, // цель анимации движения .4, // продолжительность анимации { scaleX: tempScaleX, // свойство анимации движения от 0 до значения tempScaleX scaleY: tempScaleX / 4, // свойство для анимации 1/4 силы tempScaleX onStart: playSound, // метод, вызываемый при запуске анимации onStartParams: [tempScaleX], // параметр для метода playSound onUpdate: assignFilter, // функция, вызываемая каждый раз, когда анимация обновляется overwrite: false // будет перезаписан другой анимацией для той же цели } ); // используем TweenLite для затухания анимации через 0,4 секунды TweenLite.to ( _фильтр, +0,4, { Scalex: 0, шкала Y: 0, OnUpdate: assignFilter, delay: .4, // пусть предыдущая анимация закончится, прежде чем исчезнет перезаписать: ложь, onComplete: createDistortion // когда закончите, вызовите createDistortion (), чтобы начать все сначала } ); // очистить таймер _timer.stop (); _timer.removeEventListener (TimerEvent.TIMER_COMPLETE, onTimerComplete); _timer = null; } еще // если деактивирован { _timer.stop (); _timer.removeEventListener (TimerEvent.TIMER_COMPLETE, onTimerComplete); _timer = null; createDistortion (); // начать все сначала } }
Если для свойства _active установлено значение true, фильтр применяется, а если нет, цикл просто запускается снова, пропуская эффект. Давайте добавим 2 вспомогательных метода:
приватная функция playSound ($ scaleX: Number): void { var transform: SoundTransform = new SoundTransform ($ scaleX * .01); _sound.play (0, 0, преобразование); } приватная функция assignFilter (): void { для каждого (var viewport: ViewportLayer в _vieportLayerArray) viewport.filters = [_filter]; }
Метод playSound () воспроизводит звук с соответствующей громкостью для интенсивности эффекта. $ scaleX находится в диапазоне от 50 до 100, поэтому громкость звука будет варьироваться от 0,5 до 1. Метод assignFilter () вызывается при каждом обновлении TweenLite и применяет преобразованный фильтр ко всем элементам ViewportLayers в _viewportLayerArray.
Шаг 42: Внешнее управление
Как вы видели по ссылке предварительного просмотра, после нажатия кнопки MainMenu3D покидает сцену и заменяется либо игрой, либо подменю. Когда это произойдет, нам не понадобится эффект, пока MainMenu3D снова не вернется на сцену. Следующие два метода позаботятся об этом для нас:
публичная функция deActivate (): void {_active = false; } публичная функция activ (): void {_active = true; }
И это завершает класс DistortionEffect3D.
Шаг 43: Веха, применяющая искажения к MainMenu3D
Вернитесь к методу setMenuEffect () MainMenu3D и добавьте в него приведенный ниже код:
var viewportLayerArray: Array = []; для каждого (переменная компонента: UIComponent3D в this.children) { viewportLayerArray.push (component.interfaceLayer); viewportLayerArray.push (component.textLayer); } _distortion = новый DistortionEffect3D (viewportLayerArray);
Не забудьте раскомментировать объявление свойства _distortion в верхней части класса. Все, что мы здесь делаем, — это просматриваем все UIComponent3D внутри MainMenu3D, чтобы получить доступ к их ViewportLayers и поместить их все в массив. После того, как собраны все слои ViewportLayers, для которых вы хотите применить эффект искажения, самое время создать экземпляр DistortionEffect3D и передать массив в качестве единственного параметра. Затем перейдите к методу prepareIntro () MainMenu3D и добавьте приведенный ниже код в самом начале:
if (_distortion) _distortion.activate (); // если _distortion не нуль, активировать его
Теперь добавьте код, чтобы отключить его, когда MainMenu3D не является текущим меню. Перейдите к методу startExit () в MainMenu3D и добавьте код в самом начале:
if (_distortion) _distortion.deActivate (); // если _distortion не нуль, деактивировать его
Идите вперед и запустите программу. Пример результата связан здесь . Вы должны увидеть и услышать, как эффект искажения повторяется где-то между 5 и 20 секундами.
Шаг 44: дополнительные эффекты — StaticGlow3D
А сейчас давайте сосредоточимся на добавлении еще 3 эффектов для улучшения нашего интерфейса. Во-первых, класс StaticGlow3D, который добавит прозрачное свечение для всех меню. Мы хотим, чтобы наши меню выглядели голографическими, и этот класс обеспечит этот эффект. Его обязанности:
- нарисовать BitmapData в качестве базового изображения для эффекта
- обеспечить внешний контроль для анимации входа и выхода
- есть 2 различных способа анимировать эффект и соответствовать тому, как открывается активное меню
Создайте новый класс с именем StaticGlow3D и расширьте для него DisplayObject3D. Вставьте код ниже, заменив все внутри, чтобы начать:
пакет { импорт com.greensock.easing.Expo; import com.greensock.TweenMax; импортировать flash.display.BitmapData; import flash.display.BitmapDataChannel; импорт flash.display.Graphics; импорт flash.display.Sprite; импорт flash.filters.BlurFilter; импорт flash.geom.Point; import org.papervision3d.materials.BitmapMaterial; import org.papervision3d.objects.DisplayObject3D; import org.papervision3d.objects.primitives.Plane; import org.papervision3d.view.layer.ViewportLayer; import org.papervision3d.view.Viewport3D; открытый класс StaticGlow3D расширяет DisplayObject3D { защищенная переменная плоскость: плоскость; защищенная переменная _bitmapData: BitmapData; защищенная переменная _alphaBitmap: BitmapData; защищенный var _viewport: Viewport3D; защищенная переменная _backgroundLayer: ViewportLayer; публичная функция StaticGlow3D ($ name: String, $ viewport: Viewport3D) { супер ($ name); _viewport = $ viewport; в этом (); } } }
Все переменные объявлены защищенными для наследования. StaticGlow3D будет служить суперклассом для классов BackgroundGlow3D и BackgroundNoise3D. Его конструктор вызывает super (), чтобы назначить имя для DisplayObject3D. Затем устанавливается свойство _viewport и вызывается init ().
Шаг 45: подготовка визуального актива для эффекта
Метод init () создает изображение, используемое для эффекта. Добавьте код ниже после конструктора:
защищенная функция init (): void { _bitmapData = new BitmapData (400, 400, true, 0); // BitmapData используется в качестве материала для 3D-плоскости _alphaBitmap = new BitmapData (400, 400, true, 0); // BitmapData, которая использовала для исчезновения сторон _bitmapData var sprite: Sprite = новый Sprite; // инструмент для рисования // рисуем скругленный прямоугольник var g: Graphics = sprite.graphics; g.beginFill (0, 1); // цвет здесь не важен, так как мы копируем только его альфа-канал g.drawRoundRect (50, 50, 300, 300, 100, 100); // центр, чтобы дать достаточно места для затухания sprite.filters = [новый BlurFilter (50, 50)]; // размываем прямоугольник так, чтобы стороны медленно исчезали _alphaBitmap.draw (sprite) // нарисовать спрайт в _alphaBitmap BitmapData g.clear (); // повторно использовать объект Graphics, чтобы нарисовать новый скругленный прямоугольник g.beginFill (0x6AB5FF, 1); // цвет для свечения g.drawRoundRect (0, 0, 400, 400, 100, 100); // нарисовать больший прямоугольник, достаточно большой, чтобы скопировать все _alphaBitmap с размытием _bitmapData.draw (sprite); // рисуем новое изображение в _bitmapData // копирование альфа-канала _alphaBitmap для применения блеклых сторон к _bitmapData _bitmapData.copyChannel (_alphaBitmap, _alphaBitmap.rect, новая точка, BitmapDataChannel.ALPHA, BitmapDataChannel.ALPHA) var material: BitmapMaterial = new BitmapMaterial (_bitmapData); // используется как BitmapMaterial _plane = новый самолет (материал, 1400,1200,4,4); // создаем плоскость, используя материал _backgroundLayer = _viewport.getChildLayer (_plane); // доступ к свойству ViewportLayer для применения фильтров и эффектов _backgroundLayer.alpha = 0; // сделать полностью невидимым _backgroundLayer.layerIndex = -1; // так что всегда в фоновом режиме addChild (_plane); // добавить в качестве дочернего элемента DisplayObject3D }
Как видно из комментариев, 3D-плоскости предоставлен специальный материал из двух растровых данных. Вероятно, проще, если мы просто использовали объект VectorShape3D и применили к нему размытие, но это тоже хорошо. Позже вы увидите, как мы можем использовать этот же принцип и создавать статический эффект с выцветшими углами.
Шаг 46: Контроль и использование
Как только все будет подготовлено, все, что нам нужно сделать, — это внешний контроль за постепенным исчезновением эффекта. Добавьте 2 последних метода:
public function flash ($ sideways: Boolean = false): void {if ($ sideways == true) {_backgroundLayer.scaleX = .2; // сжимаем изображение на 1/5 его первоначальной ширины} else {_backgroundLayer.scaleY = .2; // сжимаем изображение на 1/5 его первоначальной высоты} TweenMax.to (_backgroundLayer, // цель анимации движения .4, {delay: .4, // воспроизведение через 0,4 секунды для синхронизации с меню alpha: .2, / / конечное значение для альфа-свойства scaleX: 1, // конечное значение для свойства scaleX - работает, если $ sideways равно true scaleY: 1, // конечное значение для свойства scaleY - работает для упрощения по умолчанию: Expo.easeInOut, // используемый тип легкости overwrite: false, // нельзя перезаписать onComplete: TweenMax.to, // метод вызывается, когда анимация завершает onCompleteParams: [_ backgroundLayer, .4, {alpha: .07}] // параметры, передаваемые для метод вызывается onComplete}); } открытая функция fadeOut ($ sideways: Boolean = false): void {if ($ sideways == true) {TweenMax.to (_backgroundLayer, 1, {scaleX: .2, scaleY: 1, облегчение: Expo.easeInOut, перезапись: ложный } ); } else {TweenMax.to (_backgroundLayer, 1, {scaleX: 1, scaleY: .2, ease: Expo.easeInOut, overwrite: false}); } TweenMax.to (_backgroundLayer, .4, {delay: .4, alpha: 0, overwrite: false}); }
Метод flash () вызывается до появления меню на сцене. Он проверяет значение $ sideway и анимирует на основе этого значения. Если значение $ sideways равно true, например, когда мы заходим в меню настроек, свойство scaleX свечения сжимается, а затем переходит в нормальное состояние. Если в качестве значения по умолчанию оставить $ sideways — false, как, например, при переходе в главное меню, свойство scaleY свечения сжимается, а затем переходит в нормальное состояние. Второй публичный метод, fadeOut (), делает противоположное и вызывается при закрытии меню. Только на этот раз изображение истончается, а затем исчезает.
Шаг 47: Тестирование вехи StaticGlow3D
Сначала перейдите в начало класса, где объявлены свойства, и добавьте _staticGlow в качестве свойства экземпляра. Войдите в метод init () тестера и добавьте вызов addStaticGlow () перед вызовом addMainMenu (). Затем добавьте приведенный ниже код после метода init ():
приватная функция addStaticGlow (): void { _staticGlow = new StaticGlow3D ('staticglow', область просмотра); scene.addChild (_staticGlow); }
Затем перейдите внутрь методов addMainMenu () и onMenuExitComplete (). Добавьте вызов _staticGlow.flash () после вызова метода startIntro () MainMenu3D. Затем перейдите в начало метода navigateTo () и добавьте вызов _staticGlow.fadeOut (). Методы должны выглядеть следующим образом:
приватная функция addMainMenu (): void { var mm: MainMenu3D = новый MainMenu3D («меню», область просмотра); mm.addEventListener (MainMenu3D.START_GAME_CLICKED, navigateTo); mm.addEventListener (MainMenu3D.SETTINGS_CLICKED, navigateTo); mm.addEventListener (MainMenu3D.ABOUT_CLICKED, navigateTo); mm.addEventListener (MainMenu3D.EXIT_CLICKED, navigateTo); mm.addEventListener (MainMenu3D.EXIT_COMPLETE, onMenuExitComplete); scene.addChild (mm); mm.startIntro (); _staticGlow.flash (); // добавить этот вызов } приватная функция navigateTo (e: Event): void { _staticGlow.fadeOut (); // добавить этот вызов переключатель (электронный тип) { case MainMenu3D.START_GAME_CLICKED: трассировка («загрузить игру и играть»); перемена; case MainMenu3D.SETTINGS_CLICKED: трассировка («меню настроек загрузки»); перемена; case MainMenu3D.ABOUT_CLICKED: трассировка («загрузить о меню»); перемена; case MainMenu3D.EXIT_CLICKED: трассировка («выход из приложения»); перемена; } } приватная функция onMenuExitComplete (e: Event): void { MainMenu3D (e.target) .startIntro (); _staticGlow.flash (); // добавить этот вызов }
Запустите программу, и вы должны получить результат, показанный по ссылке здесь . Хорошо! Далее идет класс StaticNoise3D.
Шаг 48: применение статического шума в PV3D
Если вы хотите увидеть этот эффект в действии, перейдите по ссылке предварительного просмотра, размещенной выше, и измените Качество на лучшее в меню настроек. Этот класс будет расширять StaticGlow3D и применять некоторые модификации. Вот список:
- нарисовать изображение для использования в качестве статического шума // так же, как суперкласс
- обеспечить внешнее управление для анимации входа и выхода // так же, как суперкласс
- есть 2 различных способа анимировать эффект и соответствовать тому, как открывается активное меню // то же, что и суперкласс
- обеспечить внешний доступ для вызовов обновления для применения случайного шума к BitmapData для эффекта // дополнительная ответственность
Создайте новый класс и назовите его BackgroundNoise3D, пусть он расширяет StaticGlow3D.
Скопируйте приведенный ниже код и замените на него содержимое нового класса:
пакет { import flash.display.BitmapDataChannel; импорт flash.geom.Point; import flash.utils.getTimer; import org.papervision3d.view.Viewport3D; открытый класс BackgroundNoise3D расширяет StaticGlow3D { публичная функция BackgroundNoise3D ($ name: String, $ viewport: Viewport3D) { супер ($ name, $ viewport); } } }
Поскольку мы используем ООП, нам нужно импортировать только то, что нам нужно, чтобы изменить класс. Конструктор класса принимает те же 2 параметра и передает их обоим в StaticGlow3D.
Шаг 49: Подготовка, контроль и использование
Как показано в списке обязанностей, все очень похоже на суперкласс, за исключением того, как создается эффект и 1 дополнительная ответственность. Метод update () позаботится о применении шума к BitmapData, который используется для эффекта. Это, я думаю, самый маленький класс в этом проекте. Добавьте код ниже:
публичная функция update (): void { _bitmapData.noise (getTimer (), 0, 255, 7, true); // применить шум к BitmapData _bitmapData.copyChannel (_alphaBitmap, _alphaBitmap.rect, новая точка, BitmapDataChannel.ALPHA, BitmapDataChannel.ALPHA); // применить альфа-канал _alphaBitmap }
Вы можете получить больше информации о методе BitmapData.noise () здесь . Вот и все. BackgroundNoise3D закончен! Еще один хороший пример силы ООП.
Шаг 50: веха в применении BackgroundNoise3D
Внутри метода init () тестера добавьте вызов addBackgroundNoise () чуть ниже вызова метода addStaticGlow. Скопируйте код ниже после фактического метода addStaticGlow ():
приватная функция addBackgroundNoise (): void { _backgroundNoise = new BackgroundNoise3D ('backgroundNoise', область просмотра); // убедитесь, что вы объявили переменную экземпляра scene.addChild (_backgroundNoise); }
Далее, он управляется так же, как StaticGlow3D. Добавьте коды ниже в соответствии с комментарием, размещенным над каждым кодом:
// добавляем после вызова _staticGlow.flash в методах addMainMenu () и onMenuExitComplete () _backgroundNoise.flash (); // добавить ниже вызов _staticGlow.fadeOut в методе navigateTo () _backgroundNoise.fadeOut ();
Наконец, нам нужно повторно вызывать его метод update (), чтобы отразить изменения, примененные к шумовому эффекту. Добавьте приведенный ниже код в метод onRenderTick ():
_backgroundNoise.update ();
Не забудьте объявить _backgroundNoise как свойство экземпляра типа BackgroundNoise3D в верхней части класса. Теперь вы можете запустить программу. Это должно выглядеть как ссылка здесь .
Шаг 51: еще один эффект — BackgroundGlow3D
Мне все еще казалось, что меню было неполным, поэтому я подумал, почему бы не добавить полосатый фон, который светится до того, как меню оживут. Его список обязанностей:
- нарисовать изображение, чтобы использовать его как полосатое свечение // изменено из суперкласса
- обеспечить внешнее управление для анимации входа и выхода // изменено из суперкласса
- воспроизводить звук каждый раз, когда применяется эффект // дополнительная функциональность
Создайте новый класс и назовите его BackgroundGlow3D. Это тоже расширит StaticGlow3D. Скопируйте код ниже, заменив все в новом классе:
пакет { import com.greensock.TweenLite; импортировать flash.display.BitmapData; import flash.display.BitmapDataChannel; импорт flash.display.Graphics; импорт flash.display.Sprite; импорт flash.filters.BlurFilter; импортировать flash.filters.GlowFilter; импорт flash.geom.Point; импорт flash.media.Sound; импорт flash.media.SoundTransform; import org.papervision3d.materials.BitmapMaterial; import org.papervision3d.objects.primitives.Plane; import org.papervision3d.view.Viewport3D; открытый класс BackgroundGlow3D расширяет StaticGlow3D { публичная функция BackgroundGlow3D ($ name: String, $ viewport: Viewport3D) { супер ($ name, $ viewport); // так же, как суперкласс } } }
Здесь происходит больше импорта из-за небольшого количества изменений в изображении для эффекта. Но конструктор остается идентичным.
Шаг 52: Подготовка визуального актива
Размеры одинаковы, но на этот раз мы рисуем линии с пробелами между ними в BitmapData. Добавьте код ниже после конструктора:
переопределить защищенную функцию init (): void { _bitmapData = new BitmapData (400, 400, true, 0); _alphaBitmap = new BitmapData (400, 400, true, 0); var _parentSprite: Sprite = новый Sprite; var sprite: Sprite = новый Sprite; var g: Graphics = sprite.graphics; g.beginFill (0, 1); g.drawRoundRect (25, 50, 350, 300, 100, 300); sprite.filters = [новый BlurFilter (50, 50)]; _alphaBitmap.draw (sprite) g.clear (); // начало изменений var color: uint = 0xB3FFFF; для (var i: uint = 0; i <35; i ++) { спрайт = новый спрайт; g = sprite.graphics; g.lineStyle (.5, цвет, .3); g.moveTo (-20,0); g.lineTo (420, 0) sprite.y = i * 11; _parentSprite.addChild (sprite); } // добавлено свечение _parentSprite.filters = [new GlowFilter (color, 1, 5, 5, 3)]; // конец изменений спрайт = новый спрайт; g = sprite.graphics; g.beginFill (0xC6FFFF, 1); // применил другой цвет g.drawRoundRect (0, 0, 400, 400, 100, 100); _bitmapData.draw (_parentSprite); _bitmapData.copyChannel (_alphaBitmap, _alphaBitmap.rect, новая точка, BitmapDataChannel.ALPHA, BitmapDataChannel.ALPHA) var material: BitmapMaterial = new BitmapMaterial (_bitmapData); _plane = новый самолет (материал, 1400,1200,4,4); _backgroundLayer = _viewport.getChildLayer (_plane); _backgroundLayer.alpha = 0; _backgroundLayer.layerIndex = -1; addChild (_plane); }
Смотрите комментарий в коде, где написано «начало изменений»? Эта часть добавляет спрайты с нарисованными на них линиями и добавляет их в _parentSprite. _ParentSprite затем используется в качестве фона для BitmapData, используемого в качестве материала для 3D-плоскости.
Шаг 53: Внешнее управление
Этот эффект будет иметь только один внешний контроль. Метод flash () будет вызываться каждый раз при загрузке меню. В отличие от эффекта статического свечения, который остается с меню, этот эффект исчезнет, как только он начнет мигать. Это делает метод fadeOut () неактуальным. Добавьте код ниже:
переопределить открытую функцию flash ($ sideways: Boolean = false): void { var snd: Sound = CustomLoader.getInstance () .getSound ('backgroundFlash'); // доступ из экземпляра CustomLoader TweenLite.to (_backgroundLayer, // target .4, // продолжительность { задержка: .4, // задержка alpha: .4, // конечное значение целевого свойства onStart: snd.play, // воспроизводить звук при запуске анимации onStartParams: [0, 0, new SoundTransform (.2)], // параметры для метода, вызываемого при запуске анимации onComplete: TweenLite.to, // метод, вызываемый, когда заканчивается анимация onCompleteParams: [_ backgroundLayer, .4, {alpha: 0}] // параметры для метода, вызываемого по завершении анимации } ); }
Переопределенный из суперкласса, параметр $ sideways является обязательным, но не имеет приложения. Модификация здесь также включает воспроизведение звукового эффекта backgroundFlash, загруженного из экземпляра CustomLoader. Это завершает класс BackgroundGlow3D. Поскольку мы не переопределяли метод fadeOut (), он все еще доступен для этого подкласса. Если вы хотите полностью отключить его, просто переопределите метод и оставьте его пустым, не передавая вызов суперклассу.
Шаг 54: этап добавления BackgroundGlow3D
Вернитесь в метод init () тестера и добавьте вызов addBackgroundGlow () чуть ниже вызова метода addBackgroundNoise (). Скопируйте приведенный ниже код после метода addBackgroundNoise ():
приватная функция addBackgroundGlow (): void { _backgroundGlow = new BackgroundGlow3D ('backgroundGlow', область просмотра); scene.addChild (_backgroundGlow); }
Затем перейдите к методам addMainMenu () и onMenuExitComplete () и добавьте следующий код:
_backgroundGlow.flash ();
Снова убедитесь, что _backgroundGlow объявлен как свойство экземпляра типа BackgroundGlow3D в верхней части класса. каждый раз, когда вызывается метод startIntro () MainMenu, также должен вызываться метод flash () для всех эффектов. Теперь запустите программу. Результат можно посмотреть здесь .
Теперь это пронизано эффектами! =) Позже мы добавим опцию для включения или выключения BackgroundNoise3D.
Сделайте перерыв и вернитесь, когда будете готовы приступить к созданию первого из двух подменю, AboutMenu3D.
Шаг 55: Добавление подменю About — AboutMenu3D
Этот DisplayObject3D будет модифицированным подклассом MainMenu3D. Он будет содержать скрытую 3D-текстовую прокрутку, 2 кнопки для прокрутки этого текста и кнопку «Назад» для возврата в главное меню. Его список обязанностей:
- создать 2 границы для использования в качестве оболочки для содержимого этого меню // так же, как суперкласс
- создать и добавить 3 кнопки и добавить слушателей для них // модифицированные из суперкласса
- подготовиться к вводной анимации // модифицировано из суперкласса
- добавить эффекты и анимацию // модифицировано из суперкласса
- добавить 3D прокрутку текста // новая ответственность
- добавить маску для 3D-прокрутки текста // новая ответственность
- обеспечить внешнее управление для воспроизведения анимации вступления и выхода // так же, как суперкласс
- управлять активацией и деактивацией кнопок // так же, как суперкласс
- отправить пользовательское событие, вызванное кнопкой возврата, чтобы UserInterface3D мог загрузить MainMenu3D назад // дополнительная ответственность
Вернитесь сюда по ссылке предварительного просмотра и нажмите кнопку «О программе», чтобы открыть это меню. Он выглядит проще, чем MainMenu3D из-за меньшего количества кнопок, но его внутренняя работа немного сложнее. Создайте новый класс и назовите его AboutMenu3D. Пусть это продлит MainMenu3D. Когда файл класса открыт, просто скопируйте и вставьте приведенный ниже код, заменив содержимое класса.
пакет { import com.greensock.TweenMax; импорт flash.display.Sprite; импорт flash.events.Event; import org.papervision3d.core.math.Number2D; import org.papervision3d.events.InteractiveScene3DEvent; import org.papervision3d.materials.ColorMaterial; import org.papervision3d.materials.special.Letter3DMaterial; import org.papervision3d.objects.primitives.Plane; import org.papervision3d.typography.Font3D; import org.papervision3d.typography.Text3D; import org.papervision3d.view.layer.ViewportLayer; import org.papervision3d.view.Viewport3D; открытый класс AboutMenu3D расширяет MainMenu3D { приватная переменная _text3D: Text3D; private var _textLayer: ViewportLayer; private var _mask: ViewportLayer; приватная переменная _scrollUp: Boolean; private var _scrollDown: Boolean; публичная функция AboutMenu3D ($ name: String, $ viewport: Viewport3D) { супер ($ name, $ viewport); } } }
Все переменные экземпляра объявлены закрытыми только потому, что мы больше не будем расширять этот класс для этого проекта. Но если вам кажется, что вам, возможно, придется расширить его позже для своих собственных проектов, смело изменяйте модификаторы соответствующим образом.
Шаг 56: Инициализация
Чтобы изменить содержимое этого меню, свойства должны быть изменены из метода init (). Добавьте код ниже после конструктора:
переопределить защищенную функцию init (): void { _buttonPosY = [-250]; // нам нужна только одна позиция 'y' для всех кнопок этого меню _buttonTitles = ['<назад', 'вверх', 'вниз']; // новый набор кнопок для использования super.init (); // вызывает метод init в Mainmenu3D, который вызывает createFrame, addButtons и setMenuEffect createMask (); // дополнительная ответственность createText (); // дополнительная ответственность }
Новые значения назначаются для унаследованных свойств, которые необходимо изменить перед вызовом метода init () суперкласса. О новых обязанностях заботятся. Далее мы переопределяем метод createFrame (), чтобы изменить внешний вид двух границ. Добавьте код ниже после метода init ():
переопределить защищенную функцию createFrame (): void { _topNav = новый UIComponent3D ( '_TopNav', _viewport, [ новый Number2D (-692, 17), новый Number2D (-632, 55), новый Number2D (632, 55), новый Number2D (692, 17), новый Number2D (692, -55), новый Number2D (653, -55), новый Number2D (613, -22), новый Number2D (207, -22), новый Number2D (164, -1), новый Number2D (-152, -1), новый Number2D (-196, -22), новый Number2D (-610, -22), новый Number2D (-644, -55), новый Number2D (-692, -55), новый Number2D (-692, 17) ] ); _topNav.fillColor = 0x0080FF; // меняем цвет на синий _bottomNav = новый UIComponent3D ( '_BottomNav', _viewport, [ новый Number2D (692, -17), новый Number2D (632, -55), новый Number2D (-632, -55), новый Number2D (-692, -17), новый Number2D (-692, 55), новый Number2D (-653, 55), новый Number2D (-613, 22), новый Number2D (-207, 22), новый Number2D (-164, 1), новый Number2D (152, 1), новый Number2D (196, 22), новый Number2D (610, 22), новый Number2D (644, 55), новый Number2D (692, 55), новый Number2D (692, -17) ] ); //_bottomNav.fillColor = 0xEE5311; // меняем цвет на оранжевый _topNav.init (); _bottomNav.init (); addChild (_topNav); addChild (_bottomNav); }
Границы нарисованы совершенно иначе, чем у суперкласса. Затем добавьте модифицированный метод addButtons ():
переопределить защищенную функцию addButtons (): void { _buttonArray = []; // назначаем новый массив для подготовки к использованию кнопка var: Button3D; // локальная переменная // рисуем координаты для upArrow var upArrow: Array = [ новый Number2D (-69, -19), новый Number2D (-54, -39), новый Number2D (0, 6), новый Number2D (54, -39), новый Number2D (69, -19), новый Number2D (2, 39), новый Number2D (-69, -19) ]; // рисуем координаты для downArrow var downArrow: Array = [ новый Number2D (69, 19), новый Number2D (54, 39), новый Number2D (0, -6), новый Number2D (-54, 39), новый Number2D (-69, 19), новый Number2D (-2, -39), новый Number2D (69, 19) ]; var argumentsArray: Array = [upArrow, downArrow]; // используем массив для простого доступа для создания кнопок для (var i: uint = 0; i <_buttonTitles.length; i ++) { if (_buttonTitles [i] == '<назад') { кнопка = новая кнопка3D (_buttonTitles [I], _viewport, [ новый Number2D (-182, -60), новый Number2D (-93, 60), новый Number2D (182, 60), новый Number2D (182, -26), новый Number2D (143, -26), новый Number2D (105, -60), новый Number2D (-182, -60) ] ); button.x = 500; button.fillColor = 0x0080FF; button.init (); button.text3D.x = -630; // расположить текст вручную в центре кнопки button.addEventListener (InteractiveScene3DEvent.OBJECT_CLICK, onButtonClick); } else // если имя / метка кнопки не равно '<back'; { button = new Button3D (_buttonTitles [i], _viewport, argumentsArray [i-1], false); button.fillColor = 0x80FF00; button.x = -75 + (i - 1) * 150; // центрируем положение «x» на 2 скроллерах button.noClick = true; // удаляем прослушиватель onButtonClick () button.init (); button.addEventListener (InteractiveScene3DEvent.OBJECT_OVER, oButtonOver); button.addEventListener (InteractiveScene3DEvent.OBJECT_OUT, oButtonOut); } button.y = _buttonPosY [0]; _buttonArray.push (кнопка); addChild (кнопка); } }
Он выглядит огромным только из-за пространства, занимаемого координатами чертежа. Все, что он делает, это добавляет 3 кнопки, размещает их и назначает соответствующих слушателей на основе названного для них имени. Смотрите комментарии для описания. Следующий метод переопределяет суперкласс и остается пустым, поэтому эффект искажения не применяется для этого меню:
переопределить защищенную функцию setMenuEffect (): void { //ничего не делать }
Это заботится обо всех унаследованных методах, запущенных из init (). Теперь о двух дополнительных функциях. Добавьте код ниже:
приватная функция createMask (): void { var материал: ColorMaterial = новый ColorMaterial (0xFFFFFF, 1); плоскость var: плоскость = новая плоскость (материал, _topNav.width, 550, 10, 10); _mask = _viewport.getChildLayer (plane); addChild (самолет); }
Метод вызывается перед createText (), чтобы сделать маску доступной и готовой. 3D-плоскость создается с той же шириной, что и границы и высотой 550. Чтобы использовать 3D-объект в качестве маски, нам нужно получить доступ к его свойству ViewportLayer. Затем добавьте метод createText ():
приватная функция createText (): void { var text: String = 'Это описывает все об игре, инструментах, использованных для ее создания, и ее цели. Также здесь вы можете разместить информацию о себе и всех, кто помогал с проектом. Вы можете добавить больше текста здесь, если вам действительно нужно. У нас есть скроллер, чтобы убедиться, что у нас достаточно места для того, что вам нужно написать. '; var материал: Letter3DMaterial = новый Letter3DMaterial (0xFFFFFF); var font3D: Font3D = новое тысячелетие; _text3D = новый Text3D (текст, font3D, материал); _textLayer = _viewport.getChildLayer (_text3D); _text3D.x = -1000; _text3D.y = 200; _text3D.z = -25; _text3D.align = 'left'; _text3D.scale = .75; _textLayer.alpha = 0; // сделать текст невидимым _textLayer.layerIndex = -1; // поместим его за кнопки addChild (_text3D); _textLayer.mask = _mask; // применить маску }
Это похоже на то, как мы создали текст для Button3D или UIComponent3D. Маскирование применяется путем назначения ViewportLayer 3D-плоскости в качестве маски для ViewportLayer Text3D.
Шаг 57: расширение унаследованной вступительной анимации
Прямо сейчас, когда вызывается startIntro (), 2 границы и 3 кнопки будут анимироваться так же, как MainMenu3D. Добавьте код ниже, чтобы добавить 3D-текст при запуске вступления:
переопределить защищенную функцию initializeButtons (): void { super.initializeButtons (); TweenMax.to (_textLayer, .2, {alpha: 1, delay: .2, overwrite: true}); }
Метод initializeButtons () вызывается, когда границы достигают своих открытых позиций. Проверьте метод startIntro () в MainMenu3D для обновления. Здесь у нас есть метод суперкласса для обработки 3 кнопок, а затем анимация трехмерного текста. Затем добавьте модифицированный метод showButtons (), вызываемый из initializeButtons () MainMenu3D:
переопределить защищенную функцию showButtons ($ button: Button3D): void { super.showButtons (кнопка $); // запускает onObjectOver кнопки через суперкласс _scrollDown = _scrollUp = false; // убедитесь, что 3D-текст не прокручивается }
Здесь мы делаем то же самое с суперклассом, чтобы убедиться, что для _scrollDown и _scrollUp установлены значения false. Мы должны были сделать это здесь, потому что другие 2 кнопки используются для прокрутки и используют слушатели onButtonOver (). Если эти слушатели будут вызваны функцией showButtons (), трехмерный текст начнет прокручиваться.
Шаг 58: Обработка событий мыши
Все обрабатывается внутри, кроме случаев, когда нажата кнопка «Назад». Добавьте код ниже:
переопределить защищенную функцию onButtonClick (e: InteractiveScene3DEvent): пусто { переключатель (e.target.name) { case '<back': dispatchEvent (новое событие (MainMenu3D.BACK_TO_MAIN)); перемена; } startExit (); }
Это информирует UserInterface3D, чтобы вернуться в главное меню. Давайте теперь добавим функцию прокрутки:
приватная функция oButtonOver (e: InteractiveScene3DEvent): пусто { переключатель (e.target.name) { case 'up': _scrollUp = true; _scrollDown = false; перемена; дело "вниз": _scrollDown = true; _scrollUp = false; перемена; } } приватная функция oButtonOut (e: InteractiveScene3DEvent): пусто { _scrollUp = _scrollDown = false; }
Эти два метода присваивают значение свойствам _scrollUp и _scrollDown, которые будут использоваться в качестве маркера при прокрутке текста. Вы увидите позже, когда мы перейдем к дополнительному методу onUpdate ().
Шаг 59: расширение наследуемой анимации выхода
Ничего особенного для метода startExit (). Мы просто делаем 3D-текст невидимым, а затем оставляем суперклассу все остальное. Метод hideButtons () переопределяется, чтобы убедиться, что для _scrollUp и _scrollDown снова установлено значение false. Если этого не сделать, трехмерный текст будет прокручиваться вниз, пока меню удалено. Добавьте код ниже:
переопределить публичную функцию startExit (): void { _textLayer.alpha = 0; super.startExit (); } переопределить защищенную функцию hideButtons ($ button: Button3D): void { super.hideButtons ($ кнопка); // запускает onObjectOver кнопки через суперкласс _scrollDown = _scrollUp = false; // убедитесь, что 3D-текст не прокручивается }
Если вы не уверены, как эти два метода взаимодействуют, вернитесь и просмотрите метод startExit () MainMenu3D.
Шаг 60: прокрутка трехмерного текста
Как и BackgroundNoise3D, визуальные изменения могут быть применены только из метода update ().
публичная функция update (): void { if (_scrollDown == true) {if (_text3D.y <700) _text3D.y + = 10; }; if (_scrollUp == true) {if (_text3D.y> 200) _text3D.y - = 10; }; }
Этот метод будет вызываться повторно из метода onRenderTick () UserInterface3D. Он постоянно проверяет значения _scrollUp и _scrollDown и корректирует положение «y» трехмерного текста. Это завершает класс AboutMenu3D.
Шаг 61: Тестирование вехи AboutMenu3D
Вернитесь к методу init () тестера и закомментируйте вызовы addBackgroundNoise и addMainMenu, затем добавьте вызов addAboutMenu () в нижней части метода. Затем добавьте код ниже метода init ():
приватная функция addAboutMenu (): void { _aboutMenu = new AboutMenu3D ('about', область просмотра); _aboutMenu.addEventListener (MainMenu3D.BACK_TO_MAIN, navigateTo); _aboutMenu.addEventListener (MainMenu3D.EXIT_COMPLETE, onMenuExitComplete); scene.addChild (_aboutMenu); _aboutMenu.startIntro (); _staticGlow.scaleX = 1,5; _backgroundGlow.scaleX = 1.5; _staticGlow.flash (); _backgroundGlow.flash (); }
Не забудьте объявить _aboutMenu как свойство экземпляра типа AboutMenu3D в верхней части класса. Как вы можете видеть, это очень похоже на реализацию MainMenu3D. На этот раз мы слушаем только MainMenu3D.BACK_TO_MAIN и масштабируем два эффекта на 1,5 процента от первоначального размера. Затем измените метод navigateTo (), как показано ниже, с комментариями:
приватная функция navigateTo (e: Event): void { _staticGlow.fadeOut (); //_backgroundNoise.fadeOut (); // закомментируем это переключатель (электронный тип) { case MainMenu3D.START_GAME_CLICKED: трассировка («загрузить игру и играть»); перемена; case MainMenu3D.SETTINGS_CLICKED: трассировка («меню настроек загрузки»); перемена; case MainMenu3D.ABOUT_CLICKED: трассировка («загрузить о меню»); перемена; case MainMenu3D.EXIT_CLICKED: трассировка («выход из приложения»); перемена; case MainMenu3D.BACK_TO_MAIN: // добавить эту новую цель перехода трассировка («загрузить MainMenu3D»); перемена; } }
Обязательно закомментируйте вызов вызова метода _backgroundNoise.fadeOut (), так как на этот раз мы его не создаем. Назначьте новую цель перехода для события MainMenu3D.BACK_TO_MAIN в нижней части оператора switch.
OnMenuExitComplete () будет действовать точно так же для AboutMenu3D, благодаря ООП, но вам также необходимо закомментировать вызов _backgroundNoise.flash () внутри него.
Наконец, зайдите в метод onRenderTick () и измените код в соответствии с комментариями, как показано ниже:
переопределить защищенную функцию onRenderTick (event: Event = null): void { var xDist: Number = mouseX - stage.stageWidth * .5; var yDist: Number = mouseY - stage.stageHeight * .5; _camPitch + = ((yDist * _rotX) - _camPitch + 90) * _easOut; _camYaw + = ((xDist * _rotY) - _camYaw + 270) * _easOut; camera.orbit (_camPitch, _camYaw); super.onRenderTick (событие); //_backgroundNoise.update (); // закомментируем это _aboutMenu.update (); // добавить этот вызов }
Теперь запустите приложение, и вы должны увидеть что-то вроде этого .
Шаг 62: Добавление подменю настроек — SettingsMenu3D
Мы дошли до нашего последнего меню. Безусловно, это меню более сложное, чем два других. Но чтобы этот класс работал, нам нужно создать 3 новых класса — CheckBox3D, RadioButton3D и ButtonGroup3D. Итак, давайте выпрыгнем и поработаем над этими компонентами. Давайте начнем с CheckBox3D. Вы увидите подробную информацию о SettingsMenu3D, когда мы перейдем к шагу 75.
Шаг 63: Создание нового типа Button3D — CheckBox3D
Перейдите по ссылке предварительного просмотра и играйте с полноэкранным флажком в меню настроек. Включите его, затем выключите снова, нажав на него. После его включения вы также можете выключить его, нажав клавишу выхода. Он несколько отличается от Button3D — он использует координаты для рисования по-разному, кнопка остается на своей оси ‘z’, когда мышь находится над ней, экземпляр будет иметь дополнительную логическую переменную для хранения значения ее текущего состояния, кнопка будет иметь дополнительные внешние элементы управления, чтобы включить или выключить ее. Его список обязанностей:
- играть звуковые эффекты для мыши и мыши. // унаследованы
- добавить интерактивную плоскость, которая будет вызывать события мыши. // унаследованы
- применять эффекты для наведения мыши, мыши и щелчка мыши. // модифицированный
- обеспечить внешнее управление для добавления и удаления слушателей событий мыши // унаследованных
- обеспечить внешнее управление для удаления слушателей щелчка мыши // наследуется
- обеспечить внешнее управление для включения или выключения кнопки // дополнительные функции
- нарисовать флажок с помощью Vectorshape3D // модифицировано из UIComponent3D
- хранить свое собственное состояние и предоставлять к нему доступ извне // новая функциональность
Создайте новый класс с именем CheckBox3D, пусть он расширяет Button3D. Замените код в этом коде ниже:
пакет { import org.papervision3d.core.math.Number2D; import org.papervision3d.events.InteractiveScene3DEvent; import org.papervision3d.materials.special.VectorShapeMaterial; import org.papervision3d.objects.special.Graphics3D; import org.papervision3d.objects.special.VectorShape3D; import org.papervision3d.view.Viewport3D; Открытый класс CheckBox3D расширяет Button3D { защищенное переменное _state: Boolean; публичная функция CheckBox3D ($ name: String, $ viewport: Viewport3D, $ координаты: массив = null, $ showText: Boolean = true) { _coordinates = $ координаты == ноль? [ новый Number2D (-25, 0), // x местоположение новый Number2D (-25, 0), // y местоположение новый Number2D (50, 0), // ширина новый Number2D (50, 0), // высота новый Number2D (10, 0), // ellipseWidth новый Number2D (10, 0) // ellipseHeight ] : $ координаты; super ($ name, $ viewport, _coordinates, $ showText); } } }
Инстанциация такая же, за исключением значений внутри переменной _coordinates. Для рисования мы будем использовать метод Graphics3D.drawRoundRect () вместо методов moveTo () и lineTo (), которые мы использовали для суперкласса. Чтобы сохранить единообразие, мы сохраним массив Number2D _coordinates и просто не будем использовать его свойство ‘y’, установив для них значение 0. Смотрите комментарии для обозначения.
Шаг 64: инициализация CheckBox3D
Как только экземпляр создан и метод init () вызван извне, запускаются следующие 3 метода. Добавьте модифицированный метод setDimensions () после конструктора:
переопределить защищенную функцию setDimensions (): void { _width = _coordinates [2] .x; // назначаем ширину _height = _coordinates [3] .x; // назначаем высоту }
Затем добавьте модифицированный метод createInterface ():
переопределить защищенную функцию createInterface ($ array: Array): void { drawButton (); // новая функциональность addInteractivePlane (); // унаследовано от Button3D }
Здесь мы полностью откажемся от вызова метода createInterface () суперкласса. Вместо этого он вызывает новый метод drawButton (), а затем возвращается к использованию метода addInteractivePlane () суперкласса. Затем добавьте модифицированный метод createText ():
переопределить защищенную функцию createText (): void { super.createText (); _text3D.x = -1000; // положение слева от флажка _text3D.z = Button3D.OUT_POSITION; _text3D.scale = .75; }
После разрешения суперклассу создавать текст, CheckBox3D вступает во владение и изменяет его местоположение и масштаб.
Шаг 65: Рисуем CheckBox
Этот метод сначала вызывается методом createInterface () и каждый раз, когда вызывается onObjectClick (). Он отображает флажок на основе текущего значения _state.
защищенная функция drawButton (): void { if (_interfaceGraphic) removeChild (_interfaceGraphic); var material: VectorShapeMaterial = new VectorShapeMaterial (); _interfaceGraphic = new VectorShape3D (материал); var g: Graphics3D = _interfaceGraphic.graphics; g.lineStyle (_lineThickness, _lineColor, _lineAlpha); var fillAlpha: Number; if (_state == true) fillAlpha = _fillAlpha; // показать или скрыть центр для включения или выключения иначе fillAlpha = 0; g.beginFill (_fillColor, fillAlpha); g.drawRoundRect (_coordinates [0] .x, _coordinates [1] .x, _coordinates [2] .x, _coordinates [3] .x, _coordinates [4] .x, _coordinates [5] .x); // рисуется по-другому g.endFill (); _interfaceLayer = _viewport.getChildLayer (_interfaceGraphic); // назначаем применить эффект мыши setLayerIndex (_interfaceLayer, _layerIndex); addChild (_interfaceGraphic); _interfaceGraphic.x = -70; // немного левее _interfaceGraphic.z = Button3D.OVER_POSITION; // сделать его всплывающим, чтобы улучшить внешний вид }
Он должен напоминать вам о методе createInterface () UIComponent3D. Смотрите комментарии для его различий.
Шаг 66: Ответ на события мыши
Для наведения мыши мы хотим, чтобы флажок все еще светился, но оставался в исходном положении. Добавьте переопределенный метод onObjectOver ():
переопределить открытую функцию onObjectOver (e: InteractiveScene3DEvent = null): void { super.onObjectOver (е); this.z = Button3D.OUT_POSITION; // не позволяйте ему приблизиться к камере }
каждый раз, когда флажок установлен, мы хотим, чтобы он включался и выключался. Добавьте следующий код:
переопределить открытую функцию onObjectClick (e: InteractiveScene3DEvent = null): void { _state =! _государство; // переключаем true или false drawButton (); // перерисовываем кнопку для отображения ее состояния dispatchEvent (новый InteractiveScene3DEvent (InteractiveScene3DEvent.OBJECT_CLICK)); // так же, как суперкласс _buttonClickSound.play (0,0, _soundTransform); // воспроизводить звук так же, как суперкласс }
Во-первых, _state устанавливается в противоположное значение; затем вызывается метод drawButton (), чтобы перерисовать флажок. Затем он отправляет событие и воспроизводит назначенный звук для нажатия кнопок. Для метода onObjectOut () не требуется никаких модификаций, поэтому мы пропустим это здесь.
Шаг 67: внешний доступ к CheckBox3D
Вот вам и дополнительная функциональность для внешнего или выключения кнопки. Метод turnOn () установит значение _state в true, затем вызовет метод drawButton ():
публичная функция turnOn (): void { _state = true; drawButton (); }
Затем добавьте соответствующий метод turnOff ():
публичная функция turnOff (): void { _state = false drawButton (); }
Эти методы помогут, когда вы используете флажок в группе. Вы увидите его применение, когда мы скоро сгруппируем переключатели.
И наконец, добавьте доступ к текущему состоянию флажка:
публичная функция получить состояние (): логическое { вернуть _state; }
Шаг 68: Milestone Testing CheckBox3D
Вернитесь к методу init () внутри класса Tester и закомментируйте вызовы методов addAboutmenu (), addBackgroundGlow () и addStaticGlow (). Еще в методе init () добавьте вызов addCheckbox () внизу. Зайдите в метод onRenderTick () и закомментируйте вызов _aboutMenu.update (). Затем добавьте новый метод ниже метода init ():
приватная функция addCheckbox (): void { var cb: CheckBox3D = новый CheckBox3D ('checkbox', область просмотра); scene.addChild (cb); cb.fillColor = 0x00FF00; // изменил цвет cb.lineAlpha = .6; // изменен, чтобы показать границы флажка cb.lineThickness = 4; // модифицировано немного толще cb.lineColor = 0xFFFFFF; // также изменил цвет cb.init (); // вызывается после установки всех графических свойств cb.addEventListener (InteractiveScene3DEvent.OBJECT_CLICK, checkboxClicked); }
Очень важно изменить значение lineAlpha, помните, по умолчанию это 0 из суперкласса UIComponent3D. Затем добавьте обратный вызов для прослушивателя checkboxClicked:
приватная функция checkboxClicked (e: InteractiveScene3DEvent): пусто { след (e.target.state); }
Мы будем использовать эту информацию для изменения полноэкранного режима позже. А пока давайте просто сделаем трассировку. Теперь запустите приложение, и вы должны увидеть что-то похожее на картинку ниже. Трассировка должна показывать значение состояния флажка при каждом нажатии флажка. Положение немного смещено, но мы исправим это, когда добавим его в качестве компонента для меню настроек.
Шаг 69: Создание RadioButton3D из CheckBox3D
Вот снова ссылка для предварительного просмотра, если вы хотите посмотреть, как работает переключатель. Зайдите в меню настроек и поиграйте с группой переключателей.
Создайте новый класс с именем RadioButton3D, сделайте так, чтобы он расширял CheckBox3D, и сохраните его. Замените содержимое нового класса на код ниже:
пакет { import org.papervision3d.core.math.Number2D; import org.papervision3d.materials.special.VectorShapeMaterial; import org.papervision3d.objects.special.Graphics3D; import org.papervision3d.objects.special.VectorShape3D; import org.papervision3d.view.Viewport3D; Открытый класс RadioButton3D расширяет CheckBox3D { публичная функция RadioButton3D ($ name: String, $ viewport: Viewport3D, $ координаты: массив = null, $ showText: Boolean = true) { _coordinates = $ координаты == ноль? [новый Number2D (0,0), новый Number2D (0,0), новый Number2D (25,0)]: $ координаты; super ($ name, $ viewport, _coordinates, $ showText); } } }
Будет только 3 визуальные модификации от CheckBox3D, поэтому список обязанностей одинаков. Во-первых, нам нужно изменить масштаб и положение текста / метки. Во-вторых, мы используем метод Graphics3D.drawCircle () вместо Graphics3D.drawRoundRect () для рисования переключателя. И третье, поскольку мы используем Graphics3D.drawCircle (), метод setDimensions () необходимо будет изменить, чтобы использовать то же значение для его свойств width и height. Добавьте код ниже для переопределенного метода setDimensions () после конструктора:
переопределить защищенную функцию setDimensions (): void { _width = _coordinates [2] .x * 2; _height = _width; }
Затем добавьте модифицированный метод drawButton ():
переопределить защищенную функцию drawButton (): void { if (_interfaceGraphic) removeChild (_interfaceGraphic); var material: VectorShapeMaterial = new VectorShapeMaterial (); _interfaceGraphic = new VectorShape3D (материал); var g: Graphics3D = _interfaceGraphic.graphics; g.lineStyle (_lineThickness, _lineColor, _lineAlpha); var fillAlpha: Number; if (_state == true) fillAlpha = _fillAlpha; иначе fillAlpha = 0; g.beginFill (_fillColor, fillAlpha); g.drawCircle (_coordinates [0] .x, _coordinates [1] .x, _coordinates [2] .x); // единственная разница g.endFill (); _interfaceLayer = _viewport.getChildLayer (_interfaceGraphic); setLayerIndex (_interfaceLayer, _layerIndex); addChild (_interfaceGraphic); _interfaceGraphic.z = Button3D.OVER_POSITION; }
Теперь добавьте модифицированный метод createText ():
переопределить защищенную функцию createText (): void { super.createText (); _text3D.x = -300; _text3D.y = -50; _text3D.scale = .5; // сделать его наполовину оригинальным }
И это завершает RadioButton3D. Слава Богу за наследство. Вы можете протестировать его, если хотите, просто измените часть, где написано новое CheckBox3D, с новым RadioButton3D внутри метода addCheckBox () в Tester, и все готово. Или вы можете подождать, пока мы не создадим ButtonGroup3D, чтобы протестировать группу радиокнопок, которые мы делаем дальше.
Шаг 70: ButtonGroup3D
Этот класс будет действовать как менеджер и контейнер для группы переключателей. Он принимает 4 обязательных параметра и 1 необязательный при создании экземпляра. Параметры: имя / метка для группы, область просмотра, массив имен кнопок и состояние по умолчанию. Последний необязательный параметр был создан для предоставления возможности выравнивания кнопок по вертикали или по горизонтали. К сожалению, из-за нехватки времени я смог применить только горизонтальное выравнивание. Я оставлю это вам, чтобы закончить с вертикальным вариантом. Ниже приведен список обязанностей.
- создать текст для использования в качестве имени и метки
- создать набор радиокнопок, которые будут работать вместе как группа
- управляйте кнопками так, чтобы только одна находилась во включенном состоянии (все остальные находятся в выключенном состоянии)
- отправлять событие STATE_CHANGED при изменении состояния группы (т. е. при включении другой кнопки)
- держать значение текущего состояния группы
- заставьте каждую кнопку светиться так же, как их суперкласс, когда меню собирается закрыться
Создайте новый класс с именем ButtonGroup3D и сделайте так, чтобы он расширял DisplayObject3D. Скопируйте код ниже, чтобы заменить весь контент внутри нового класса:
пакет { импорт flash.events.Event; import org.papervision3d.events.InteractiveScene3DEvent; import org.papervision3d.materials.special.Letter3DMaterial; import org.papervision3d.objects.DisplayObject3D; import org.papervision3d.typography.Font3D; import org.papervision3d.typography.Text3D; import org.papervision3d.view.layer.ViewportLayer; import org.papervision3d.view.Viewport3D; Открытый класс ButtonGroup3D расширяет DisplayObject3D { public static const VERTICAL: String = 'vertical'; public static const HORIZONTAL: String = 'горизонтальный'; public static const STATE_CHANGED: String = 'stateChanged'; частная переменная _buttonNames: Array; // названия кнопок для создания private var _state: String; // свойство для хранения состояния группы кнопок частный var _viewport: Viewport3D; // область просмотра, переданная из Tester или UserInterface3D приватная переменная ориентация: строка; // по умолчанию выравнивание по горизонтали private var _buttonArray: Array; // будет содержать ссылку на все кнопки, созданные для доступа private var _textLayer: ViewportLayer; // текст / метка для группы открытая функция ButtonGroup3D ($ name: String, $ viewport: Viewport3D, $ buttonNames: Array, $ defaultState: String, $ direction: String = HORIZONTAL) { супер ($ название); // передаем имя в DisplayObject3D _buttonNames = $ buttonNames; // присваиваем значение _state = $ defaultState; // присваиваем значение _viewport = $ viewport; // присваиваем значение _orientation = $ ориентация; // присваиваем значение в этом (); } } }
Опять же, как и другие классы во время создания экземпляров, параметры передаются и сохраняются, затем вызывается метод init () для подготовки содержимого компонентов.
Шаг 71: Инициализация — ButtonGroup3D
Метод init () вызывает два других метода для подготовки текста и кнопок для группы. Добавьте код ниже после метода конструктора:
приватная функция init (): void { createText (); addButtons (); }
Следующий метод для создания текста такой же, как мы сделали для других классов, только позиция и масштаб были изменены. Добавьте код ниже метода init ():
приватная функция createText (): void { var материал: Letter3DMaterial = новый Letter3DMaterial (0xDDFFFF); var font3D: Font3D = новое тысячелетие; var text3D: Text3D = новый Text3D (имя, font3D, материал); _textLayer = _viewport.getChildLayer (text3D); text3D.x = -1000; text3D.y = 510; text3D.align = 'left'; text3D.scale = .75; // сделать 3/4 размера оригинала _textLayer.layerIndex = -3; // помещаем сзади, чтобы кнопка находилась над текстом addChild (text3D); }
Следующий. добавьте метод addButtons ():
приватная функция addButtons (): void { _buttonArray = []; кнопка вар: RadioButton3D; для (var i: uint = 0; i <_buttonNames.length; i ++) { button = new RadioButton3D (_buttonNames [i], _viewport); button.fillColor = 0xFF0000; button.lineAlpha = .6; button.lineThickness = 4; button.fillAlpha = .6; button.lineColor = 0xFFFFFF; button.init (); addChild (кнопка); _buttonArray.push (кнопка); if (button.name == _state) { button.turnOn (); // визуально отражаем состояние «включено» button.deActivate (); // прекращаем прослушивать события мыши, так как она уже включена } еще { button.activate (); // добавляем прослушиватели событий мыши, чтобы их можно было включить } if (_orientation == HORIZONTAL) // здесь мы выравниваем кнопки по горизонтали { var buttonWidth: Number = button.width + 50; var buttonSpacing: Number = buttonWidth * (_buttonNames.length + 1); var positionX: Number = buttonSpacing / (_buttonNames.length); var center: Number = buttonSpacing * -.5; button.x = центр + позицияX * i; button.y = 500; } // здесь вы можете добавить функцию «вертикального» выравнивания (с помощью оператора «else») button.addEventListener (InteractiveScene3DEvent.OBJECT_CLICK, onButtonClick); // добавляем прослушиватель здесь, чтобы ButtonGroup3D узнала, когда нажата любая из его кнопок. } }
Верхняя часть цикла проходит через количество имен кнопок, сохраненных в массиве _buttonNames. Затем он устанавливает визуальные свойства каждой кнопки и добавляет их в качестве дочерних одновременно, сохраняя ссылку для каждого в _buttonArray. Средняя часть метода проверяет, соответствует ли имя кнопки назначенному состоянию по умолчанию, которое также было передано в конструкторе. Если это так, кнопка включается, а затем отключается от прослушивания событий. Если нет, кнопка остается в выключенном состоянии и активируется для прослушивания событий. Последняя часть просто выравнивает кнопки по горизонтали. Каждой кнопке назначается слушатель, который срабатывает только при активной кнопке. ButtonGroup3D обработает это внутренне перед отправкой.
Шаг 72: Управление событиями нажатия в ButtonGroup3D
Ниже приведен обратный вызов, который будет обрабатывать события нажатия для всех активных кнопок. Добавьте код после метода addButtons ():
приватная функция onButtonClick (e: InteractiveScene3DEvent): пусто { _state = e.target.name; для (var i: uint = 0; i <_buttonArray.length; i ++) { if (e.target.name! = _buttonArray [i] .name) { _buttonArray [i] .turnOff (); // визуально отражаем состояние выключения _buttonArray [i] .activate (); // начинаем слушать события мыши, чтобы снова включить } еще { _buttonArray [i] .deActivate (); } } dispatchEvent (новое событие (STATE_CHANGED)); }
Здесь состоянию для группы кнопок назначается имя активной кнопки, по которой была нажата кнопка. Затем все кнопки проходят через петлю, чтобы увидеть, была ли нажата кнопка. Если это так, он отключается от прослушивания щелчков, если кнопка не совпадает с кнопкой, которая была нажата, она отключается и снова активирует ее для событий щелчков. Когда цикл завершается, отправляется событие STATE_CHANGED, информирующее его родительский контейнер — SettingsMenu3D.
Шаг 73: Внешний доступ
Метод flash () заставит мигать все кнопки, когда меню будет закрыто. Вы увидите, как это применяется, когда мы доберемся до SettingsMenu3D. Добавьте код ниже:
публичная функция flash (): void { для каждого (var do3d: DisplayObject3D у детей) { if (do3d - Button3D) Button3D (do3d) .onObjectOver (новый InteractiveScene3DEvent (InteractiveScene3DEvent.OBJECT_OVER)); } }
И, наконец, добавьте код ниже, чтобы обеспечить доступ к текущему состоянию группы кнопок:
публичная функция get state (): String {return _state; }
Шаг 74: Milestone Testing ButtonGroup3D
Вернитесь к классу Tester внутри метода init () и закомментируйте вызов addCheckbox (), затем добавьте вызов addButtonGroup () под ним. Вставьте приведенный ниже код после метода init ():
приватная функция addButtonGroup (): void { var bg: ButtonGroup3D = new ButtonGroup3D («Пример», область просмотра, [«один», «два», «три»], «два»); bg.addEventListener (ButtonGroup3D.STATE_CHANGED, onStateChange); bg.x = 200; bg.y = -500; scene.addChild (bg); }
Прямо сейчас при текущей настройке лучше всего использовать от 3 до 5 символов для надписей кнопок. Когда создается экземпляр ButtonGroup3D, ему передается имя для группы кнопок, область просмотра, массив имен кнопок в строковом формате, которые будут использоваться в качестве имен для каждой кнопки, а также в качестве различных состояний для группы кнопок, и состояние по умолчанию, которое может быть любая из 3 строк внутри массива кнопок. После создания экземпляра необходимо прослушать пользовательское событие ButtonGroup3D.STATE_CHANGED, чтобы узнать, когда была нажата активная радиокнопка. Остальные помещают экземпляр ButtonGroup3D в центр и добавляют его в сцену. Затем добавьте обратный вызов для слушателя события onStateChange:
приватная функция onStateChange (e: Event): void { трассировка (ButtonGroup3D (e.target) .state); }
Здесь мы просто проследим, выполняет ли ButtonGroup3D то, что должно. Запустите приложение, чтобы увидеть результат.Это должно выглядеть так же , как это .
Шаг 75: Построение настроекMenu3D
Как и AboutMenu3D, этот класс также будет наследоваться от MainMenu3D. Это будет наше последнее меню, и как только мы это сделаем, мы поработаем над классом UserInterface3D, чтобы наконец собрать все воедино. Это меню позволит пользователю изменить несколько внутренних настроек флеш-плеера, добавить или удалить эффект и сохранить выбранный уровень для игры. Его список обязанностей:
- создать 2 границы для использования в качестве оболочки для содержимого // изменено
- создать и добавить кнопки и добавить слушателей для них // изменено
- подготовиться к вводной анимации // модифицировано
- добавить эффекты и анимацию // модифицировано
- обеспечить внешнее управление для воспроизведения анимации вступления и выхода // так же, как суперкласс
- управлять активацией и деактивацией кнопок // изменено
- отправлять пользовательские события, запускаемые кнопками, чтобы UserInterface3D мог применить изменения к настройкам флэш-плеера или удалить эффект. // модифицированный
- сохранить уровень игры доступным для внешнего доступа // дополнительные функции
- сохранить качество сцены, доступное для внешнего доступа // дополнительные функции
Создайте новый класс с именем SettingsMenu3D и сделайте так, чтобы он расширял MainMenu3D. Замените содержимое класса с кодом ниже:
пакет { импорт com.greensock.easing.Expo; import com.greensock.TweenMax; импорт flash.display.StageQuality; импорт flash.events.Event; импорт flash.events.MouseEvent; импорт flash.media.Sound; импорт flash.media.SoundTransform; import org.papervision3d.core.math.Number2D; import org.papervision3d.events.InteractiveScene3DEvent; import org.papervision3d.view.Viewport3D; Открытый класс SettingsMenu3D расширяет MainMenu3D { public static const LEVEL_EASY: String = 'levelEasy'; public static const LEVEL_NORMAL: String = 'levelNormal'; public static const LEVEL_HARD: String = 'levelHard'; private var _level: String = LEVEL_NORMAL; private var _quality: String = StageQuality.MEDIUM; закрытый var _gameLevel: ButtonGroup3D; private var _stageQuality: ButtonGroup3D; публичная функция SettingsMenu3D ($ name: String, $ viewport: Viewport3D) { супер ($ name, $ viewport); } } }
Если вы отметите это меню из ссылки просмотра здесь , вы увидите , что он содержит 1 флажок , который переключает режим полноэкранного, группы кнопок 2 радио , которые обрабатывают качество стадии и уровень игры, и 1 кнопку назад , чтобы вернуться в главное меню , Первые 3 свойства в верхней части объявления класса будут служить уровнями игры для нашей программы. Закрытое свойство _level будет всегда хранить 1 из этих 3 уровней и будет иметь значение по умолчанию LEVEL_NORMAL. Свойство _quality будет содержать значение качества сцены и по умолчанию будет StageQuality.MEDIUM. Последние 2 свойства будут содержать экземпляры ButtonGroup3D, 1 для качества сцены и другое для уровня игры. Конструктор должен только передать информацию суперклассу.
Шаг 76: Инициализация для SettingsMenu3D
Как только метод init () вызывается конструктором суперкласса, мы переопределяем его из SettingsMenu3D и вносим изменения в некоторые унаследованные свойства. _ButtonPosY назначается только 2 позициям «y» для кнопок, которым следует следовать, _buttonTitles назначается новый массив, содержащий новую информацию, которую необходимо создать в качестве кнопок. Затем вызывается метод init () суперкласса для продолжения процесса. Добавьте код ниже метода конструктора:
переопределить защищенную функцию init (): void { _buttonPosY = [0, 200]; _buttonTitles = ['<<', 'Fullscreen']; super.init (); }
Из метода init () суперкласса вызываются следующие 3 метода. Первым является createFrame (), который переопределяется для изменения формы и цвета границ меню. Добавьте код после метода init ():
переопределить защищенную функцию createFrame (): void { _topNav = новый UIComponent3D ( '_TopNav', _viewport, [ новый Number2D (0, 286), новый Number2D (60, 326), новый Number2D (60, 367), новый Number2D (-60, 312), новый Number2D (-60, -315), новый Number2D (60, -367), новый Number2D (60, -325), новый Number2D (0, -288), новый Number2D (0, 286) ] ); _topNav.fillColor = 0xFF8000; _bottomNav = новый UIComponent3D ( '_BottomNav', _viewport, [ новый Number2D (0, -286), новый Number2D (-60, -326), новый Number2D (-60, -367), новый Number2D (60, -312), новый Number2D (60, 315), новый Number2D (-60, 367), новый Number2D (-60, 325), новый Number2D (0, 288), новый Number2D (0, -286) ] ); _bottomNav.fillColor = 0xFF8000; _topNav.init (); _bottomNav.init (); addChild (_topNav); addChild (_bottomNav); }
Метод addButtons () был немного изменен. Я разделил метод на две части, чтобы его было легче понять. Он начинается с подготовки _buttonArray для хранения ссылок на кнопки, которые мы собираемся создать. _buttonTitles затем циклически просматривается и проверяется, соответствует ли имя ‘<<‘. Если это так, экземпляр Button3D создается и добавляется в центр меню. Его текст центрируется вручную внутри визуального представления кнопки. Если имя не соответствует «<<», вместо этого создается экземпляр CheckBox3D, который помещается в верхней части меню. Цвета экземпляра также изменяются перед вызовом метода init () кнопки. Находясь в цикле, каждой кнопке назначается прослушиватель для кликов, расположенный на оси ‘y’ на основе значения текущей итерации в _buttonPosY,сохранил ссылку в _buttonArray и добавил ее в качестве дочерних элементов SettingsMenu3D. Вторая часть добавляет 2 ButtonGroup3D для контроля качества сцены и уровня игры. У нас также есть другой слушатель, назначенный для этих групп кнопок, так как они должны обрабатываться по-разному. Добавьте полный код дальше:
переопределить защищенную функцию addButtons (): void { //первая часть _buttonArray = []; кнопка var: Button3D; для (var i: uint = 0; i <_buttonTitles.length; i ++) { if (_buttonTitles [i] == '<<') { кнопка = новая кнопка3D ( _buttonTitles [I], _viewport, [ новый Number2D (49, 113), новый Number2D (-49, 19), новый Number2D (-49, -19), новый Number2D (49, -113), новый Number2D (49, 113) ] ); button.x = 450; button.init (); button.text3D.x = -540; } еще { кнопка = новый CheckBox3D (_buttonTitles [i], _viewport); button.x = 200; button.fillColor = 0x0080FF; button.lineAlpha = .6; button.lineThickness = 4; button.lineColor = 0xEE5311; button.init (); } button.addEventListener (InteractiveScene3DEvent.OBJECT_CLICK, onButtonClick); button.y = _buttonPosY [i]; _buttonArray.push (кнопка); addChild (кнопка); } //вторая часть _gameLevel = new ButtonGroup3D ('Level', _viewport, ['easy', 'nrml', 'hard'], 'nrml'); _gameLevel.addEventListener (ButtonGroup3D.STATE_CHANGED, onStateChange); addChild (_gameLevel); _gameLevel.x = 200; _gameLevel.y = -500; _stageQuality = new ButtonGroup3D ('Quality', _viewport, ['med', 'high', 'best'], 'med'); _stageQuality.addEventListener (ButtonGroup3D.STATE_CHANGED, onStateChange); addChild (_stageQuality); _stageQuality.x = 200; _stageQuality.y = -700; }
И метод setMenuEffect (), последний метод, вызываемый init (). Мы переопределяем это здесь и не применяем никакого эффекта. Ребята, я передам это как дополнительное домашнее задание, если вы хотите использовать DistortionEffect для SettingsMenu3D. Помните, что для применения фильтра требуется массив слоев области просмотра. Добавьте код ниже:
переопределить защищенную функцию setMenuEffect (): void { //ничего не делать }
Шаг 77: Передача вступительной анимации — SettingsMenu3D
Поскольку две границы открываются в горизонтальном движении, они расположены немного иначе, чем мы сделали это для суперкласса. И _gameLevel, и _stageQuality полностью прозрачны и готовы к вводной анимации. Добавьте код ниже после метода setMenuEffect ():
переопределить защищенную функцию prepareIntro (): void { _topNav.x = -75; _bottomNav.x = 75; _topNav.interfaceLayer.alpha = _bottomNav.interfaceLayer.alpha = 0; // так же, как суперкласс для каждого (кнопка var: Button3D в _buttonArray) button.visible = false; // так же, как суперкласс // дополнительная ответственность _gameLevel.visible = false; _stageQuality.visible = false; }
Метод startIntro () отличается от суперкласса только тем, как открываются 2 границы. Здесь мы перемещаем границы ‘x’, чтобы отодвинуть их друг от друга. Добавьте следующий код:
переопределить публичную функцию startIntro (): void { prepareIntro (); var sound: Sound = CustomLoader.getInstance () .getSound ('menuExpand'); TweenMax.to (_topNav.interfaceLayer, .4, {alpha: 1, задержка: .5, onStart: sound.play, onStartParams: [0,0, новый SoundTransform (1)], перезапись: false}); TweenMax.to (_bottomNav.interfaceLayer, .4, {alpha: 1, задержка: .5, перезапись: false}); TweenMax.to (_topNav, .5, {x: -500, задержка: 0,75, легкость: Expo.easeInOut, перезапись: ложь}); TweenMax.to (_bottomNav, .5, {x: 500, задержка: .75, Easy: Expo.easeInOut, перезапись: false, onComplete: initializeButtons}); }
Метод initializeButtons () не нужно менять, поэтому мы оставляем его как есть в суперклассе.
Метод showButtons () вызывает свой супер метод, а затем вступает во владение, чтобы управлять вступлением для 2 ButtonGroup3D. Добавьте следующий код:
переопределить защищенную функцию showButtons ($ button: Button3D): void { super.showButtons (кнопка $); _gameLevel.visible = true; _stageQuality.visible = true; _gameLevel.flash (); // заставляем переключатели внутри ButtonGroup3D мигать так же, как кнопка «Назад» и флажок _stageQuality.flash (); }
Шаг 78: обработка событий мыши — SettingsMenu3D
Метод onButtonClick () будет обрабатывать щелчки для полноэкранного флажка и кнопки возврата. Он имеет ту же функциональность, что и суперкласс. Если имя нажатой кнопки «<<», оно отправляет MainMenu.BACK_TO_MAIN и запускает анимацию выхода. Если был установлен полноэкранный флажок, он отправляет InteractiveScene3DEvent.OBJECT_CLICK. Переключение в полноэкранный режим будет осуществляться через UserInterface3D, поэтому все, что мы здесь делаем, это информируем его о событии. Добавьте код ниже:
переопределить защищенную функцию onButtonClick (e: InteractiveScene3DEvent): пусто { переключатель (e.target.name) { case '<<': dispatchEvent (новое событие (MainMenu3D.BACK_TO_MAIN)); startExit (); перемена; case 'Fullscreen': dispatchEvent (новый InteractiveScene3DEvent (InteractiveScene3DEvent.OBJECT_CLICK)); перемена; } }
Метод onStateChange () будет обрабатывать щелчки для двух групп кнопок. Здесь он проверяет состояние цели события и отвечает соответственно. Затем, если имя цели — «Качество», оно передает событие вверх для использования UserInterface3D. Нам не нужно распространять событие, если оно пришло с уровня, так как оно будет проверено классом Основной документ перед загрузкой образца игрового спрайта. Поэтому мы просто проследим это здесь для тестирования. Добавьте код ниже:
приватная функция onStateChange (e: Event): void { переключатель (ButtonGroup3D (e.target) .state) { дело "легко": _level = LEVEL_EASY; перемена; case 'nrml': _level = LEVEL_NORMAL; перемена; дело "трудно": _level = LEVEL_HARD; перемена; case 'med': _quality = StageQuality.MEDIUM; перемена; case 'high': _quality = StageQuality.HIGH; перемена; дело «лучший»: _quality = StageQuality.BEST; перемена; } if (e.target.name == 'Quality') dispatchEvent (e); if (e.target.name == 'Level') trace ('игра настроена на:' + ButtonGroup3D (e.target) .state); // только для тестирования }
Шаг 79: обработка анимации выхода — SettingsMenu3D
При нажатии кнопки «Назад» вызывается метод startExit () суперкласса. Нам не нужно переопределять его здесь, поскольку он будет работать так же для SettingsMenu3D, как и для суперкласса. Как только функция startBittons () вызывается функцией hideButtons (), мы высвечиваем 2 группы кнопок, поэтому они выходят так же, как и другие кнопки, и затем становятся невидимыми. После обработки двух групп кнопок он передает вызов суперклассу, чтобы снять флажок и кнопки возврата.
переопределить защищенную функцию hideButtons ($ button: Button3D): void { _gameLevel.flash (); _stageQuality.flash (); TweenMax.delayedCall (.1, hideObject, [_gameLevel]); TweenMax.delayedCall (.1, hideObject, [_stageQuality]); super.hideButtons ($ кнопка); // обрабатывать флажок и кнопку возврата }
Метод hideObject () также просто наследуется без изменений и после завершения вызывает вызываемый здесь метод closeNav (). Опять же, он отличается от суперкласса только тем, как закрываются 2 границы. Добавьте код ниже:
переопределить защищенную функцию closeNav (): void { var sound: Sound = CustomLoader.getInstance () .getSound ('menuCollapse'); TweenMax.to (_topNav.interfaceLayer, .2, {alpha: 0, задержка: .4, перезапись: false}); TweenMax.to (_bottomNav.interfaceLayer, .2, {alpha: 0, delay: .4, перезапись: false, onComplete: dispatchEvent, onCompleteParams: [новое событие (EXIT_COMPLETE)]}); TweenMax.to (_topNav, .5, {x: -75, onStart: sound.play, ease: Expo.easeInOut, overwrite: false}); // закрываем горизонтально с позицией х TweenMax.to (_bottomNav, .5, {x: 75, ease: Expo.easeInOut, overwrite: false}); // закрываем горизонтально с позицией х }
Шаг 80: Внешний доступ — SettingsMenu3D
Вот несколько дополнительных функций для SettingsMenu3D. Добавьте код ниже:
публичная функция get gameLevel (): String { вернуть _level; } публичная функция get stageQuality (): String { вернуть _качество; } публичная функция get fullScreen (): логическое значение { return CheckBox3D (this.getChildByName ('Fullscreen')). state; }
Эти 3 метода обеспечивают внешний доступ к 3 конфигурациям, хранящимся в SettingsMenu3D. К ним будут обращаться классы Main и UserInterface3D. Затем добавьте метод exitFullScreen ():
публичная функция exitFullScreen (): void { var cb: CheckBox3D = this.getChildByName ('Fullscreen') как CheckBox3D; if (cb.state == true) cb.onObjectClick (); }
Этот метод вызывается, когда пользователь нажимает клавишу выхода, таким образом, даже если SettingsMenu3D не является активным меню, его все равно можно отключить, если пользователь решит выйти из полноэкранного режима. На следующем шаге вы увидите, как это используется, когда мы протестируем SettingsMenu3D. У нас будет класс Main document для прослушивания этого события, чтобы мы могли синхронизировать полноэкранный флажок, даже если UserInterface3D не активен на сцене.
Шаг 81: Настройки тестирования MilestoneMenu3D
Хорошо, есть довольно много модификаций, которые мы должны сделать, чтобы протестировать SettingsMenu3D. Мы будем прокладывать путь сверху. Зайдите в объявление пакета Tester по импорту и добавьте следующий код:
import flash.display.StageDisplayState;
импортировать flash.events.FullScreenEvent;
Далее перейдите к методу конструктора. Добавьте код ниже после вызова startRendering ():
addEventListener (Event.ADDED_TO_STAGE, onAddedToStage);
Это событие сообщит нам, когда сцена будет доступна для доступа. Затем, после конструктора, добавьте метод обратного вызова ниже:
приватная функция onAddedToStage (e: Event): void { removeEventListener (Event.ADDED_TO_STAGE, onAddedToStage); stage.addEventListener (FullScreenEvent.FULL_SCREEN, onFullscreen); setStageQuality (); }
Прослушиватель FullScreenEvent будет использоваться для информирования SettingsMenu3D о том, чтобы полноэкранный флажок был выключен. Метод setStageQuality () устанавливает качество сцены на основе стандартного stageQuality в SettingsMenu3D. Добавьте два метода, которые отвечают на них:
приватная функция на полном экране (e: FullScreenEvent): пусто { // если свойство события fullScreen имеет значение false, сообщить меню настроек, чтобы отключить полноэкранный флажок if (e.fullScreen == false) _settingsMenu.exitFullScreen (); } приватная функция setStageQuality (): void { stage.quality = _settingsMenu.stageQuality; }
Когда вы посмотрите на класс документа Main, вы увидите, что экземпляр Tester создается перед его добавлением на сцену. Поэтому применение изменений качества сцены сразу после создания экземпляра SettingsMenu3D не будет работать. «Сценический» объект просто еще не будет доступен. Поэтому зайдите в метод init () для Tester и раскомментируйте вызовы методов addStaticGlow () и addBackgroundGlow (). Затем закомментируйте вызов addButtonGroup () и добавьте вызов addSettingsMenu () под ним. Затем добавьте приведенный ниже код после метода init ():
приватная функция addSettingsMenu (): void { _settingsMenu = new SettingsMenu3D ('settings', viewport); _settingsMenu.addEventListener (MainMenu3D.BACK_TO_MAIN, navigateTo); _settingsMenu.addEventListener (ButtonGroup3D.STATE_CHANGED, onStateChange); _settingsMenu.addEventListener (InteractiveScene3DEvent.OBJECT_CLICK, toggleFullscreen); _settingsMenu.addEventListener (MainMenu3D.EXIT_COMPLETE, onMenuExitComplete); scene.addChild (_settingsMenu); _staticGlow.scaleX = 1,25; _backgroundGlow.scaleX = 1.25; _settingsMenu.startIntro (); _staticGlow.flash (true); _backgroundGlow.flash (); }
Убедитесь, что _settingsMenu объявлена как переменная экземпляра типа SettingsMenu3D.
У нас есть 4 разных слушателя, назначенных экземпляру SettingsMenu3D. Метод navigateTo () запускается при нажатии кнопки «<<» внутри SettingsMenu3D. Метод onStateChange () вызывается, когда группа кнопок с именем «Quality» меняет состояние и заменяет содержимое метода onStateChange (), как показано ниже. Метод toggleFullscreen () запускается всякий раз, когда устанавливается полноэкранный флажок, а метод onMenuExitComplete () запускается, когда меню завершает анимацию выхода. Мы устанавливаем scaleX для _staticGlow и _backgroundGlow в 1,25 раза больше их исходного размера, чтобы соответствовать меню. После вызова метода startIntro () мы вызываем методы flash () для _staticGlow и _backgroundGlow, передавая логическое значение true, чтобы они мигали по горизонтали.Добавьте 2 дополнительных метода обратного вызова для SettingsMenu3D ниже:
приватная функция toggleFullscreen (e: InteractiveScene3DEvent): пусто { трассировка (_settingsMenu.fullScreen); if (stage) stage.displayState = _settingsMenu.fullScreen == true? StageDisplayState.FULL_SCREEN: StageDisplayState.NORMAL; } приватная функция onStateChange (e: Event): void // этот метод уже существует, просто замените код в нем на код здесь { stage.quality = _settingsMenu.stageQuality; // заменить содержимое этим утверждением }
Нам нужно проверить, доступно ли свойство stage, прежде чем изменять его состояние отображения. Мы применяем это здесь, чтобы подготовить это, когда мы используем это для UserInterface3D. Там, если игра активна, UserInterface3D будет удален со сцены и временно потеряет свое свойство сцены. Метод onStateChange () не должен проверять этап, поскольку он может быть запущен только из SettingsMenu3D. Наконец, перейдите к методу onMenuExitComplete () и передайте значение true для вызова метода _staticGlow.flash (). Сделайте то же самое для вызова метода _staticGlow.fadeOut () внутри метода navigateTo ().
Теперь запустите программу. Вы должны получить результат, как ссылка здесь . Для тех, кто использует Flash IDE, полноэкранный режим не будет работать при запуске из Flash. Вам придется открыть SWF-файл напрямую с помощью Flash Player.
Шаг 82: Собираем все вместе
Увы, финальный класс для нашего проекта. Класс UserInterface3D — самый большой из них. Он будет наследоваться от BasicView, как и класс Tester. Думайте об этом классе как о главном контроллере, все будет обрабатываться этим классом. Вернитесь и проверьте ссылку здесь для полнофункционального предварительного просмотра. Поиграйте с ним на мгновение, чтобы почувствовать, как UserInterface3D управляет всем. Вот его список обязанностей:
- настроить сцену — т.е. установить режим сортировки на индексную сортировку, установить свойства камеры и т.д …
- создайте все меню и загрузите каждое из них соответствующим образом
- управлять всеми событиями из 3 меню и применять изменения для их обозначения — т.е. переключить полноэкранный режим, сообщить классу основного документа, чтобы загрузить игру
- обрабатывать позицию 1 большого DisplayObject3D, в котором будут размещены все 3 меню
- добавьте 3 эффекта — фоновый шум, фоновое свечение и статическое свечение и управляйте ими
- обеспечить внешнее управление для загрузки главного меню при удалении игрового спрайта
- обеспечить внешний контроль для управления полноэкранным флажком в SettingsMenu3D, когда полноэкранный режим отключен, когда игровой спрайт активен
Я разделил класс на две большие части: инициализацию и обработку событий. Создайте новый класс с именем UserInterface3D и сделайте так, чтобы он расширял BasicView. Вставьте код ниже, заменив весь код внутри нового класса:
package {import flash.display.StageDisplayState; импорт flash.display.StageQuality; импорт flash.events.Event; import flash.net.navigateToURL; import flash.net.URLRequest; импортировать flash.system.Capabilities; import flash.system.fscommand; import org.papervision3d.events.InteractiveScene3DEvent; import org.papervision3d.objects.DisplayObject3D; import org.papervision3d.view.BasicView; import org.papervision3d.view.layer.util.ViewportLayerSortMode; открытый класс UserInterface3D extends BasicView {открытый статический констант START_GAME: String = 'startGame'; // используется как пользовательское событие, отправляемое при нажатии кнопки «начать игру» из главного меню // следующие 6 свойств добавят трехмерную перспективу в активное меню private var _rotationX: Number = .05; private var _rotationY: Number = .05; приватная переменная _easeOut: Number = .1; приватная переменная _reachX: Number = .3; private var _reachY: Number = .3; private var _reachZ: Number = .9; private var _xPosArray: Array = [0, -2000, -4000]; // используется в качестве позиции 'x' для каждого меню private var _grandObject3D: DisplayObject3D; // большой контейнер DisplayObject3D для всех меню private var _backgroundNoise: BackgroundNoise3D; // экземпляр эффекта BackgroundNoise3D private var _backgroundGlow: BackgroundGlow3D; // экземпляр эффекта BackgroundGlow3D private var _staticGlow: StaticGlow3D; // экземпляр эффекта StaticGlow3D private var _mainMenu: MainMenu3D; // экземпляр закрытого файла Mainmenu3D var _settingsMenu: MainMenu3D; // экземпляр приватной переменной SettingsMenu3D _aboutMenu: MainMenu3D; // экземпляр приватной переменной AboutMenu3D _currentMenu: MainMenu3D; // будет содержать экземпляр для текущего активного меню private var _targetMenu: MainMenu3D; // будет содержать экземпляр целевого меню, которое заменит текущее меню private var _targetX: Number; // будет удерживать новую позицию 'x' _grandObject нужно будет перейти к отображению нового меню private var _targetScaleX: Number = 1; // масштаб, используемый для эффектов фонового свечения, статического свечения и фонового шума private var _closeApp: Boolean; // по умолчанию false, если true, приложение / веб-страница закроются после закрытия главного меню private var _loadGame: Boolean; // по умолчанию false, если true, пользовательское событие START_GAME отправляется и перехватывается классом Main document public function UserInterface3D () {if (stage) init (); иначе addEventListener (Event.ADDED_TO_STAGE, init); }}}
У этого класса довольно много свойств, но мы рассмотрели большинство из них в классе Tester. Смотрите комментарии для описания свойств. Конструктор настроен на запуск метода init (), только когда сцена доступна. Это позволяет избежать ошибок при попытке доступа к объекту «stage».
Шаг 83: Инициализация — Часть 1
Как только метод init () вызывается, он запускает серию методов, которые по ответственным причинам нарушают процесс инициализации. Добавьте код ниже после конструктора:
приватная функция init (e: Event = null): void { removeEventListener (Event.ADDED_TO_STAGE, init); // это нужно сделать только один раз startRendering (); // запускаем движок рендеринга PV3D, это обрабатывается суперклассом BasicView AbstractView setupScene (); // установить свойства сцены initializeEffects (); // добавить 3 эффекта initializeInterface (); // добавить 3 меню setStageQuality (); // изменить свойства сцены }
Эти методы не являются взаимозаменяемыми, вы столкнетесь с ошибками, если попытаетесь вызвать setStageQuality () перед initializeInterface (). Добавьте метод setUpScene () после метода init ():
приватная функция setupScene (): void { camera.target = DisplayObject3D.ZERO; // установить нулевую цель камеры - освободить камеру viewport.interactive = true; // включить интерактивность viewport.containerSprite.sortMode = ViewportLayerSortMode.INDEX_SORT; // исправить проблему сортировки, которую мы обсуждали в начале проекта _grandObject3D = new DisplayObject3D; // добавляем контейнер для 3 меню scene.addChild (_grandObject3D); }
Здесь вы можете применить модификации для камеры, сцены и области просмотра. Здесь мы удостоверяемся, что камера не смотрит ни на один DisplayObject3D. Для области просмотра режим сортировки и интерактивные свойства изменяются в соответствии с нашими требованиями. Здесь мы также добавляем 1 DisplayObject3D, в котором будут размещены 3 меню. Я решил сделать это, чтобы лучше контролировать 3 меню. Эффекты будут добавлены непосредственно в сцену, так как им не нужно будет перемещаться, как в меню. Затем добавьте initializeEffects () после метода setUpScene ():
приватная функция initializeEffects (): void { _backgroundNoise = new BackgroundNoise3D ('backgroundNoise', область просмотра); _backgroundNoise.z = -10; _backgroundGlow = new BackgroundGlow3D ('backgroundGlow', область просмотра); _backgroundGlow.z = 50; _staticGlow = new StaticGlow3D ('staticGlow', область просмотра); scene.addChild (_backgroundNoise); scene.addChild (_backgroundGlow); scene.addChild (_staticGlow); }
Этот метод просто добавляет 3 эффекта в сцену с небольшими различиями для их положений «z». Добавьте следующий код для метода initializeInterface () следующим образом:
приватная функция initializeInterface (): void { initMainMenu (); initSettingsMenu (); initAboutMenu (); addInteractivity (_mainMenu); // загружает главное меню в сцену }
InitializeInterface () создает экземпляры всех меню, а затем загружает экземпляр MainMenu3D в сцену. Я расскажу больше об отдельных методах, когда мы перейдем к ним. Затем добавьте метод setStageQuality () после initializeInterface ():
приватная функция setStageQuality (e: Event = null): void {stage.quality = SettingsMenu3D (_settingsMenu) .stageQuality; switch (stage.quality) {case 'HIGH': case 'MEDIUM': scene.removeChild (_backgroundNoise); перемена; case 'BEST': scene.addChild (_backgroundNoise); перемена; }}
Здесь для качества рабочей области задано стандартное качество сцены для экземпляра SettingsMenu3D. Этот метод вызывается каждый раз, когда экземпляр SettingsMenu3D отправляет событие ButtonGroup3D.STATE_CHANGED. Он также проверяет, установлено ли качество сцены на «ЛУЧШИЙ»; если это так, экземпляр BackgroundNoise () добавляется в сцену, если нет, он удаляется из сцены. Мы предоставляем пользователю возможность включить или отключить его, так как он интенсивно использует процессор.
Шаг 84: Инициализация — Часть 2
Давайте теперь перейдем к добавлению всех меню. Во-первых, initMainMenu (). Добавьте код ниже:
приватная функция initMainMenu (): void { _mainMenu = new MainMenu3D («главное меню», область просмотра); _mainMenu.addEventListener (MainMenu3D.START_GAME_CLICKED, navigateTo); _mainMenu.addEventListener (MainMenu3D.SETTINGS_CLICKED, navigateTo); _mainMenu.addEventListener (MainMenu3D.ABOUT_CLICKED, navigateTo); _mainMenu.addEventListener (MainMenu3D.EXIT_CLICKED, navigateTo); _mainMenu.x = _xPosArray [0]; }
Все так же, как мы их использовали в классе Tester, за исключением позиции «x», которую мы применяем к каждому из меню. Также обратите внимание, что мы не добавили меню в _grandObject3D. Это будет сделано, когда вызывается addInteractivity (), передавая правильное меню для загрузки. Затем добавьте метод initSettingsMenu ():
приватная функция initSettingsMenu (): void { _settingsMenu = new SettingsMenu3D («меню настроек», область просмотра); _settingsMenu.addEventListener (MainMenu3D.BACK_TO_MAIN, navigateTo); _settingsMenu.addEventListener (InteractiveScene3DEvent.OBJECT_CLICK, toggleFullscreen); _settingsMenu.addEventListener (ButtonGroup3D.STATE_CHANGED, setStageQuality) _settingsMenu.x = Math.abs (_xPosArray [1]); }
Позиция ‘x’ установлена на абсолютное значение, потому что _grandObject3D будет перемещаться в направлении истинного значения. Хорошим объяснением было бы: «если текущая позиция« x »равна 0, то есть где _mainMenu находится, и нам нужно перейти к позиции« x »_settingsMenu, равной 2000, _grandObject3D переместится на позицию« x »с -2000 центрирования _settingsMenu в сцена.» Помните, что все меню содержатся внутри _grandObject3D с разными позициями ‘x’. Затем добавьте initAboutMenu ():
приватная функция initAboutMenu (): void { _aboutMenu = новый AboutMenu3D ('about menu', область просмотра); _aboutMenu.addEventListener (MainMenu3D.BACK_TO_MAIN, navigateTo); _aboutMenu.x = Math.abs (_xPosArray [2]); // так же, как мы сделали для _settingsMenu }
После добавления всех меню поток событий возвращается к методу initializeInterface () и вызывает addInteractivity (). Добавьте код ниже:
приватная функция addInteractivity ($ menu: MainMenu3D): пусто { _currentMenu = $ menu; _grandObject3D.addChild (_currentMenu); _currentMenu.addEventListener (MainMenu3D.EXIT_COMPLETE, loadTargetMenu); _currentMenu.startIntro (); if (_currentMenu - это SettingsMenu3D) { _staticGlow.flash (true); _backgroundNoise.flash (true); } еще { _staticGlow.flash (); _backgroundNoise.flash (); } _backgroundGlow.flash (); }
Вот как _mainMenu в основном загружается на сцену. Этот метод также вызывается при каждом нажатии кнопки для изменения меню. Он работает с методом loadTargetMenu (), который обсуждается ниже в разделе обработки событий. Здесь свойству _currentMenu назначается меню, которое необходимо загрузить. _grandObject3D затем добавляет это меню как единственный дочерний элемент, чтобы сделать его доступным для сцены. Затем меню добавляется слушателем, когда оно полностью закрылось. Эта информация позволит загружать меню замены только после полного закрытия предыдущего меню. После вызова метода startIntro () он проверяет тип меню; если он имеет тип SettingsMenu3D, он сообщает _staticGlow и _backgroundNoise для анимирования по горизонтали; если тип меню — что-то еще, два эффекта будут анимированы по вертикали. И это завершает раздел инициализации.
Шаг 85: Обработка событий
С этого момента остальные функции UserInterface3D запускаются событиями. Добавьте код, который отвечает при нажатии полноэкранного флажка в _settingsMenu:
приватная функция toggleFullscreen (e: InteractiveScene3DEvent): пусто { если (этап) { stage.displayState = SettingsMenu3D (_settingsMenu) .fullScreen == true? StageDisplayState.FULL_SCREEN: StageDisplayState.NORMAL; } }
Далее, поскольку полноэкранный режим может измениться, когда пользователь нажимает клавишу escape, когда игровой спрайт активен (это означает, что экземпляр UserInterface3D был временно удален как дочерний элемент основного документа), нам нужно будет сообщить _settingsMenu, чтобы снять флажок полноэкранный флажок, когда это произойдет. Добавьте код ниже:
публичная функция exitFullScreen (): void { SettingsMenu3D (_settingsMenu) .exitFullScreen (); }
Теперь, когда экземпляр класса Main document обнаруживает, что пользователь вышел из полноэкранного режима, экземпляр SettingsMenu3D информируется. Мы добавим этот слушатель в класс основного документа, когда закончим сборку UserInterface3D. Затем добавьте неявный метод get уровня:
публичная функция get level (): String { вернуть SettingsMenu3D (_settingsMenu) .gameLevel; }
Это позволит Основному документу получить доступ к уровню, выбранному в _settingsMenu, и проинформировать об этом игровой спрайт. Затем добавьте метод navigateTo ():
защищенная функция navigateTo (e: Event): void { _backgroundNoise.fadeOut (); if (_currentMenu - это SettingsMenu3D) _staticGlow.fadeOut (true); else _staticGlow.fadeOut (); переключатель (электронный тип) { case MainMenu3D.SETTINGS_CLICKED: _targetMenu = _settingsMenu; _targetScaleX = 1,25; _targetX = _xPosArray [1]; перемена; case MainMenu3D.ABOUT_CLICKED: _targetMenu = _aboutMenu; _targetScaleX = 1,5; _targetX = _xPosArray [2]; перемена; case MainMenu3D.EXIT_CLICKED: _targetMenu = _mainMenu; _closeApp = true; // закройте браузер здесь перемена; case MainMenu3D.BACK_TO_MAIN: case MainMenu3D.START_GAME_CLICKED: if (e.type == MainMenu3D.START_GAME_CLICKED) { _loadGame = true; // загрузить игру здесь } _targetMenu = _mainMenu; _targetScaleX = 1; _targetX = _xPosArray [0]; перемена; } }
Это работает так же, как мы использовали его для класса Tester. Здесь мы используем его для масштабирования эффектов и изменения значений свойств _closeApp и _loadGame. Оба будут использоваться методом loadTargetMenu (), обсуждаемым далее. Добавьте код ниже:
публичная функция loadTargetMenu (e: Event): void { if (_closeApp == true) { var jscommand: String = "window.open ('close.html', '_ self');"; var req: URLRequest = new URLRequest ("javascript:" + jscommand + "void (0)"); if (Capabilities.playerType == 'PlugIn') navigateToURL (req, "_self"); if (Capabilities.playerType == 'StandAlone') fscommand ("quit", "true"); } if (_loadGame == true) { dispatchEvent (новое событие (START_GAME)); _loadGame = false; // установить обратно в ложь return; // нет необходимости продолжать, поэтому остановитесь здесь } _currentMenu.removeEventListener (MainMenu3D.EXIT_COMPLETE, loadTargetMenu); // удалить слушателя _grandObject3D.removeChild (_currentMenu); // удалить текущее меню, которое только что закрылось _backgroundNoise.scaleX = _backgroundGlow.scaleX = _staticGlow.scaleX = _targetScaleX; // корректно масштабируем эффекты addInteractivity (_targetMenu); // загрузить новое целевое меню, назначенное в методе navigateTo () _grandObject3D.x = _targetX; // правильно позиционировать }
Этот метод вызывается после полного выхода из текущего меню. Вот почему проигрыватель webpage / standAlone закрывается только после того, как меню исчезает, когда вы нажимаете кнопку выхода. Если значение _loadGame равно true, отправляется UserInterface3D.START_GAME, чтобы сообщить основному документу о загрузке игрового спрайта. Как только событие отправлено, _loadGame снова устанавливается в false и метод преждевременно завершается. Игра Sprite будет загружена, а UserInterface3D будет удалена со сцены. Это также метод, который основной документ будет вызывать для загрузки экземпляра UserInterface3D обратно на сцену.
Затем добавьте метод onRenderTick () ниже:
переопределить защищенную функцию onRenderTick (event: Event = null): void { _backgroundNoise.update (); // обновляем фоновый шум if (_currentMenu - это AboutMenu3D) AboutMenu3D (_currentMenu) .update (); // если _settingsMenu активен, обновите его, чтобы включить прокрутку текста var xDist: Number = mouseX - stage.stageWidth * .5; var yDist: Number = mouseY - stage.stageHeight * .5; var targetRotX: Number = (-yDist * _rotationX - _currentMenu.rotationX) * _easeOut; var targetRotY: Number = (-xDist * _rotationY - _currentMenu.rotationY) * _easeOut; _currentMenu.rotationX + = targetRotX; _currentMenu.rotationY + = targetRotY; _backgroundNoise.rotationX = _currentMenu.rotationX; _backgroundNoise.rotationY = _currentMenu.rotationY; _backgroundGlow.rotationX = _currentMenu.rotationX; _backgroundGlow.rotationY = _currentMenu.rotationY; _staticGlow.rotationX = _currentMenu.rotationX; _staticGlow.rotationY = _currentMenu.rotationY; super.onRenderTick (событие); }
То же приложение, что и в Tester. Но вместо этого камера остается на том же месте, а все остальное вращается и перемещается.
Шаг 86: Окончательные дополнения для основного класса документов
Как я уже упоминал ранее, класс документа Main будет иметь некоторую часть управления игрой Sprite и UserInterface3D. Вернитесь в класс Main и добавьте еще 3 свойства экземпляра:
частный var _sprite: Sprite; // будет использоваться как игровой спрайт приватная переменная _ui3d: UserInterface3D; // будет содержать ссылку на экземпляр UserInterface3D private var _textField: TextField; // текст внутри игрового спрайта
Затем зайдите в метод onLoad () и закомментируйте все, что связано с классом Tester, затем добавьте приведенный ниже код.
_ui3d = new UserInterface3D; _ui3d.addEventListener (UserInterface3D.START_GAME, startGame); addChild (_ui3d);
Это просто добавляет экземпляр UserInterface3D на сцену и прослушивает, когда нажимается кнопка запуска игры. Затем добавьте метод startGame ():
приватная функция startGame (e: Event): void { trace ('загрузить игровой спрайт / мувиклип здесь ...'); если (! _sprite) { _sprite = новый спрайт; _sprite.graphics.lineStyle (1); _sprite.graphics.beginFill (0x000040); _sprite.graphics.drawCircle (0, 0, 100); если (! _textField) { _textField = new TextField; _textField.mouseEnabled = false; _textField.autoSize = TextFieldAutoSize.LEFT; _textField.border = true; _textField.width = 200; _textField.height = 30; _textField.textColor = 0xFFFFFF; } _sprite.addEventListener (MouseEvent.CLICK, activMenu); _sprite.addChild (_textField); } _textField.text = 'Тип игрока:' + Capabilities.playerType + '' + 'Уровень игры:' + _ui3d.level; _textField.x = -_textField.width / 2; _textField.y = -_textField.height / 2; _sprite.x = stage.stageWidth / 2; _sprite.y = stage.stageHeight / 2; addChild (_sprite); _ui3d.stopRendering (); // нет необходимости рендериться вне сцены removeChild (_ui3d); }
Здесь мы загружаем простой спрайт, представляющий вашу игру. Текст внутри него получает информацию непосредственно из экземпляра UserInterface3D, а также показывает, загружен ли SWF-файл в плагин или в автономный проигрыватель Flash Player. Ему назначается прослушиватель щелчков, поэтому класс основного документа может снова загрузить экземпляр UserInterface3D при щелчке по этому спрайту.
Метод ниже заботится о перезагрузке UserInterface3D:
приватная функция activMenu (e: MouseEvent): void { removeChild (e.target as Sprite); // удаляем игровой спрайт addChild (_ui3d); _ui3d.startRendering (); _ui3d.loadTargetMenu (новое событие (MainMenu3D.EXIT_COMPLETE)); }
Поздравляем! Вы успешно завершили проект! Теперь запустите полнофункциональное приложение, чтобы увидеть результат.
Вывод
Как я уже говорил в своем учебнике по Atoms , Papervision3D — очень простой и мощный инструмент. Поэкспериментируйте с ним, и вы получите всевозможные интересные 3D-эффекты — от простых симуляций до сложных интерфейсов. Теперь у вас есть опыт создания GUI-фреймворка, загруженного эффектами, используя PV3D. Наряду с загрузкой исходного кода, я создал простое приложение для рисования, которое поможет вам в разработке вашего интерфейса. Это идет с короткой запиской о том, как использовать это.
Надеюсь, вам понравилось читать эту статью.
Как всегда, по любым вопросам, предложениям или проблемам, пожалуйста, оставьте примечание в разделе комментариев.
Спасибо за прочтение!