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

Движемся дальше

Изменение размеров объекта

Метод slideTo перемещает объект из одного места в другое. Теперь мы немного изменим метод slideTo для создания метода scaleTo, который будем применять с объектом Stage для создания фоновой панели изменяемого размера, которая будет изменяться с увеличением или уменьшением фильма и находиться по центру под названием.

  1. Откройте файл stageObject3.fla и сохраните его в файле resize001.fla. Теперь нарисуйте серый квадрат размером 100х100 пикселей и преобразуйте его в фильм с центральной точкой регистрации (закрепления).
  2. Удалите новый фильм с рабочего места, но перетащите его инстанс на новый слой с именем background panel, который размещается под слоем, содержащим заголовок "center stage".
  3. С помощью Property inspector назовите инстанс фильма именем bg и измените его размер так, чтобы он был размером 500 пикселей в ширину и 350 в высоту. С помощью панели Align расположите фильм по центру по горизонтали и по вертикали, нажав соответствующие кнопки при выделенной кнопке To Stage. Ваше рабочее место и временная диаграмма будут выглядеть так.

  4. Создадим код, который будет сохранять постоянное расстояние от фильма до края в 25 пикселей, независимо от размера фильма. Прежде всего, нужно изменить размер. Добавьте в фильм приемник под другими приемниками.
    Stage.addListener(bg);
  5. Затем добавьте в фильм приемник onResize под другими приемниками onResize. После этого сохраните фильм и запустите его.
    bg.onResize = function() {
            this._xscale = Stage.width-50;
            this._yscale = Stage.height-50;
        };

Анимация изменения размеров

Все работает корректно. Уголки скользят на свои места, и было бы неплохо, чтобы фон так же постепенно изменял размер. Мы реализуем это в нашем следующем шаге. Сохраните фильм в файле resize002.fla.

  1. Создадим метод scaleTo, заменив _xscale и _yscale на _x и _y в методе slideTo. Введите следующий код под функцией slideTo.
    MovieClip.prototype.scaleTo = function
        (xsc, ysc, speed,callbackObj, callbackFunc) {
          var noo;
          if (this.scaleControl) {
              noo = this.scaleControl;
          } else {
              noo = this.createEmptyMovieClip
               ("scaleControl", this. depth++);
          }
          noo.txsc = xsc;
          noo.tysc = ysc;
          noo.speed = speed;
          noo.callBackObj = callBackObj;
          noo.calIBackFunc = callBackFunc;
          noo.onEnterFrame = function() {
              this._parent._xscale += 
               (this.txsc-this._parent._xscale)/this, speed;
              this._parent._yscale += 
                (this.tysc-this._parent._yscale)/this .speed;
              if (Math.abs(this.txsc-this._parent._xscale)<0.2 &&
              КMath.abs(this.tysc-this._parent._yscale)<0.2) {
              this._parent._xscale = this.tx;
              this._parent._yscale = this.ty;
              //execute callback (not used yet)
              this.callBackObj [this.callBackFunc](this._parent);
              this.removeMovieClip();
              }
          };
      };
  2. Эта конструкция работает так же, как и slideTo, но размер объекта может изменяться. Теперь мы просто изменим функцию onResize для вызова этого метода, с передачей ей конечных значений.
    bg.onResize = function() {
            var xsc = Stage.width-50;
            var ysc = Stage.height-50;
            this.scaleTo(xsc, ysc, 5);
        };
  3. При проверке в браузере вы увидите, что серый фон постепенно изменяет размер во время увеличения или уменьшения окна браузера.

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

Использование простого метода изменения параметров

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

var obj = {_x:50, _y:100};
    this.tweenTo (obj, 5);

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

  1. Замените предыдущие функции slideTo и scaleTo следующим кодом.
    MovieClip.prototype.tweenTo = function(targetsObj, speed,
    КcallbackObj, callbackFunc) {
    var noo;
        if (this.tweenControl) {
            noo = this.tweenControl;
         }   else   {
        noo = this.createEmptyMovieClip("tweenControl", this.depth++);
        }
        // store the object containing target properties and values
        noo.targetsObj = targetsObj;
         noo.speed = speed;
         noo.callBackObj = callBackObj;
         noo.callBackFunc = callBackFunc;
         noo.onEnterFrame = function() {
         var count;
         // as its an object we can't check length.
         }
    }
  2. Затем нужно настроить цикл на прохождение и изменение всех значений. Для итерации через значения в объекте мы используем цикл for:in следующим образом.
    for (var prop in this.targetsObj) {
            this._parent[prop]+=(this.targetsObj 
             [prop]this._parent[prop] )/this, speed;
        }

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

  3. Если фильм достиг конечного параметра, нужно переключить его на этот конечный параметр и затем удалить его из объекта targets. Новый код выделен жирным шрифтом.
    for (var prop in this.targetsObj) {
            this._parent[prop] += (this.targetsObj 
             [prop] this ._parent[prop]) /this.speed;
            // if property has reached target value
            if (Math.abs(this.targetsObj[prop]- 
             this._parent[prop])<0.4) {
                this._parent[prop] = this.targetsObj[prop];
                delete this.targetsObj[prop];
            }
        }
  4. Добавим проверку того, является ли объект targets пустым. В отличие от объекта массива, объект класса не имеет параметра длины, поэтому нам нужно знать, сколько параметров пройдено циклом. Так как параметр каждого фильма достигает соответствующего конечного параметра, конечный параметр удаляется из targetsObj. Когда все параметры фильма достигают конечных параметров, в targetsObj не останется параметров, и значением count будет ноль вследствие отсутствия параметров для обработки циклом. Когда count равен нулю, мы можем уничтожить управляющий фильм и вызвать функцию обратной связи.
    MovieClip.prototype.tweenTo = function
           (targetsObj, speed, callbackObj, calIbackFunc) {
            var noo;
            if (this.tweenControl) {
                noo = this.tweenControl;
            } else {
                noo = this.createEmptyMovieClip
                 ("tweenControl", this.depth++);
            }
            noo.targetsObj = targetsObj;
            noo.speed = speed;
            noo.callBackObj = callBackObj;
            noo.callBackFunc = callBackFunc;
            noo.onEnterFrame = function() {
                var count;
                // as it's an object we can't check length.
                for (var prop in this. targetsObj) {
                    this._parent[prop] += (this.targetsObj[prop] -
                    Кthis._parent [prop]) /this.speed;
                    if (Math.abs (this.targetsObj 
                      [prop] this._parent [prop])<0.4) {
                        this._parent[prop] = this.targetsObj[prop];
                        delete this.targetsObj[prop];
                    }
                    count++;
                }
            if (!count) {
                this.callBackObj[this.calIBackFunc](this._parent);
                this.removeMovieClip();
                }
            };
        };
    Пример 5.5.
  5. Для применения этого метода управления движением нужно изменить приемники onResize. Вот один из них для правого угла, влияющий на _x и _y.
    br.onResize = function() {
            // define targets
            var obj = (_x:Stage.right-this._width, 
               _y:Stage.bottom this ._height};
            this.tweenTo(obj, 5);
        };
            :а вот фоновый приемник, влияющий на 
              значения _xscale и _yscale.
        bg.onResize = function() {
            var obj = (_xscale:Stage.width-50, _yscale:Stage.height-50};
            this.tweenTo(obj, 5);
        };

    Ниже приведен целиком код, в котором также были изменены функции onResize.

    fscommand("allowscale", "false");
        Stage.scaleMode="showAll";
        Stage.originalWidth = Stage.Width;
        Stage.originalHeight = Stage.Height;
        Stage.scaleMode="noScale";
        Stage.onResize = function() {
            this.left = this.getLeft();
            this.top = this.getTop();
            this.right = this.getRight();
            this.bottom = this.getBottom();
        };
        Stage.getLeft = function() {
            return -1*(this.width-this.originalWidth)/2;
        };
        Stage.getTop = function() {
            return -1* (this.height-this.originalHeight)/2;
        };
        Stage.getRight = function() {
            return this.left+this.width;
        };
        Stage.getBottom = function() {
            return this.top+this.height;
        };
        Stage.addListener(Stage);
        Stage.addListener(tl);
        Stage.addListener(tr);
        Stage.addListener(bl);
        Stage.addListener(br);
        Stage.addListener(bg);
        MovieClip.prototype.tweenTo = function(targetsObj, speed, callbackObj, callbackFunc) {
            var noo;
            if (this.tweenControl) {
                noo = this.tweenControl;
            } else {
                noo = this.createEmptyMovieClip("tweenControl",this.depth++);
            }
            noo.targetsObj = targetsObj;
            noo.speed = speed;
            noo.callBackObj = callBackObj;
            noo.callBackFunc = callBackFunc;
            noo.onEnterFrame = function() {
                var count;
                // as its an object we can't check length,
                for (var prop in this.targetsObj) {
                    this._parent[prop] += (this.targetsObj[prop]- this._parent [prop] ) /
                    Кthis. speed;
                    if (Math.abs(this.targetsObj [prop]- this._parent[prop])<0.4) {
                            this._parent [prop] = this.targetsObj[prop];
                            delete this.targetsObj [prop];
                    }
                    count++;
                }
                if (! count) {
                    this.callBackObj [this.callBackFunc](this._parent);
                    this.removeMovieClip();
                }
            };
        };
        tl.onResize = function() {
            var obj = (_x:Stage.left, _y:Stage.top};
            this.tweenTo(obj, 5);
        };
        tr.onResize = function() {
            var obj = (_x:Stage.right-this._width, _y:Stage.top};
            this.tweenTo(obj, 5);
        };
        bl.onResize = function() {
            var obj = (_x:Stage.left, _y:Stage.bottom-this._height};
            this.tweenTo(ob j, 5);
        };
        br.onResize = function() {
            var obj = (_x:Stage.right-this._width, _y:Stage.bottom thi s._height};
            this.tweenTo(obj, 5);
        };
        bg.onResize = function() {
            var obj = (_xscale:Stage.width-50, _yscale:Stage.height-50};
            thi s.tweenTo(obj, 5);
        };
    Пример 5.6.
  6. Сохраните фильм в файле resize003.fla и запустите его. Он работает точно так же, как и в предыдущем файле, но его код более компактен.

    Можно сделать еще больше - например, поставить интенсивность фона в зависимость от размера рабочего места.

    bg.onResize = function() {
            var obj = {_alpha:100*
              (Stage.Width/Stage.originalWidth),
            К_xscale:Stage.width-50, _yscale:Stage.height-50};
            this.tweenTo(obj, 5);
        };

    Эффект будет лучше заметен, если изменять цвет квадрата в фильме с серого на красный или синий. Если вы сделаете рабочее место совсем небольшим, фон практически полностью исчезнет (resize004.fla).

    Нужно иметь в виду, что вместо создания tweenTo в виде метода объекта MovieClip можно было бы создать отдельный класс tween, унаследовав его из класса MovieClip. Это удобно, если большое количество фильмов требует доступ к этим методам. Реализовать это можно так.

    function tweenable() {
        }
        tweenable.prototype = new Movieclip();
        Object.registerClass("tweenableMc", tweenable);
        tweenable.tweenTo = function() {
            var noo;
            if (this.tweenControl) {
                noo = this.tweenControl;
            } else {
                noo = this.createEmptyMovieClip("tweenControl", this.depth++);
            }
            noo.targetsObj = targetsObj;
            noo.speed = speed;
            noo.callBackObj = callBackObj;
            noo.callBackFunc = callBackFunc;
            noo.onEnter Frame = function() {
                var count;
                // as it's an object we can't check length,
                for (var prop in this.targetsObj) {
                    this._parent [prop] += (this.targetsObj [prop]
                    Кthis._parent [prop] ) /this. speed;
                    if (Math.abs (this.targetsObj [prop] this._parent [prop] ) <0.4) {
                        this._parent[prop] = this.targetsObj [prop];
                        delete this.targetsObj [prop];
                    }
                    count++;
                }
                if (!count) {
                    this.callBackObj [this.callBackFunc](this._parent);
                    this.removeMovieClip();
                }
            };
        };
    Пример 5.7.

    Можно использовать Object.registerClass для связывания любого отдельного символа фильма с данным классом. Тогда вы могли бы добавить дополнительные методы к этому классу для добавления параметров к tween.

    tweenable.prototype.addToTween = function(obj) {
        //loop through and add properties to targetsObj
        for (var prop in obj) {
          this.tweenControl.targetsObj [prop] = obj [prop];
       }
    };

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

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

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

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

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

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

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