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

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

Матрица преобразования

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

Если вы обратитесь к панели Reference (Window > Reference) и посмотрите на beginGradientFill, вы увидите, что вторым типом матрицы является матрица преобразования размером 3х3.


Немного поговорим об этом, так как здесь вам должно быть далеко не все понятно. Это будет не урок линейной алгебры, а упражнение, выполнив которое вы будете иметь преставление о том, что вам нужно знать для использования этой матрицы. Разумеется, мы могли бы поговорить о единичных матрицах, перестановках и т.д., но сейчас это не обязательно.

Матрица - это прямоугольный массив чисел. Проше говоря - ящик с числами. Это специальная структура ящика, которая позволяет математическим путем выполнять разнообразные действия с числами. Но как же этот ящик с числами связан с параметрами градиента?

Если вы просто добавляете числа, вы можете не обращать внимания на третий столбец. (Конечно, если вы только добавляете числа и оставляете градиент статическим, нет никаких оснований для отказа от использования первого типа матрицы. Матрица второго типа становится нужной в том случае, если нам необходимо изменять форму и анимировать градиент, так как структура 3х3 позволяет преобразовывать матрицу с помощью операций, а следовательно и градиент.) Остальные шесть параметров относятся к сдвигу, размеру и повороту градиента.

Для преобразования существующей матрицы мы просто умножаем ее на матрицу, содержащую преобразование. Если вы никогда не видели пример умножения матриц, посмотрите на рисунок ниже.


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

К счастью кто-то облегчил нам жизнь, обеспечив нас возможностью работать с преобразованиями матриц подобным образом. Если у вас под рукой есть компакт диск Flash MX, зайдите в папку Goodies\ Macromedia\ Other Samples и найдите в ней файл transformmatrix.as. (Вы также можете скопировать его с компакт-диска этой книги.) Этот файл ActionScript содержит класс матриц для поддержки преобразований матрицы градиента. Откройте этот файл в текстовом редакторе и внимательно прочтите весь код.

Нам в помощь предоставлены методы "упрощения процесса построения матриц для перехода к функциям рисования Flash MX". Внимательно просмотрев код, вы увидите, что класс содержит матрицы изменения размеров, смещения и поворота, а также метод с именем concat, который осуществляет умножение матриц, как показано на рисунке выше.

Матрицы преобразования для нашего градиента выглядят следующим образом.

  • Смещение

  • Поворот

  • Изменение размера

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

Рассмотрим небольшой пример с использованием этих методов.

Преобразование градиента 1: блюз восхода
  1. Создайте и сохраните новый фильм. Скопируйте transformmatrix.as в ту же папку, в которой находится созданный фильм.
  2. Откройте панель Actions, выделите кадр 1 слоя по умолчанию и введите следующий код.
    #include "transformmatrix.as"
    
    this.createEmptyMovieClip("grad" , 1);
    colors = [0xDEFFFF, 0x000033]; 
    alphas = [100, 100]; 
    ratios = [0, 255];
    
    matrix = new TransformMatrix();
    
    matrix.rotate (-90); 
    matrix.scale (400, 550); 
    matrix.translate(0, 800);
    
    drawGrad = function () {
      matrix.translate(0, -5);
      this.clear();
      this.beginGradientFill("linear", colors, alphas, ratios, matrix);
      this.moveTo(0, 0);
      this.lineTo(550, 0);
      this.lineTo(550, 400);
      this.lineTo(C, 400); 
      this.endFill();
    };
    
    grad.onEnterFrame = drawGrad;

    Смысл этого кода вам уже знаком. Единственные новые строки - это преобразование матрицы. Во-первых, мы создаем новый инстанс объекта матрицы, как в файле transformmatrix.as. Поворачиваем нашу новую матрицу на -90 градусов (объект сам осуществляет перевод в радианы) и увеличиваем его до размера 400x550. Выполнение этого изменения размера на нашей исходной пустой матрице изменит ее размер для соответствия высоте и ширине нашего рабочего места по умолчанию.

    Несмотря на то, что в данном примере это может ввести в заблуждение, помните, что при выполнении операции изменения размера вы умножаете имеющийся размер на ваши новые значения, поэтому, при умножении на 2 будет удвоен текущий размер.

    Затем мы смещаем наш градиент вниз на 800 пикселей, что позволит нам постепенно смещать градиент вверх в каждом кадре, и это будет похоже на восход солнца.

  3. Запустите фильм. Откиньтесь на спинку кресла и расслабьтесь, наблюдая за тем, как темно-синяя ночь постепенно сменится днем (со скоростью 12 fps это изменение происходит плавно и медленно).

    Этот пример был небольшой и эффектный. Может быть еще интереснее.

Преобразование градиента 2: поворот
  1. Откройте новый фильм (убедитесь, что он находится в одной папке с файлом transformmatrix.as ). Откройте панель Actions и введите следующий код в кадр 1 главной точки временной шкалы.
    #include "transformmatrix.as"
    
    colors = [0XE7D2EC, 0xE7D2EC, 0xE7D2EC]; 
    alphas = [0, 100, 0]; 
    ratios = [128, 192, 255]; 
    gradType = ["radial", "linear"];
    gradNum = 0;
    
    drawGrad = function () {
      this.matrix.rotate(this.rot); 
      this.clear();
      this.beginGradientFill(gradType[gradNum], colors, alphas, ratios, this.matrix); 
      this.moveTo(-275, -200); 
      this.lineTo(275, -200); 
      this.lineTo(275, 200); 
      this.lineToi-275, 200); 
      this.endFill();
    };
    
    for (i = 1; i<5; i++)  {
      var grad = _root.createEmptyMovieClip("grad"+i, i);
      grad._x = 275;
      grad._y = 200;
      grad.matrix = new TransformMatrix();
      grad.matrix.scale(200, 400);
      grad.onEnter Frame = drawGrad;
      grad.rot = (i%2>0) ? 5 : -5; 
    }
    
    grad1.matrix.rotate(90); 
    grad2.matrix.rotate(90); 
    this.onMouseDown = function() {
      gradNum = gradNum+1>1 ? 0 : gradNum+1; 
    };
    Пример 9.4.

    Обратите внимание, что в этом коде мы перемещаем все четыре фильма в центр нашего рабочего места. Это делается потому, что метод rotate поворачивает точку регистрации нашего фильма, и нужно было получить этот эффект в центре рабочего места, а не в левом верхнем углу. Я также добавил управляющий элемент onMouseDown для переключения между линейным и радиальным градиентом. Предположите, какой эффект получится в результате работы этого кода, прежде чем вы запустите этот фильм, чтобы выяснить, насколько хорошо вы поняли принципы создания градиентов с помощью рисования API.

    Если вы незнакомы с оператором модуля (%), запомните: он возвращает остаток от деления двух операндов. Например, 5%2 вернет 1 (делим 5 на 2 и получаем остаток 1). Это быстрый способ определения четности числа. Любое четное число делится на 2 без остатка, а при делении нечетного числа будет остаток 1. Проверяя четность, можно поворачивать фильмы в различных направлениях.

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

Преобразование градиента 3: затемнение градиентов
  1. Откройте новый фильм и, как обычно, убедитесь, что он сохранен в той же папке, что и файл transformmatrix.as. Введите следующий код в кадр 1 главной точки временной шкалы.
    #include "transformmatrix.as"
    
    gradDepth = 1; 
    grads = [];
    
    makeGrad = function () {
      var grad = this.createEmptyMovieClip("grad"+gradDepth, gradDepth);
      grad._x = 275;
      grad._y = 200;
      grad._alpha = 10;
      grad.matrix = new Transf ormMatrix ();
      grad.matrix.scale(5, 10);
      grads.push(grad);
      gradDepth++;
    };
    
    colors = [0x000000, 0xFFFFFF, 0x000000, 0xFFFFFF, 0x000000]; 
    alphas = [0, 100, 0, 100, 0]; 
    ratios = [0, 64, 128, 192, 255];
    
    gradType = ["linear", "radial"];
    gradNum = 0;
    
    drawGrads = function () {
      for (var i = 0; i<grads. length; i++) { 
        var grad = grads[i]; 
        grad._alpha += 2; 
        grad.matrix.scale(1.1, 1.1); 
        grad.matrix.rotate (5); grad.clear();
        grad.beginGradientFill(gradType[gradNum], colors, alphas, ratios,grad.matrix); 
        grad.moveTo(-275, -200); 
        grad.lineTo(275, -200); 
        grad.lineTo(275, 200); 
        grad.lineTo(-275, 200); 
        grad.endFill(); 
        if (grad.matrix.b>2000) { 
          grad.removeMovieClip(); 
          grads.shift(); 
        } 
      } 
    };
    
    this.onEnterFrame = drawGrads; 
    this.onMouseDown = function() {
      gradNum = gradNum+1>1 ? 0 : gradNum+1;
    };
    setInterval(this, "makeGrad", 1000);
    Пример 9.5.

    В этом коде мы установили функцию для создания градиентов. Если вы перейдете в конец кода, вы увидите, что здесь использован setInterval для вызова этой функции каждые 1000 миллисекунд. Каждый градиент будет изначально небольшим и затемненным, затем, при каждом вызове drawGrads, он будет увеличиваться и становиться ярче. По достижении максимального размера он будет удален.

  2. Теперь сделайте фон вашего фильма черным и запустите его. Не забудьте попробовать переключение линейных/радиальных градиентов щелчком мыши!

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

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

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

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

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

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

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