AS3 - Ссылка на этап после реализации предварительного загрузчика

Я только что закончил основную структуру небольшой игры и оставил простой прелоадер напоследок. Я такой глупый.

После многочисленных руководств я нашел то, что мне помогло - Pre Loader в Flash Builder

Прелоадер работает и игра стоит на сцене, но зависает моментально. Любая ссылка на этап в моем коде LevelOne вызывает ошибки. ошибка № 1009: невозможно получить доступ к свойству или методу ссылки на пустой объект.

До внедрения Preloader мой класс приложения (RookiesGame) использовался как переключатель уровня. Каждый уровень содержится в спрайте. RookiesGame начинается с добавления LevelOne на сцену, затем, когда игрок завершает ее, RookiesGame удаляет LevelOne и добавляет LevelTwo на сцену и т. Д.

Классы уровня ссылаются на этап с помощью переменной _stage.

С тех пор, как я изучил эту структуру, предварительный загрузчик стал классом приложения, а RookiesGame стал просто еще одним классом, и это действительно меня сбило с толку. Разве _stage var по-прежнему не работает? Можно ли оставить RookiesGame переключателем уровней?

В любом случае основная проблема - это отсылка к сцене из классов уровня.

Текущий код:

Класс предварительного загрузчика

Работает нормально, игра запускается.

package
{
    import flash.display.DisplayObject;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.utils.getDefinitionByName;

    [SWF(width="650", height="450", backgroundColor="#FFFFFF", frameRate="60")]

    public class Preloader extends Sprite
    {
        // Private
        private var _preloaderBackground:Shape
        private var _preloaderPercent:Shape;
        private var _checkForCacheFlag:Boolean = true;
        // Constants
        private static const MAIN_CLASS_NAME:String = "RookiesGame";

        public function Preloader()
        {
            trace("Preloader: Initialized.")
            addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
        }

        public function dispose():void
        {
            trace("Preloader: Disposing.")
            removeEventListener(Event.ENTER_FRAME, onEnterFrame);
            if (_preloaderBackground)
            {
                removeChild(_preloaderBackground);
                _preloaderBackground = null;
            }
            if (_preloaderPercent)
            {
                removeChild(_preloaderPercent);
                _preloaderPercent = null;
            }
        }

        // Private functions

        private function onAddedToStage(e:Event):void
        {
            trace("Preloader: Added to stage.");
            removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
            stage.scaleMode = StageScaleMode.SHOW_ALL;
            stage.align = StageAlign.TOP_LEFT;
            addEventListener(Event.ENTER_FRAME, onEnterFrame);
        }

        private function onEnterFrame(e:Event):void
        {
            if (_checkForCacheFlag == true)
            {
                _checkForCacheFlag = false;
                if (root.loaderInfo.bytesLoaded >= root.loaderInfo.bytesTotal)
                {
                    trace("Preloader: No need to load, all " + root.loaderInfo.bytesTotal + " bytes are cached.");
                    finishedLoading();
                }
                else
                    beginLoading();
            }
            else
            {
                if (root.loaderInfo.bytesLoaded >= root.loaderInfo.bytesTotal)
                {
                    trace("Preloader: Finished loading all " + root.loaderInfo.bytesTotal + " bytes.");
                    finishedLoading();
                }
                else
                {
                    var percent:Number = root.loaderInfo.bytesLoaded / root.loaderInfo.bytesTotal;
                    updateGraphic(percent);
                    trace("Preloader: " + (percent * 100) + " %");
                }
            }
        }

        private function beginLoading():void
        {
            // Might not be called if cached.
            // ------------------------------
            trace("Preloader: Beginning loading.")
            _preloaderBackground = new Shape()
            _preloaderBackground.graphics.beginFill(0x333333)
            _preloaderBackground.graphics.lineStyle(2,0x000000)
            _preloaderBackground.graphics.drawRect(0,0,200,20)
            _preloaderBackground.graphics.endFill()

            _preloaderPercent = new Shape()
            _preloaderPercent.graphics.beginFill(0xFFFFFFF)
            _preloaderPercent.graphics.drawRect(0,0,200,20)
            _preloaderPercent.graphics.endFill()

            addChild(_preloaderBackground)
            addChild(_preloaderPercent)
            _preloaderBackground.x = _preloaderBackground.y = 10
            _preloaderPercent.x = _preloaderPercent.y = 10
            _preloaderPercent.scaleX = 0
        }

        private function updateGraphic(percent:Number):void
        {
            // Might not be called if cached.
            // ------------------------------
            _preloaderPercent.scaleX = percent
        }

        private function finishedLoading():void
        {
            var RookiesGame:Class = getDefinitionByName(MAIN_CLASS_NAME) as Class;

            if (RookiesGame == null)
                throw new Error("Preloader: There is no class \"" + MAIN_CLASS_NAME + "\".");

            var main:DisplayObject = new RookiesGame() as DisplayObject;
            if (main == null)
                throw new Error("Preloader: The class \"" + MAIN_CLASS_NAME + "\" is not a Sprite or MovieClip.");

            addChild(main);
            dispose();
        }
    }
}

Класс RookiesGame (раньше был классом приложения)

Любые ссылки на этап вызвали ошибку # 1009, которая прекратилась, когда я изменил stage.addChild на this .addChild

Я еще не дошел до обработчика переключателя уровня с предварительным загрузчиком, поэтому я тоже не знаю, как будет работать stage.focus!

package
{
        import flash.display.MovieClip;
        import flash.display.Sprite;
        import flash.events.Event;

        public class RookiesGame extends Sprite
        {
            private var _levelOne:LevelOne;
            private var _levelTwo:LevelTwo;

                public function RookiesGame()
                {
                _levelOne = new LevelOne(stage);
                _levelTwo = new LevelTwo(stage);
                this.addChild(_levelOne); 
                        this.addEventListener("levelOneComplete",levelTwoSwitchHandler);                        
                }
                private function levelTwoSwitchHandler(event:Event):void
                {
                        this.removeChild(_levelOne);
                    _levelOne = null;
                    this.addChild(_levelTwo);
                        stage.focus = stage;            

                }
            }
}

LevelOne Class

Множество ошибок # 1009. Все, что связано со сценой.

Класс огромен, поэтому я выделю проблемные блоки.

Ошибка # 1009 при обращении к этапу добавления слушателей клавиатуры.

_stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
_stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler); 

Также # 1009 при обращении к этапу для проверки границ этапа. Больше нельзя просто изменить stage. на this..

private function checkStageBoundaries(gameObject:MovieClip):void
        {
            if (gameObject.x < 50)
            {
                gameObject.x = 50;
            }
            if (gameObject.y < 50)
            {
                gameObject.y = 50;
            }
            if (gameObject.x + gameObject.width > _stage.stageWidth - 50)
            {
                gameObject.x = _stage.stageWidth - gameObject.width - 50;
            }
            if (gameObject.y + gameObject.height > _stage.stageHeight - 50)
            {
                gameObject.y = _stage.stageHeight - gameObject.height - 50;
            }
        }

Я ссылаюсь на _stage позже в программе, чтобы удалить прослушиватели событий. Вот и все.

_stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
_stage.removeEventListener(KeyboardEvent.KEY_UP, keyUpHandler);  

Как я могу ссылаться на этап без этих ошибок и оставить RookiesGame в качестве переключателя уровня.

Структура класса LevelOne

Чтобы показать, как я использую (d) _stage.

package
{
       //import classes

        public class LevelOne extends Sprite
        {
        //Declare the variables to hold the game objects

        //A variable to store the reference to the stage from the application class
        private var _stage:Object;


        public function LevelOne(stage:Object)
            {
                _stage = stage; 
                this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
            }
            private function addedToStageHandler(event:Event):void
            {
                startGame();
                this.removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
            }
            private function startGame():void
            {
            //Includes _stage references that mess everything up.
            }
            private function levelCleared():void
            {
            //When Level finished, dispatch event to tell RookiesGame to switch levels.
            dispatchEvent(new Event("levelOneComplete", true));
            }
    }         
}

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


person Rookie    schedule 06.03.2014    source источник


Ответы (1)


Вы передаете нулевой stage в LevelOne из своего RookiesGame класса. Всякий раз, когда вы создаете экземпляр RookiesGame, конструктор запускается первым, он еще не был добавлен в список отображения, поэтому его унаследованная ссылка на stage равна null. Что вам нужно сделать, так это добавить прослушиватель событий для ADDED_TO_STAGE в класс RookiesGame:

package
{
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.events.Event;

    public class RookiesGame extends Sprite
    {
        private var _levelOne:LevelOne;
        private var _levelTwo:LevelTwo;

            public function RookiesGame()
            {
                addEventListener( Event.ADDED_TO_STAGE, onAdded );                        
            }
            //added to stage event
            private function onAdded( e:Event ):void {
                removeEventListener( Event.ADDED_TO_STAGE, onAdded );
                _levelOne = new LevelOne(stage);
                _levelTwo = new LevelTwo(stage);
                this.addChild(_levelOne); 
                this.addEventListener("levelOneComplete",levelTwoSwitchHandler);
            }

            ...
        }

Также, если вы используете addChild() вызов для LevelOne, как в addChild(_levelOne), он имеет собственную ссылку на stage после того, как он был добавлен в список отображения, вам не нужно создавать _stage переменную для этих классов, если вы добавляете их в список отображения.

Также у вас есть слушатель для ADDED_TO_STAGE в LevelOne, где переменная stage больше не была бы нулевой, поэтому вы можете полностью удалить переменную класса _stage.

person Bennett Yeates    schedule 06.03.2014
comment
Спасибо, что отлично сработало. Вы правы и в том, что полностью удалили переменную _stage. В тексте, который я изучал, используются _stage var и ADDED_TO_STAGE? Странный. Еще раз спасибо! - person Rookie; 07.03.2014