Untitled Document

Лабораторная работа 6
Шаг 1: О Displacement Mapping
Displacement map работает таким образом, что использует цветовые значения одного изображения, на основании которых меняет позиции пикселов в другом изображении. Этот эффект часто используется, чтобы создать плавающую графическую оболочку ('wrap') вокруг объекта в пространстве. Мы собираемся использовать его здесь, чтобы искажать кнопку таким образом, чтобы она выглядела так, как будто бы она получила статические помехи.
Шаг 2: Настройка вашего файла Flash
Создайте новый файл Flash (ActionScript 3). Установки вашего мувика будут зависеть от вашей игры. Для демонстрации я установил для своего мувика размеры 500x300, черный фон, и 30 fps.
Шаг 3: Создаем Simple Button
Создайте новый символ кнопки Button на сцене (Insert > New Symbol). Создайте 4 состояния для вашей кнопки. Требуемый дизайн должен соответствовать вашей игре. Что-либо сверкающее и полупрозрачное работает очень хорошо с этим эффектом. Я использовал для себя фонт Genetrix Square, но вы можете использовать любой, чтобы ваша игра выглядела на отлично.
Дайте вашей кнопке инстанс имя 'button1'.
Шаг 4: Тестируем
Если вы сохраните и протестируете ваш мувик (Control > Test Movie), вы увидите вашу кнопку на сцене, внешний вид которой будет меняться в зависимости от курсора мыши и rollover-статусов, которые вы сконструировали.
Шаг 5: Создаем класс JitteryButton
Нам нужно добавить настраиваемую функциональность нашей кнопке. Мы усовершенствуем ее, создав новый настраиваемый класс и поместив нашу простую кнопку внутри него.
Создайте новый файл ActionScript, назовите его 'JitteryButton.as'. Сохраните этот файл в той же самой директории , что и ваш основной файл Flash. Добавим этот код, чтобы создать оболочку для нашей кнопки:
CODE
package {
import flash.display.Sprite;
import flash.display.SimpleButton;
public class JitteryButton extends Sprite {
private var myButton:SimpleButton; // содержит ссылку на нашу простую кнопку
// конструктор класса
public function JitteryButton(button:SimpleButton) {
myButton = button; // принимаем переданную кнопку на сцене
}
}
В этом коде принимается простая кнопка (simple button) и запоминается ссылка на нее. Позже мы добавим больше функциональности.
Шаг 6: Создаем класс Game
Создайте новый файл ActionScript, назовите его 'Game.as'. Он будет классом документа для нашего мувика. Сохраните его в той же директории, где ваш основной файл Flash. Этот код будет добавлять нашу настраиваемую оболочку кнопки на сцену:
CODE
package {
import flash.display.MovieClip;
import flash.display.SimpleButton;
public class Game extends MovieClip {
private var startButton:JitteryButton;
// Конструктор класса
public function Game() {
// создаем дрожащую кнопку из простой кнопки на сцене
startButton = new JitteryButton(button1);
// добавляем новую кнопку на сцену
addChild(startButton);
}
}
}
Этот код создает новый экземпляр нашего настраиваемого класса JitteryButton и передает ему кнопку на сцене ('button1').
Конечно, класс вашего документа для игры окончательно будет отличаться от того кода, что вы видите здесь. Здесь мы только концентрируемся на коде для нашей кнопки.
Вернитесь внутрь вашего файла Flash, установите класс документа 'Game'. Помните, что вы не включаете здесь расширение файла.
Шаг 7: Тестируем снова
Если вы сохраните и протестируете снова ваш мувик в этой точке, вы в точности увидите то же самое, что вы видели при тестировании на шаге 4. Единственное различие - это то, что теперь наш код настроен на возможность добавления наших настраиваемых свойств.
Шаг 8: Создаем изображение Displacement Map
Теперь мы будем создавать картинку статического узора, которую мы будем использовать для искажения графики нашей кнопки.
Откройте Photoshop и создайте новое изображение, заполненное нейтральным серым цветом (#808080). Картинка должна быть немного шире, чем ваша кнопка и выше в 3 или 4 раза. Моя кнопка размером 277x56, а моя картинка размером 310x220.
Мы начнем с нейтрального серого цвета, потому что он не даст никакого эффекта нашей картинке.
Шаг 9: Добавим шум
Теперь мы добавим немного шума к нашей картинке. Это не будет очень заметно в нашем статическом эффекте, но это даст немного дополнительного мерцания . Вы можете пропустить этот шаг, если желаете.
Сдублируйте слой фона и назовите новый слой 'Noise'. Теперь вы должны иметь два слоя, заполненных нейтральным серым. Выделите новый слой Noise и выберите Filter > Noise > Add Noise. Установите Amount= 120%, Distribution = Uniform. Отметьте Monochromatic.
Нажмите OK.
Установите для слоя 'Noise' Оpacity=10%.
Шаг 10: Добавим линии ( Lines)
Создайте новый слой и назовите его 'Lines'. Теперь используйте pencil brush в 1px, чтобы добавить несколько горизонтальных черных и серых линий к картинке.
Запомните, как эти линии будут действовать при эффекте на нашу картинку: линии, темнее чем нейтральные, будут сдвигать наше изображение в одном направлении, а линии, которые светлее, будут сдвигать ее в другом направлении.
Шаг 11: Сохраним картинку Displacement Map
Выберите File > Save for Web & Devices и сохраните вашу картинку как 8 color gif, назовите ее 'staticMap.gif'.
Шаг 12:
Вернитесь во Flash, импортируйте 'staticMap.gif' в вашу библиотеку (File > Import > Import to Library...). Откройте linkage properties, отметьте Export for ActionScript, и установите имя класса как 'StaticMap'.
Шаг 13: Создаем фильтр Displacement Map
Добавим эту функцию к нашему классу JitteryButton:
CODE
// создаем фильтр displacement map
private function createDMFilter():DisplacementMapFilter {
var mapBitmap:BitmapData = new StaticMap(0,0); // используем bitmap data из нашей картинки StaticMap
var mapPoint:Point = new Point(0, 0); // положение картинки StaticMap по отношению к нашей кнопке
var channels:uint = BitmapDataChannel.RED; // какой цвет использовать для displacement
var componentX:uint = channels;
var componentY:uint = channels;
var scaleX:Number = 5; // величина горизонтального сдвига
var scaleY:Number = 1; // величина вертикального сдвига
var mode:String = DisplacementMapFilterMode.COLOR;
var color:uint = 0;
var alpha:Number = 0;
return new DisplacementMapFilter(
mapBitmap,
mapPoint,
componentX,
componentY,
scaleX,
scaleY,
mode,
color,
alpha );
}
Эта функция просто создает фильтр Displacement Map с использованием BitmapData из нашей картинки StaticMap. Нет необходимости в такой функции, но я создал ее для ясности.
Для того, чтобы работать со всем этим, нам нужно импортировать эти классы сверху в нашем классе JitteryButton:
CODE
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.filters.DisplacementMapFilter;
import flash.filters.DisplacementMapFilterMode;
import flash.geom.Point;
Шаг 14: Применяем фильтр
Теперь мы создадим переменную, которая будет хранить фильтр. Мы применим его к кнопке, присвоив свойству 'filters' для кнопки массив, который содержит наш фильтр.
Здесь код класса JitteryButton (строки 18 и 25 новые):
CODE
package {
import flash.display.Sprite;
import flash.display.SimpleButton;
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.filters.DisplacementMapFilter;
import flash.filters.DisplacementMapFilterMode;
import flash.geom.Point;
import caurina.transitions.Tweener;
public class JitteryButton extends Sprite{
private var myButton:SimpleButton;
//создаем переменную, которая содержит displacement map filter
private var dmFilter:DisplacementMapFilter = createDMFilter();
// Конструктор класса
public function JitteryButton(button:SimpleButton) {
myButton = button;
// применим фильтр к кнопке
myButton.filters = new Array(dmFilter);
}
// создаем фильтр displacement map
private function createDMFilter():DisplacementMapFilter {
var mapBitmap:BitmapData = new StaticMap(0,0); // используем bitmap data из нашей картинки StaticMap
var mapPoint:Point = new Point(0, 0); // положение картинки StaticMap по отношению к нашей кнопке
var channels:uint = BitmapDataChannel.RED; // какой цвет использовать для displacement
var componentX:uint = channels;
var componentY:uint = channels;
var scaleX:Number = 5; // величина горизонтального сдвига
var scaleY:Number = 1; // величина вертикального сдвига
var mode:String = DisplacementMapFilterMode.COLOR;
var color:uint = 0;
var alpha:Number = 0;
return new DisplacementMapFilter(
mapBitmap,
mapPoint,
componentX,
componentY,
scaleX,
scaleY,
mode,
color,
alpha );
}
}
}
Шаг 15: Тестируем снова
Если мы сохраним и протестируем теперь файл, мы можем увидеть фильтр displacement map, примененный к нашей кнопке.
Вы можете увидеть, как горизонтальные линии, которые мы нарисовали в StaticMap, сдвигают пикселы в нашей кнопке влево и вправо. Величина сдвига зависит от темноты линий в картинке и scaleX, установленной в нашем фильтре Displacement Map Filter.
К сожалению, неанимированная статика выглядит однобоко некрасиво. Давайте это сейчас исправим...
Шаг 16: Добавляем функцию randRange
Это простая функция, которая возвращает случайное целое число внутри определенного диапазона:
CODE
// возвращает случайный номер внутри определенного диапазона (включительно)
private function randRange(min:int, max:int):int {
var randomNum:int = Math.floor(Math.random() * (max - min + 1)) + min;
return randomNum;
}
Я думаю, что это очень легко - генерировать случайные значения. С помощью рандомизации получим несколько различных значений для нашего статического эффекта, чтобы управлять им.
Добавим это к нашему классу JitteryButton
Шаг 17: Анимируем Displacement Map Filter
Существует пара способов, с помощью которых мы можем анимировать статический эффект. Первый способ - изменять величину горизонтального сдвига, примененную к нашей кнопке. Это делается посредством свойства scaleX в DisplacementMapFilter.
Мы можем также анимировать положение картинки StaticMap по отношению к нашей кнопке. Это будет гарантировать то, что одни и те же области кнопки не всегда получат сдвиг.
Чтобы анимировать эффект, мы добавим функцию, назовем ее 'displayStatic', которая будет вызываться в каждом фрейме, и будет изменять эти два свойства фильтра. Добавим эту функцию к нашему классу JitteryButton:
CODE
// вызывается в ENTER_FRAME
private function displayStatic(e:Event):void {
dmFilter.scaleX = randRange(fuzzMin, fuzzMax);
dmFilter.mapPoint = new Point(0, randRange(0, -160));
myButton.filters = new Array(dmFilter);
}
Первая строка этой функции рандомизирует величину горизонтального сдвига - получает значение между значениями переменных fuzzMin и fuzzMax. Добавим эти 2 переменные к нашему классу JitteryButton:
CODE
private var fuzzMin:int = 0;
private var fuzzMax:int = 2;
Вторая строка функции displayStatic рандомизирует координату Y StaticMap по отношению к нашей кнопке. Мы уже задали в фильтре использование нашей картинки StaticMap, таким образом мы должны только изменить положение.
Третья строка только переприсваивает фильтр для нашей кнопки.
Последнее, что нам нужно сделать для получения этой анимации - это добавить слушатель события ENTER_FRAME. Добавим эту строку в функцию конструктора класса JitteryButton:
CODE
// начинаем отображение статического эффекта
addEventListener(Event.ENTER_FRAME, displayStatic);
И не забудьте импортировать класс Event вверху в файле JitteryButton:
CODE
import flash.events.Event;
Шаг 18: Тестируем снова
Если вы сохраните и протестируете мувик сейчас, вы увидите эффект, который заставляет нашу кнопку мерцать и подпрыгивать:
Это стильно и прелестно, но мы хотим, чтобы эффект также реагировал на курсор мыши. Вперед...
Шаг 19: Настроим интенсивность эффекта
Теперь мы добавим две функции, чтобы настроить интенсивность эффекта дрожания. Мы будем вызывать эффект, а в настоящее время мы имеем низкую интенсивность Low, итак мы добавим настройки для Medium и High интенсивности. Добавим эти функции к нашему классу JitteryButton:
CODE
// увеличиваем интенсивность статики на MEDIUM
private function setStaticMedium(e:MouseEvent = null):void {
fuzzMin = 2;
fuzzMax = 6;
staticLength = randRange(8, 12);
}
// увеличиваем интенсивность статики на HIGH
private function setStaticHigh(e:MouseEvent = null):void {
fuzzMin = 12;
fuzzMax = 25;
staticLength = 12;
}
Вы можете видеть, что мы настроили интенсивность установкой значений переменных fuzzMin и fuzzMax. Таким способом наша функция displayStatic будет использовать эти новые значения, когда она устанавливает горизонтальный сдвиг фильтра.
Мы также добавим переменную по имени staticLength. Мы будем использовать ее, чтобы установить насколько долго будет длиться эффект интенсивности (число фреймов) перед тем, как вернуться к низкой интенсивности. Добавим эту переменную к нашему классу JitteryButton и модифицируем нашу функцию displayStatic таким образом:
CODE
private var staticLength:int;
// вызывается в ENTER_FRAME
private function displayStatic(e:Event):void {
dmFilter.scaleX = randRange(fuzzMin, fuzzMax);
dmFilter.mapPoint = new Point(0, randRange(0, -160));
myButton.filters = new Array(dmFilter);
staticLength--;
if(staticLength <= 0){
fuzzMin = 0;
fuzzMax = 2;
}
}
Этот новый код уменьшает переменную staticLength и вновь присваивает fuzzMin и fuzzMax значения низкой интенсивности, когда значение staticLength достигает нуля.
Шаг 20: Настроим для кнопки обработчики Rollover
Чтобы заставить нашу кнопку реагировать на курсор мыши, нам нужно добавить два слушателя мышиных событий и функции обработчиков для каждого события.
Добавляем мышиные слушатели в функции конструктора нашего класса JitteryButton:
CODE
// добавляем слушатели событий rollover для кнопки
myButton.addEventListener(MouseEvent.ROLL_OVER, onButtonRollOver);
myButton.addEventListener(MouseEvent.ROLL_OUT, onButtonRollOut);
Теперь создадим два обработчика событий, которые относятся к этим двум новым строкам. Они также пойдут в класс JitteryButton:
CODE
// вызывается на кнопку ROLL_OVER
private function onButtonRollOver(e:MouseEvent):void {
setStaticHigh();
}
// вызывается на кнопку ROLL_OUT
private function onButtonRollOut(e:MouseEvent):void {
setStaticMedium();
}
Чтобы заставить все это работать, мы должны импортировать класс MouseEvent вверху нашего файла JitteryButton:
CODE
import flash.events.MouseEvent;
Теперь, когда наша кнопка распознает событие ROLL_OVER, она будет вызывать обработчик события, который в свою очередь запускает нашу функцию setStaticHigh. Эта функция увеличивает значения fuzzMin и fuzzMax (используемые для установки горизонтального сдвига) по продолжительности, определенной переменной staticLength.
Шаг 21: Добавляем эффект Scale
Здесь мы должны остановиться. Наш эффект анимации очень хорош и реагирует на мышиные rollovers. Но я все еще чувствую, что чего-то не хватает здесь. Давайте добавим небольшой эффект масштабирования.
для этого шага, если вы еще не сделали этого. Разместите папку 'caurina' в вашу директорию проекта и импортируйте классы Tweener вверху вашего файла JitteryButton:
CODE
import caurina.transitions.Tweener;
Tweener разрешает добавить нам некоторые очень хорошие эффекты масштабирования с помощью пары строк кода. Мы можем добавить одну строку к каждому из наших обработчиков события rollover:
CODE
// вызывается на кнопку ROLL_OVER
private function onButtonRollOver(e:MouseEvent):void {
Tweener.addTween(myButton, {scaleX: 1.1, time: .5, transition: "easeOutElastic"});
setStaticHigh();
}
// вызывается на кнопку ROLL_OUT
private function onButtonRollOut(e:MouseEvent):void {
Tweener.addTween(myButton, {scaleX: 1, time: .5, transition: "easeOutElastic"});
setStaticMedium();
}
Здесь мы добавляем анимацию на обработчик rollover, которая масштабирует свойство кнопки scaleX на 110% в течение 0.5 секунд. Мы используем тип преобразования elastic, чтобы чувствовалась пружинистость. В обработчике rollout мы делаем то же самое, но в обратную сторону, масштаб возвращается к значению 100%.
Шаг 22: Добавим звук
Последнее, что нам нужно сделать для того, чтобы завершить этот эффект, это добавить какой-нибудь звук. Я создал свой звук в Garage Band. Вы можете создать свой собственный или попытаться найти звук в сети.
После того, как вы получили звук, что вам нравится, импортируйте его в вашу библиотеку и установите linkage для экспорта как 'StaticSound'.
Чтобы добавить его в наш JitteryButton, нам нужно вначале импортировать класс Sound:
CODE
import flash.media.Sound;
Затем мы инициализируем его (добавим эту строку перед функцией конструктора):
CODE
private var staticSound:Sound = new StaticSound();
Внутри обработчика rollover мы скажем, чтобы звук играл:
CODE
// вызывается на кнопку ROLL_OVER
private function onButtonRollOver(e:MouseEvent):void {
Tweener.addTween(myButton, {scaleX: 1.1, time: .5, transition: "easeOutElastic"});
setStaticHigh();
staticSound.play();
}
Теперь отлично! Протестируйте ваш мувик, и все должно работать. Если ваша кнопка или звук не работают правильно, проверьте исходные файлы, чтобы сравнить с моим окончательным классом JitteryButton .
Шаг 23: Добавим еще кнопок
При создании этого эффекта прикольно то, что создается отдельный класс, который является оболочкой нашей кнопки, и то, что мы можем многократно легко использовать это с любыми другими кнопками.
Если вы хотите добавить кнопок еще в ваше меню для игры, только создайте новую кнопку и добавьте ее на сцену. Дайте ей инстанс имя 'button2'. Затем внутри вашего класса документа (файл 'Game.as') создайте новую JitteryButton и передайте ей в качестве параметра новую кнопку. Вот как это должно выглядеть:
CODE
package {
import flash.display.MovieClip;
import flash.display.SimpleButton;
public class Game extends MovieClip {
private var startButton:JitteryButton;
private var menuButton:JitteryButton;
// Конструктор класса
public function Game() {
// создаем дрожащие кнопки из простых кнопок на сцене
startButton = new JitteryButton(button1);
addChild(startButton);
// добавить новую кнопку очень просто!
menuButton = new JitteryButton(button2);
addChild(menuButton);
}
}
}
Если вы хотите изменить вид этого эффекта, вы можете попытаться использовать различные типы изображений для вашей графики StaticMap, и поиграть с настройками значений для fuzzMin и fuzzMax.