Опубликован: 07.11.2006 | Уровень: специалист | Доступ: платный
Лекция 10:

Анимация и интерактивность Drawing API

Радиальные градиенты

При создании радиальных градиентов единственное, что нужно изменить - тип градиента "линейный" на тип "радиальный". Вот и все. Вам также понадобится учесть, что параметры x и y матрицы не соответствуют центру радиального градиента. Поэтому, чтобы расположить центр градиента в центре фигуры, вам надо будет выполнить некоторые простые математические действия. Мы создадим трансформирующийся градиент, чтобы продемонстрировать это (обратитесь к файлу radial_gradients.fla на компакт-диске). Это градиент перетаскиваемый, так как он динамически создает светлое "пятно" вокруг движущегося указателя мыши.


  1. Создайте новый фильм с именем radial_gradients.fla. Откройте панель Actions и добавьте следующий код в кадр 1 слоя по умолчанию.
    this.createEmptyMovieClip("drawObj", 0);
    drawObj._x = 270;
    drawObj._y = 200;
    drawObj.startSquare = {x:-100, y:-100};
    drawObj.squareDim = {w:200, h:200};

    Первые три строки создают и устанавливают координаты фильма. Следующие две строки создают два отдельных объекта в качестве параметров нашего нового фильма drawObj. Они содержат начальные позиции x и y нарисованного квадрата, а также его ширину и высоту. Для создания градиента нам понадобятся все четыре значения.

  2. Добавьте эти строки под предыдущим кодом.
    spotlight = {};
    spotlight.colors = [0xFFG0EC, 0x6F0061];
    spotlight.alphas = [100, 100];
    spotlight.ratios = [0, 255];
    spotlight.matrix = {matrixType:"box", x:drawObj.startSquare.x,
    Кy:drawObj.startSquare.у, w:drawObj.squareDim.w,
    Кh:drawObj. squareDim. h, 
    Кr:0};
    spotlight.setMatrix = function() {
      this.matrix.x = _root._xmouse+drawObj.startSquare.x-drawObj._x;
      this.matrix.у = _root._ymouse+drawObj.startSquare.y-drawObj._y;
    };

    Здесь мы создаем отдельный объект для хранения параметров нашего градиента. Это не обязательно, но помогает отделить типы градиентов друг от друга при использовании нескольких заливок в рисунке.

    Установка параметров здесь совершенно ясна, так как она не отличается от кода в предыдущем примере с линейным градиентом (за исключением того, что мы используем переменные для установки значений). После этого добавляется метод, который будет устанавливать центр нашего градиента на указатель мыши. Мы берем позицию мыши, вычитаем координаты фильма drawObj и прибавляем начальную позицию нарисованного квадрата. Начальная позиция градиента сместится, и его центр окажется в точности под указателем мыши.

  3. Продолжим создание градиента, добавив следующий код под предшествующим кодом.
    drawSquare = function () {
      var right = drawObj.squareDim.w/2;
      var left = -right;
      var bottom = drawObj.squareDim.h/2;
      var top = -bottom;
      drawObj.clear();
      spotlight.setMatrix();
      drawObj.moveTo(left, top);
      drawObj.lineStyle(2, 0x333333, 100);
      drawObj.beginGradientFill("radial", spotlight.colors,
      Кspotlight.alphas, spotlight.ratios, spotlight.matrix);
      drawObj.lineTo(right, top);  
      drawObj.lineTo(right, bottom); 
      drawObj.lineTo(left, bottom); 
      drawObj.endFill(); 
      updateAfterEvent(); 
    };

    Здесь представлена наша функция, которая будет перерисовывать квадрат в каждом кадре. Сначала мы удаляем нарисованный квадрат (несмотря на то, что рисование, казалось бы, происходит поверх предыдущего рисунка, это делать необходимо). Затем вызываем метод setMatrix объекта spotlight, созданный в предыдущем шаге. Он будет изменять значения матрицы перед перерисовыванием квадрата. Остаток кода - тот же код рисования, который мы использовали ранее. Единственным отличием является то, что значения устанавливаются прежними переменными. Мы также добавляем updateAfterEvent для обновления экрана каждый раз при движении мыши, и этот код выполняется заново для предотвращения эффекта мигания.

  4. Наконец, добавим код, который будет перерисовывать квадрат при каждом движении мыши. Введите эти выражения в конце всего имеющегося кода.
    drawSquare();
    drawObj.onMouseMove = drawSquare;

    Сначала вызывается функция drawSquare в начале фильма, затем мы присваиваем функцию событию mouseMove объекта drawObj. Запустите фильм, чтобы проверить это в действии.


    Имейте в виду, что это будет работать для градиента, который заполняет всю ширину квадрата. При изменении ширины (если ширина исказит градиент, она не будет равна высоте) вам также понадобится поработать с формулами setMatrix.

    Итак, один из примеров готов. Как насчет создания чего-то такого, что может пригодиться в будущих приложениях?

Динамическая цветовая палитра

Здесь мы создадим цветовую палитру градиента, которая позволит создавать и изменять градиенты. Поэкспериментируйте с готовой палитрой ( gradient_palette.swf на компакт-диске), чтобы иметь представление о том, что мы будем создавать. Настройте параметры, изменяя радиальный градиент на линейный, и попробуйте добавлять, удалять и изменять цвета в области цветов. Во время работы, учтите, что все, за исключением компонента ComboBox в правом верхнем углу, создано динамически с помощью рисования API.


А теперь - кое-что интересное! Это упражнение довольно большое, и здесь используются некоторые более сложные концепции программирования, однако оно того стоит. Если вы хотите сравнивать ваш файл с примером во время работы, вы можете в любой момент обращаться к файлу gradient_palette.fla на компакт-диске. Итак, приступим.

  1. Создайте новый фильм. Откройте панель Components, если она не открыта (Ctrl + F7) и перетащите копию компонента ComboBox на рабочее место. Теперь удалите ее. Компонент и все его ресурсы теперь сохранены в Library, как нам и нужно. Мы будем добавлять ComboBox на рабочее место динамически в этом упражнении, и это будет единственным элементом нашей палитры, созданным заранее.
  2. Создайте символ нового фильма (Ctrl+F8) с именем colorStopSymbol. Убедитесь, что при этом отображаются параметры Advanced, и выберите опцию Export for Actionscript. Flash автоматически вставит такой же Identifier, как и имя символа. Нажмите OK, чтобы принять эти параметры.

  3. Теперь выйдите из режима Symbol Editing для возврата в главную точку временной шкалы - нам не нужно ничего добавлять в наш символ, так как это все будет сделано с помощью ActionScript. Нам просто нужен фильм в Library, который можно расширить.
  4. Переименуйте слой по умолчанию в главной точке временной шкалы, присвоив ему имя actions. Откройте панель Actions и начните с добавления следующего кода в кадр 1.
    paletteWidth = 400;
    paletteHeight = 300;
    gp = this.createEmptyMovieClip("gradientPicker", 0);
    gp._x = (Stage.width-paletteWidth)/2;
    gp._y = (Stage.height-paletteHeight)/2;
    gp.lineStyle(5, 0, 100);
    gp.beginFill (0x777777, 100);
    gp.lineTo(paletteWidth, 0);
    gp.lineTo(paletteWidth, paletteHeight);
    gp.lineTo(0, paletteHeight);
    gp.endFill();

    Сначала мы устанавливаем высоту и ширину нашей палитры цветов градиента, создаем фильм, который будет содержать палитру, затем располагаем фильм по центру рабочего места посредством принятия параметров объекта Stage. Затем используем рисование API для рисования серого поля, которое будет фоном палитры. Все это должно быть вам знакомо.

  5. Введите этот код под предыдущими строками.
    gradTypes = ["linear", "radial"]; gradNum = 0;
    sorter = function (a, b) { 
      return a[0]>b [ 0];
    };
    setGrad = function () {
      colors = [];
      alphas = [];
      ratios = [];
      stops = [];
      for (var i = 0; i<well.colorStops.length; i++) {
        stops.push([well.colorStops[i] ._x, well.colorStops[i]]);
      }
      stops.sort(sorter);
      for (var i = 0; i<stops.length; i++) {
        colors.push(stops[i] [1].stopColor);
        alphas.push(100);
        ratios.push(stops[i] [1].getValue()*255);
      }
      sample.drawGrad(); 
      well.drawGrad();
    };

    Этот код может показаться немного странным, так как мы ссылаемся здесь на объекты, которые еще не были созданы. Потерпите, сейчас мы во всем разберемся. Это начало фрагмента кода, в котором происходит взаимодействие с оттенками цветов. Их в нашем фильме будет три.

    • Gradient sample (sample) в левом верхнем углу для предварительного просмотра результата работы градиента.
    • Gradient well (well) - область в центре палитры - будет содержать все цвета, с помощью которых мы комбинируем и определяем наш градиент.
    • Solid color swatch (swatch) в правом нижнем углу палитры, будет отображать цвет текущего выбранного оттенка.

    В коде выше мы сначала устанавливаем два типа градиента (линейный или радиальный) в виде строк в массиве gradTypes. Мы сделаем их доступными при установке градиента для образца градиента. dragNum просто содержит текущий индекс массива gradTypes.

    Функция sorter будет сортировать наш двумерный массив. Мы к ней еще вернемся.

    Функция setGrad выполняется для всех colorStops (небольшие треугольники под областью цвета на рисунке в начале этого упражнения) и создает значения градиентов на основании их цветов и позиций _x. Она инициализирует все массивы (colors, alphas и ratios), предназначения каждого из которых вы еще узнаете. Массив stops будет содержать позиции _x всех фильмов colorStop, а также ссылки на сами фильмы.

    Первый цикл for затем выполняется для каждого colorStop (ссылки на каждый из них находятся в массиве colorStops цветовой области well, который мы сейчас будем устанавливать) и располагает позицию _x объекта colorStop и сам объект в этом двумерном массиве stops. После настройки массива мы сортируем его содержимое с помощью функции sorter. Этот массив необходимо сортировать, так как нужно знать порядок colorStops по их текущей позиции _x. Так как порядок позиций _x не будет являться порядком создания (при каждом щелчке пользователя могут добавляться дополнительные colorStops, и они, разумеется, могут быть перемещены в любое место цветовой области), нам нужно сортировать colorStops в порядке возрастания с наименьшей позиции _x к наибольшей. Следовательно, мы можем получить их значения для нашего градиента. Для этого мы воспользуемся методом Array.sort и функцией sorter. Метод Array.sort принимает метод сравнения, с помощью которого осуществляется сортировка. Самый простой из них (и, как оказалось, наиболее полезный) тот, который будет сортировать числа в порядке значения.

    sorter = function(a, b) {
    return a > b 
    }

    Этот псевдокод будет сортировать числа в порядке возрастания (заменив символ "больше, чем" (>) на символ "меньше, чем" (<), вы реализуете сортировку в порядке убывания). a и b представляют собой два смежных значения в нашем массиве. Flash будет полностью проходить через нужный массив и "перемешивать" все значения до тех пор, пока они не будут отсортированы. Для сортировки массива с несколькими измерениями нужно просто указать в методе sorter, по какому индексу необходимо осуществлять сортировку. В нашем упражнении с палитрой мы использовали первый индекс массива, который является параметром _x объекта colorStop. Это обеспечивает успешную сортировку colorStops в порядке слева направо.

    После сортировки colorStops мы проходим через наш отсортированный массив и вставляем значения в массивы градиентов по порядку colorStops. Каждый colorStop имеет параметр stopColor, который мы помещаем в colors. Каждый цвет будет находиться в своей максимальной яркости (впоследствии вы сможете это настроить), поэтому в массив alphas просто добавляем значение 100.

    Наконец, мы вызываем метод getValue массива colorStops, который будет возвращать процентное значение того места, где объект colorStop занимает всю цветовую область. Мы умножаем это значение на 255 для получения степени (запомните, степени варьируются от 0 до 255).

    Заполнив массивы, обеспечим автоматическое заполнение области просмотра и цветовой области.

Игорь Хан
Игорь Хан

у меня аналогичная ситуация. Однако, если взять пример из приложения (ball_motion_04_click for trial.fla) то след остается. при этом заметил, что в моем проекте в поле "One item in library" виден кружок, в то время как в приложенном примере такого кружка нет.

Вопрос знатокам, что не так?

Александр Коргапольцев
Александр Коргапольцев

объект созданый мной упорно не желает оставлять след(единственное что добился, так это то что шарик резво гоняется за курсором) функция duplicateMovieClip остаётся не активной, т.е. следа от объекта не остаётся, но если я тоже самый код вбиваю в учебный файл всё работает, не могу понять где я ошибаюсь и почему в документе созданном заново, не работает код начиная от функции duplicateMovieClip? 

Тамара Ионова
Тамара Ионова
Россия, Нижний Новгород, НГПУ, 2009
Магомед Алисултанов
Магомед Алисултанов
Россия, Волгоград, лицей 2