Опубликован: 07.11.2006 | Доступ: свободный | Студентов: 3400 / 338 | Оценка: 3.94 / 3.71 | Длительность: 37:11:00
Лекция 2:

Представление сайта

Использование пустых фильмов

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

Управляющий элемент mouseDown настраиваем так же, как и прежде:

_root.onMouseDown = function() {
  ball_mc.slideTo(this._xmouse, this._ymouse, 4);
};

Теперь наша функция slideTo будет выглядеть почти так же, как раньше, и основным отличием является то, что прежде фильм управлял сам собой, а теперь фильм выполняет внутри себя определенные действия. Это видно из замены 'this' на 'this._parent' при доступе или изменении параметров X и Y. Наш управляющий фильм осуществляет доступ и управление параметрами своего родительского фильма, т.е. того фильма, который необходимо перемещать.

MovieClip.prototype.slideTo = function(x, y, speed) {
  // create controller movieclip
  var control_mc = this.createEmptyMоvieClip ("slideControl",this.depth++);
  control_mc.targetX = x;
  control_mc.targetY = y;
  control_mc.speed = speed;
  control_mc.onEnterFrame = function() {
    // this._parent is the movieclip we're moving
    this._parent._x += (this.targetX-this._parent._x) /this.speed;
    this._parent._y += (this.targetY-this._parent._y)/this.speed;
    if (Math.abs(this.targetX-this._parent._x)<0.2 
      && Math.abs(this.targetY-this._parent._y) <0.2) {
      this._parent._x = this.targetX;
      this._parent._y = this.targetY;
      this.removeMovieClip();
    }
  };
};

Как и в отношении функции duplicate, созданной нами ранее, мы использовали ссылку, возвращаемую функцией createEmptyMovieClip для обращения к вновь созданному movieClip. Одной из возможных "ловушек" при использовании этого метода с createEmptyMovieClip является то, что пользователь может записать фильм поверх уже имеющегося внутри. Проще говоря, это то, чего нужно остерегаться при управлении фильмом; необходимо иметь некий механизм определения того, на какой глубине находятся объекты и символы. Посредством ввода переменной глубины для каждой временной линии можно эффективно реализовать данную меру предосторожности, применяя этот способ каждый раз при создании фильма. С другой стороны, можно было бы объявить глобальную переменную глубины для всех временных линий, однако все же лучше иметь одну переменную для каждой временной линии, чтобы не терять контроль над значениями. Оставляем право выбора за вами.

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

Сохраните ваш фильм в файле issueCommand2.fla. Если вы запустите фильм на данном этапе, вы заметите, что движение будет прекращено при быстром последовательном щелчке мышью. Если выполнить команду Debug > List Variables, станет видно, что причиной этого является присутствие более чем одного инстанса slideControl в нашем фильме - все они работают с различными направлениями. Таким образом, нам нужно придумать что-то такое, с помощью чего можно будет убеждаться в присутствии в любой момент времени лишь одного инстанса этого управляющего клипа внутри нашего фильма.

Возможным решением этой проблемы является создание дубликатов slideControl каждый раз на одной и той же глубине, чтобы прежний инстанс автоматически перезаписывался новым. Однако лучше не использовать этот подход, так как он нарушает схему глубины, о которой мы только что говорили. В дополнение к этому, если мы использовали метод колебаний для обеспечения движения нашего фильма, нам совершенно не нужно будет перезаписывать любые переменные скорости внутри фильма и прерывать его движение; нам необходимо сохранение этих данных до остановки фильма.

Более разумным решением будет проверка того, имеется ли уже фильм slideControl. Если это не так, то вам нужно будет создавать его, а если он уже присутствует, то нужно будет перезаписывать переменные X и Y конечной точки и событие onEnterFrame.

Оба подхода приводят к одному и тому же результату.

MovieClip.prototype.slideTo = function(x, y, speed) {
  var control_mc
  if (this.slideControl) {
    //if slideControl already exists
    control_mc = this.slideControl;
  }
  else {
    //if slideControl doesn't exist then create it
    control_mc = this.createEmptyMovieClip 
      ("slideControl", this.depth++);
  }
  control_mc.targetX = x;
  control_mc.targetY = y;
  control_mc.speed = speed;
  control_mc.onEnterFrame = function() {
    this._parent._x += (this.targetX-this._parent._x)/this.speed;
    this._parent._y += (this.targetY-this._parent._y)/this.speed;
    if (Math.abs(this.targetX-this.__parent._x)<0.2 &&
     Math.abs(this.targetY-this._parent._y)<0.2) {
      this._parent._x = this.targetX;
      this._parent._y = this.targetY;
      this.removeMovieClip();
    }
  };
};

Сохраните файл под именем i ssueCommand3.fla и при запуске фильма обратите внимание на то, что теперь он ведет себя нужным образом.

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

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

function slideDone(mс) {
  trace("movieClip "+mc+" has finished moving");
}

Вообще говоря, когда движение фильма будет прекращаться, будет осуществляться вызов функции slideDone в _root. При вызове функции slideTo, нам нужно будет добавить два других параметра - callBackObj и callBackFunc. callBackObj является местоположением вызываемой функции (в данном случае, _root ), а callBackFunc - именем вызываемой функции, т.е., в нашем случае, функции slideDone. Итак, сначала нужно добавить в нашу функцию два дополнительных параметра:

_root.onMouseDown = function() {
  ball_mc.slideTo(this._xmouse, this._ymouse, 4,  _root, "slideDone");
};

Затем нам потребуется настроить функцию slideTo для работы с этими двумя параметрами и для хранения их в фильме slideControl (посредством добавления кода):

MovieClip.prototype.slideTo = 
 function(x, y, speed, callbackObj, callbackFunc) {
  var control_mc
  if (this.slideControl) {
    control_mc = this.slideControl;
  }
  else   {
    control_mc = 
     this.createEmptyMovieClip("slideControl", this.depth++);
  }
  control_mc.targetX = x;
  control_mc.targetY = y;
  control_mc.speed = speed;
  control_mc.callBackObj = callBackObj;
  control_mc.callBackFunc = callBackFunc;
};

Наконец, нам нужно выяснить, как вызывать _root.slideDone с использованием двух переменных callBackObj и callBackFunc. Это на самом деле очень просто и делается практически таким же образом, как осуществляется, например, доступ к значению в массиве, или динамическое создание ссылки на фильм:

this.callBackObj [this.callBackFunk] (this._parent)

Часть кода перед квадратными скобками является местоположением функции ( _root ). Содержимое в квадратных скобках осуществляет поиск значения, отвечающего данной строке (в нашем случае, slideDone ), и затем значение в скобках передается в виде параметра. Передаваемое здесь значение является обращением к фильму, который мы перемещали, т.е. this._parent, our ball_mc. Наша функция целиком выглядит примерно так:

MovieClip.prototype.slideTo = 
 function (x, y, speed, callbackObj, callbackFunc) {
  var control_mc
  if (this.slideControl) {
    control_mc = this.slideControl;
  }
  else   {
    control_mc = this.createEmptyMovieClip 
      ("slideControl", this.depth++);
  }
  control_mc.targetХ = x;
  control_mc.targetY = y;
  control_mc.speed = speed;
  control_mc.callBackObj = callBackObj;
  control_mc.callBackFunc = callBackFunc;

  control_mc.onEnterFrame = function() {
    this._parent._x += (this.targetX-this._parent._x) /this.speed;
    this._parent._y += (this.targetY-this._parent._y) /this.speed;

    if (Math.abs(this.targetX-this._parent._x)<0.2 &&
     Math. abs(this.targetY-this._parent._y)<0.2) {
      this._parent._x = this.targetX;
      this._parent._y = this.targetY;
      this.callBackObj[this.callBackFunc](this._parent);
      this.removeMovieClip();
    }
  };
};

Сохраните ваш фильм в файле issueCommand004.fla и при запуске фильма вы увидите, что в окне Output отобразится сообщение "movieClip_level0.mc has finished moving", т.е. сообщение о завершении движения фильма. Это будет происходить каждый раз при остановке фильма.

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

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

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

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

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

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

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