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;            

                }
            }
}

Клас първо ниво

Много грешки #1009. Всичко, което се отнася до сцената.

Класът е огромен, така че ще подчертая проблемните части.

Грешка #1009 при рефериране на етап, добавяне на слушателите на клавиатурата.

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

Също така #1009, когато препращате към етап, за да проверите границите на етапа. Вече не мога просто да променям сцената. на това..

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)


Вие предавате null 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