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

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

Предварительная загрузка изображений

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

  1. В pictureDataComplete создадим новый фильм состояния, а также фильм, в который будут загружаться изображения. Установим enterFrame, принадлежащий _root, на значение checkPreload, которое будет обновлять состояние и проверять загрузку каждого изображения. Наконец, мы вызовем loadNext для начала загрузки первого изображения. Переменная picLoading служит для выяснения того, какое изображение загружается в данный момент. Мы заменим выражение trace, располагавшееся прежде в функции pictureDataComplete, следующим кодом.
    function pictureDataComplete() {
            _root.createStatusMovie("PICTURES LOADING");
            _root.createEmptyMovieClip("picturePlacebo", 2);
            picturePlacebo._x = 1000;
            picLoading = 0;
            // check how much is loaded on enterFrame
            this.onEnterFrame = checkPreload;
            loadNext();
        }
  2. loadNext будет проверять, имеются ли изображения, которые еще должны быть загружены, в массиве pictureObjects (если picLoading меньше, чем длина массива). Если еще остался рисунок для загрузки, он будет загружен в фильм, расположенный вне рабочего места; в противном случае этот фильм будет удален, а statusClip постепенно исчезнет с использованием tweenTo.

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

    function loadNext() {
            if (picLoading<pictureObjects.length) {
            // Load the next picture using the file property
            picturePlacebo.loadMovie(pictureObjects[picLoading].file);
            } else {
                delete this.onEnterFrame;
                var obj = {_alpha:0};
                picturePlacebo.removeMovieClip();
                _root.statusClip.tweenTo(obj, 9, _root, "setUpStage");
            }
        }
  3. Функция checkPreload работает во многом так же, как и загрузчик XML. Она создает переменную percent и устанавливает ее по getBytesLoaded внешнего (находящегося вне рабочего места) фильма, а затем отображает процентное значение в фильме status. После полной загрузки рисунка (когда процент равен 100) она сначала сохраняет ширину и высоту фильма (которые равны ширине и высоте рисунка внутри фильма) в нашем массиве pictureObjects. Затем она увеличивает переменную picLoading и вызывает loadNext. Мы расположили эту функцию под loadNext.
    function checkPreload() {
            var percent = Math.round(picturePlacebo.getBytesLoaded()
            К/picturePlacebo.getBytesTotal()*100);
            if (percent<=0) {
                percent = "0";
            }
            _root.statusClip.statusText.text = 
              "PICTURE"+(picLoading+1)+"
            КLOADING \n"+percent+"%";
            if (percent == 100) {
            // store picture's width and height
                _root.pictureObjects[picLoading].width =
                  _root.picturePlacebo._width;
                _root.pictureObjects[picLoading].height = 
                  _root.picturePlacebo._height;
                picLoading++;
                loadNext();
            }
        }

    Приведем окончательный код.

    #include "tweento.as"
        #include "brightness.as"
        #include "stage.as"
        _root.filename = "pictures.xml";
        embedder._visible = 0;
        statusTf = new TextFormat("Arial", 40, 0x4375A6);
        statusTf.align = "center";
        statusTf.leading = -5;
        function createStatusMovie(tex) {
            _root.createEmptyMovieClip("statusClip", 1);
            statusClip.createTextField("statusText", 1, 0, 0, 550, 100);
            statusClip.statusText.embedFonts = true;
            statusClip.statusText.selectable = false;
            statusClip.statusText.setNewTextFormat(statusTf);
            statusClip.statusText.text = tex;
            statusClip._x = 0;
            statusClip._y = (Stage.originalHeight statusClip.statusText.textHeight)/2-50;
        }
        function importXml() {
            trace("data imported from xml");
            pictureObjects = [];
            myXml = new Xml();
            myXml. ignoreWhite = true;
            myXml.updateXmlStatus = function() {
                var percent = Math.round(this.getBytesLoaded()/this.getBytesTotal()*100);
                if (percent<=0) {
                    percent = "0";
                }
                _root.StatusClip.statusText.text = "PICTURE DATA LOADING \n"+percent+"%";
            };
            myXml.updater = setInterval(myXml, "updateXmlStatus", 20);
            myXml.onLoad = parseMe;
            myXml.load(_root.filename);
            _root.createStatusMovie("PICTURE DATA LOADING");
        }
        function parseMe(success) {
            if (success) {
                var pictures = this.firstChild.childNodes;
                for (var i = 0; i<pictures.length; i++) {
                    var obj = {};
                    for (var j in pictures[i].attributes) {
                        obj[j] = pictures [i].attributes [j];
                    }
                    pictureObjects.push(obj);
                }
                _root.refreshSharedObj();
                clearlnterval(this.updater);
                statusClip.removeMovieClip();
                _root.pictureDataComplete();
            } else {
                _root.StatusClip.statusText.text = "FAILED TO LOAD DATA";
                clearlnterval(this.updater);
            }
        }
        function refreshSharedObj() {
            mySharedObj = sharedobject.getLocal("denim");
            mySharedObj.data.pictureObjects = pictureObject s;
            var dat = new Date();
            mySharedObj.data.timeStamp = dat.getTime();
            mySharedObj.flush();
        }
        function checkShared() {
            mySharedObj - sharedobject.getLocal("denim");
            if (mySharedObj.data.pictureObjects) {
                var dat = new Date();
                if (dat.getTime()-mysharedObj.data.timeStamp<604800000) {
                    trace("data found in shared object");
                    _root.pictureObjects = mySharedObj.data.pictureObjects;
                    pictureDataComplete();
                    return true;
                }
            }
        }
        function pictureDataComplete() {
            _root.createStatusMovie("PICTURES LOADING");
            _root.createEmptyMovieClip("picturePlacebo", 2);
            picturePlacebo._x = 1000;
            picLoading = 0;
            this.onEnterFrame = checkPreload;
            loadNext();
        }
        function loadNext() {
            if (picLoading<pictureObjects.length) {
                picturePlacebo.loadMovie(pictureObjects[picLoading].file);
            } else {
                delete this.onEnterFrame;
                var obj = {_alpha:0};
                picturePlacebo.removeMovieClip();
                _root.statusClip.tweenTo(obj , 9, _root, "setUpStage");
            }
        }
        function checkPreload() {
            var percent = Math.round(picturePlacebo.getBytesLoaded()/
            КpicturePlacebo.getBytesTotal()*100);
            if (percent<=0) {
                percent = "0";
            }
            _root.statusClip.statusText.text = "PICTURE "+(picLoading+1)+"
            КLOADING \n"+percent+"%";
            if (percent == 100) {
                _root.pictureObjects[picLoading].width = _root.picturePlacebo._width;
                _root.pictureObjects[picLoading].height = _root.picturePlacebo._height ;
                picLoading++;
                load Next();
            }
        }
        function init() {
            if (!checkShared()) {
                importXml();
            }
        }
        init();
    Пример 5.12.
  4. Сохраните ваш файл под именем preloadPictures.fla. При его запуске вы увидите следующее сообщение.

    В дополнение к этому, если вы выберете Debug > List Variables, в окне Output также отобразится, что все ваши рисунки загружены.


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

Настройка рабочего места

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

  1. Первое, что нужно сделать при вызове setUpStage - это удалить statusClip. После этого мы создадим строку кнопок для вызова нужных фотографий.
    function setUpStage() {
            _root.statusClip.removeMovieClip();
            // create the buttons
            createButtons();
            // trigger the first photo
            triggerPhoto(0);
        }
  2. Для создания кнопок мы будем использовать компонент nooButton, созданный в предыдущей лекции, поэтому убедитесь, что в Library имеется его копия (вы можете заимствовать ее из полной версии этого упражнения в файле с именем finalVersion.fla ). Мы добавим объект textFormat для кнопок в верхней части нашего кода. Приведем новую строку кода, выделенную жирным шрифтом.
    #include "tweento.as"
        #include "brightness.as"
        #include "stage.as"
        _root.filename = "pictures.xml";
        embedder._visible = 0;
        buttonTf = new TextFormat("Arial", 20, 0x4375A6);
        statusTf = new TextFormat("Arial", 40, 0x4375A6);
  3. Функция createButtons (расположенная нами под setUpStage ) знакома вам из предыдущей лекции. Мы создаем объект для установки параметров новой кнопки, ее внешнего вида и действия. На этот раз мы присваиваем функцию triggerPhoto управляющему элементу события press, которая будет передавать функции номер фотографии.
    function createButtons(imageArr, tF) {
            _root.createEmptyMovieClip("buttonHolder", 100000);
            var currx;
            for (var i = 0; i<pictureObjects.length; i++) {
                _root.buttonHolder.depth = i + 1;
                var caption = (i+1).toString().length<2 ? "00"+(i +1) : "0"+(i +1);
                var obj = {myText:caption, _x:currx, obj:_root, defaultBright:0, rollOverBright:30,
                КvisitedBright:60, activeBright:-30, pressFunction:"triggerPhoto",
                КpressArgs:i, tf:buttonTf, embedFonts:true};
                var nooButton = buttonHolder.attachMovie("nooButtonMc", "noob"+i, i, obj);
                currX += nooButton.width+5;
            }
            // set the first button to active
            buttonHolder.noob().setActive();
            buttonHolder._x = (Stage.originalWidth-buttonHolder._width)/2;
            buttonHolder._y = Math.round(Stage.bottom)-buttonHolder._height;
            // move to the bottom of the stage onResize
            buttonHolder.onResize = function() {
                var у = Math.round(Stage.bottom)-30;
                this.tweenTo({_y:y}, 3);
            };
            Stage.addListener(buttonHolder);
            Stage.onResize();
            buttonHolder.onResize();
        }
    Пример 5.13.

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


    Мы использовали несколько новых элементов во второй части функции createButtons и сейчас рассмотрим их поподробнее.

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

    buttonHolder.noob0.setActive();

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

    buttonHolder._x = (Stage.originalWidth-buttonHolder._width)/2;
        buttonHolder._y = Math.round (Stage.bottom)-buttonHolder._height;

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

    buttonHolder.onResize = function() {
            var у = Math.round(Stage.bottom)-30;
            this.tweenTo({_y:у}, 3);
        };
        Stage.addListener(buttonHolder);

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

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

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

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

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

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

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

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