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

Математика и физика Flash

Основные принципы движения

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

Что только уже не было на нашем экране: и корабли, и снаряды, и мячи: В каждом случае мы просто изменяли параметры _x и/или _y фильма. Постоянно, кадр за кадром прибавляя это значение к позиции фильма, мы создавали плавное движение. Мы также рассматривали скорость по направлению (velocity). Мы знаем, что объект имеет определенную скорость speed, скажем, 10 пикселей в кадр, но в каком направлении он движется? Можно определить это направление в углах, например можно сказать, что объект движется со скоростью 15 пикселей в секунду под углом в 45 градусов.

Напомним, что во Flash 0 градусов является самой правой точкой окружности, и величина угла растет по часовой стрелке.


Возвращаясь к нашему примеру, предположим, что объект движется со скоростью 20 (мы всегда будем иметь в виду количество пикселей в кадр) и под углом -35 градусов (это те же 35 градусов, только против часовой стрелки на рисунке выше). Или же представим, что корабль "летит" со скоростью 50 под углом 180 градусов. На следующем рисунке показаны все три случая.


Линии на рисунке называются векторами. Они обозначают как направление движения, так и скорость, а следовательно, и скорость по направлению: чем длиннее линия, тем больше скорость. Это также можно считать расстоянием, которое преодолевает объект за один кадр.

Теперь давайте вернемся к первому примеру. Объект движется со скоростью 15 ppf (пикселей в кадр) под углом 45 градусов. Чтобы правильно реализовать это движение во Flash, необходимо знать, какое значение нужно прибавлять к параметрам _x и _y в каждом кадре. Другими словами, нужно знать скорости по направлениям X и Y. Чтобы определить эти скорости, нужно найти способ преобразования "скорости плюс угол" в "скорость по направлению X, скорость по направлению Y ". Как раз здесь находит применение тригонометрия. Рассмотрим следующий рисунок.


В одном кадре корабль перемещается на 15 пикселей под углом 45 градусов. Можно также сказать, что он перемещается на х пикселей по оси x (скорость по направлению X ) и на y пикселей по оси y (скорость по направлению Y ). В результате мы получили прямоугольный треугольник. На самом деле он выглядит почти так же, как и на рисунке, изображавшем движение объекта по круговой траектории. Единственная разница заключается в использовании значений для вычисления скорости по направлению, а не абсолютной скорости. Формулы для реализации этих вычислений такие же.

x_velocity = cos(angle)*speed
  y_velocity = sin(angle)*speed

Во Flash мы будем использовать velX и velY для представления скоростей X и Y. Нам также понадобится преобразовывать углы в радианы. Вот как это выглядит в ActionScript.

var angle = 45;
  var speed = 15;
  var rad = angle*Math.PI/180;
  velX = Math.cos(rad)*speed;
  velY = Math.sin(rad)*speed;

Теперь мы можем просто добавить функцию onEnterFrame для прибавления скоростей к позиции вездесущего movieClip1, и все готово.

movieclip1_mc.onEnterFrame = function() {
    this._x += velX;
    this._y += velY;
  };

Безусловно, заставить один фильм двигаться на заданной скорости по заданному направлению не является динамической задачей. Для исследования этого метода мы продолжим использование последнего созданного нами FLA, т.е. объекта, следующего за мышью (в данном случае - космический кораблик). В последнем упражнении мы использовали формулу уменьшения для обеспечения следования фильма за указателем мыши. Если бы корабль находился далеко от указателя мыши, он бы начал перемещение быстро и затем замедлялся по мере приближения к указателю. В некоторых случаях более реалистично смотрится объект, который двигается с постоянной скоростью.

Равномерная скорость

  1. Откройте файл, над которым вы работали в предыдущем упражнении. Для освежения программы в памяти приведем весь имеющийся код.
    this.onEnterFrame = function() {
        var dx = this._xmouse-movieClip1_mc._x;
        var dy = this._ymouse-movieClip1_mc._y;
        var angle = Math.atan2(dy, dx) ;
        movieClip1_mc._rotation = angle*180/Math.PI;
        movieClip1_mc._x += (_root._xmouse-movieClip1_mc._x)/10;
        movieClip1_mc._y += (_root._ymouse-movieClip1_mc._y)/10;
      };
  2. Мы оставим первые пять строк, которые обеспечивают вращение movieClip1 в нужном направлении. После этого мы просто добавим в код вычисление скоростей X и Y по углу. Они заменят последние две строки, которые перемещали фильм. Обновите код следующим образом.
    var speed = 5;
      this.onEnterFrame = function() {
        var dx = this._xmouse-movieClip1_mc._x;
        var dy = this._ymouse-movieClip1_mc._y;
        var angle = Math.atan2(dy, dx);
        movieClip1_mc._rotation = angle*180/Math.PI;
        var velX = Math.cos(angle)*speed;
        var velY = Math.sin(angle)*speed;
        movieClip1_mc._x += velX;
        movieClip1_mc._y += velY;
      };

    Обратите внимание на то, что я также объявил переменную speed для использования в вычислениях. Всегда предпочтительно сначала объявлять переменную, а затем использовать ее в вычислениях, в отличие от реализации кодом отдельного значения. Если вам нужно будет впоследствии изменить значение speed, вам не придется искать его среди различных выражений и функций.

  3. Запустив фильм, вы увидите, что он следует за указателем мыши с постоянной скоростью, независимо от того, в каком месте он находится на экране.

    Однако вы могли заметить, что фильм, достигнув указателя мыши, перемещается на несколько пикселей за него и после этого поворачивается на 180 градусов в противоположную сторону и снова начинает движение. Это происходит постоянно, поэтому стрелка указывает то в одну, то в другую сторону. Этот недостаток можно устранить с помощью обнаружения коллизий на основе расстояний. (Видите, весь пройденный материал начинает взаимодействовать!) Нам нужно просто вычислить среднее расстояние между фильмом и указателем мыши. Если оно окажется меньшим, чем определенное расстояние, движение прекратится. Это расстояние численно будет таким же, как и средняя скорость.

  4. Введите окончательный код.
    var speed = 5;
      this.onEnterFrame = function() {
        var dx = this._xmouse-movieClip1_mc._x;
        var dy = this._ymouse-movieClip1_mc._y;
        var angle = Math.atan2(dy, dx);
        movieClip1_mc._rotation = angle*180/Math.PI;
        var dist = Math.sqrt(dx*dx+dy*dy);
        if (dist>speed) {
          velX = Math.cos(angle)*speed;
          velY = Math.sin(angle)*speed;
          movieClip1_mc._x += velX;
          movieClip1_mc._y += velY;
        }
      };
  5. Запустите фильм. Если расстояние между указателем мыши и фильмом больше, чем speed, фильм будет двигаться. В противном случае он остановится и будет ожидать дальнейших действий.

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

  6. Сохраните фильм и оставьте его открытым для следующего упражнения.
Игорь Хан
Игорь Хан

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

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

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

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

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