Preloader в actionscript 3 - Ссылочная ошибка в getDefinition () - PullRequest
3 голосов
/ 18 ноября 2009

пишу прелоадер:

package {
    import flash.display.DisplayObject;
    import flash.display.Sprite;
    import flash.text.TextField;
    import flash.display.LoaderInfo;
    import flash.events.MouseEvent;
    import flash.events.Event;
    import flash.events.ProgressEvent;
    import flash.system.System;

    public class Preloader extends Sprite {
            private var t:TextField = new TextField();
            private var ver:String = "1000";
            public function Preloader() {
                    t.y = 570;
                    addChild( t );
                    t.text = ver;

                    addEventListener( Event.ADDED_TO_STAGE, init );
            }

            private function init( e:Event ):void {
                    this.root.loaderInfo.addEventListener( ProgressEvent.PROGRESS, onLoadingProgress );
                    this.root.loaderInfo.addEventListener( Event.COMPLETE, onLoadingCompleted );

                    // See if it's already completed
                    var percent:int = int( root.loaderInfo.bytesLoaded / root.loaderInfo.bytesTotal );
                    if ( percent == 1 )
                            onLoadingCompleted();
            }

            private function onLoadingProgress( event:Event ):void {
                    var percent:int = int(root.loaderInfo.bytesLoaded / root.loaderInfo.bytesTotal * 100);
                    t.text = "Loading.. " + percent + "%";
            }

            private function onLoadingCompleted( event:Event = null ):void {
                    root.loaderInfo.removeEventListener( ProgressEvent.PROGRESS, onLoadingProgress );
                    root.loaderInfo.removeEventListener( Event.COMPLETE, onLoadingCompleted );

                    var mainClass:Class = loaderInfo.applicationDomain.getDefinition("Main") as Class;
                    var main:DisplayObject = new mainClass() as DisplayObject;

                    parent.addChild( main );
                    parent.removeChild( this );
            }
    }
}

с этим в качестве основного класса:

package {
    import flash.display.Sprite;

    public class Main extends Sprite {

            public function Main() {
            }
    }
}

так что это почти столько же, сколько я мог бы сделать.

Тем не менее, он приветствует меня с:

ReferenceError: Error #1065: Variable Main is not defined.
at flash.system::ApplicationDomain/getDefinition()
at ...

Я использую frames.frame для вставки Main. Я компилирую, используя ant и linux SDK напрямую (mxmlc). Я что-то упускаю из виду?

Ответы [ 4 ]

4 голосов
/ 18 ноября 2009

Когда вы делаете предварительный загрузчик в этом «стиле», на самом деле происходит следующее: предварительный загрузчик помещается в первый кадр приложения, а остальные - во второй. Что вам не хватает здесь, так это сообщить компилятору, что вы хотите, чтобы ваш класс Main был скомпилирован, поэтому сейчас его даже нет в swf. Вот почему getDefinition не будет работать.

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

Добавьте эту строку в опции вашего компилятора, и вы должны быть готовы:

-frame start Main

Помните, что если ваш основной класс находится в пакете, вам нужно получить полную ссылку:

-frame start com.grapefrukt.examples.Main

То же самое относится и к вызову getDefinition.

EDIT:

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

var mainClass:Class = getDefinitionByName("com.grapefrukt.examples.Main") as Class;
addChild(new mainClass() as DisplayObject);

ИЗМЕНИТЬ СНОВА: Если это работает с помощью кнопки, я думаю, событие завершено слишком рано по какой-то причине Может быть так, что не все правильно инициализируется, хотя все байты загружены. Попробуйте использовать этот код для проверки завершения:

if (currentFrame == totalFrames) onLoadingCompleted()

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

1 голос
/ 18 ноября 2012

Это немного длинно для комментария, хотя это действительно расширение ответа грейпфрукта. Это также довольно поздний ответ. Но я нигде не видел этого документированного Adobe или кем-либо еще:

Одной из причин, по которой Event.COMPLETE может показаться запущенным «рано» (до того, как следующий кадр будет фактически готов), является использование общих библиотек времени выполнения. Event.COMPLETE будет запущено, когда текущий SWF будет загружен - что может (и обычно происходит) до того, как будут загружены любые RSL.

RSL загружается «автоматически» (например, используя «Импорт для общего доступа во время выполнения» во Flash Pro) будет загружаться, когда загружаются связанные с ними символы библиотеки, что - в обычной реализации предварительного загрузчика - означает, что точка воспроизведения пытается ввести кадр 2.

Пока они не завершат загрузку, вы не сможете перейти к кадру 2 - и пока вы не сможете перейти, у вас не будет доступа ни к каким классам или экземплярам в этом кадре. Любой вызов gotoAndStop(2) или nextFrame() не будет иметь немедленного эффекта (то есть, ответ eLouai не будет работать в этом случае), и более того, вызов также не будет "поставлен в очередь". Проигрыватель просто останется на кадре 1. Может случиться так, что внутри возникнут некоторые ссылочные ошибки, которые проглочены где-то во FlashPlayer. По крайней мере, в моих тестах об ошибке никогда не сообщалось. Это просто молча терпит неудачу. play(), однако, будет переходить к следующему кадру - когда он будет готов.

Другими словами - как предполагает грейпфрукт - если воспроизводится swf, вы можете подождать currentFrame == 2 (или любой другой номер кадра) в ENTER_FRAME слушателе. В качестве альтернативы, вы можете позвонить nextFrame() или gotoAndStop(2) (или любой другой номер кадра) в ENTER_FRAME слушателе, пока не обнаружите этот currentFrame == 2. Последнее кажется чем-то, что может потенциально сломаться в будущем, так как, опять же, ошибки могут фактически происходить изнутри, хотя проигрыватель не выводит никаких данных.

Короче говоря:

play() будет ждать, пока кадр 2 не будет готов. gotoAndStop(2) или nextFrame() не будут иметь никакого эффекта, если только кадр 2 не будет готов при вызове . И Event.COMPLETE не гарантирует, что все кадры готовы к отображению. В частности, не при использовании RSL - могут быть и другие причины.

1 голос
/ 10 сентября 2011

Вам не хватает nextFrame ();
В функцию onLoadingComplete добавьте nextFrame ();

Вот голая версия:
</p> <pre><code> public class Preloader extends MovieClip { public function Preloader() { stop(); addEventListener(Event.ENTER_FRAME, onEnterFrame); this.loaderInfo.addEventListener(Event.COMPLETE, startup); // Set up progress bar / graphics } private function onEnterFrame(e:Event):void { // Display progress bar, loadedbytes, animation, etc... } private function startup(e:Event):void { nextFrame(); removeEventListener(Event.ENTER_FRAME, onEnterFrame); loaderInfo.removeEventListener(Event.COMPLETE, startup); var gameClass:Class = getDefinitionByName("Main") as Class; if (gameClass) addChild(new gameClass() as Sprite); } }

1 голос
/ 18 ноября 2009

Отличается ли у вас класс Game в пакете по умолчанию («Game» вместо «game.Game»)?

Я никогда не использовал ничего, как новый mainClass (this.root), новый mainClass () должен быть в порядке.

Кроме того, есть ли разница, если вы используете Event.INIT вместо Event.COMPLETE?

...