Question

Ive just finished the basic structure of a little game and saved the simple preloader till last. Silly me.

After numerous tutorials I found this one that worked for me - Pre Loader in Flash Builder

The preloader works and the game is on the stage, but freezes instantly. Any reference to the stage in my LevelOne code throws up errors. error #1009: cannot access a property or method of a null object reference.

Before implementing the Preloader, my Application Class (RookiesGame) was used as a level switcher. Each level is contained in a Sprite. RookiesGame starts by adding LevelOne to stage, then once player completes it, RookiesGame removes LevelOne and adds LevelTwo to stage etc.

The level classes reference the stage with the _stage variable.

Since Ive been learning this structure, the preloader becoming the application class and RookiesGame becoming just another class has really confused me. Shouldn’t the _stage var still work? Is it okay to keep RookiesGame as a level switcher?

Anyway main problem is referencing the stage from the Level Classes.

Current code:

Preloader Class

Works fine, game starts.

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 Class (used to be application class)

Any references to the stage threw up #1009 error, which stopped when I changed stage.addChild to this.addChild

Ive not got to the level switch handler yet with the preloader, so I dont know how stage.focus will work either!

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

Lots of #1009 errors. Anything referencing the stage.

Class is huge so I'll highlight problem chunks.

The #1009 error when referencing stage, adding the keyboard listeners.

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

Also #1009 when referencing stage to check stage Boundaries. Cant just change stage. to this. anymore.

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;
            }
        }

I reference _stage later in the program to remove the event listeners. Thats it.

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

How can I reference the stage, without these errors and keep RookiesGame as the level switcher.

LevelOne Class Structure

To show how I use(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));
            }
    }         
}

Sorry if thats confusing, but if you can help me reference the stage via LevelOne and RookiesGame classes, It would be much appreciated.

Was it helpful?

Solution

You are passing in a null stage to LevelOne from your RookiesGame class. Whenever you instantiate a RookiesGame the constructor will run first, it has not been added to the display list yet so its inherited reference to stage is null. What you need to do is add an event listener for ADDED_TO_STAGE in the RookiesGame class:

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);
            }

            ...
        }

Also if you are using addChild() call for LevelOne as in addChild(_levelOne) it has its own reference to stage after it's been added to the display list, you do not need to create a _stage variable for those classes if you are adding them to the display list.

Also you have the listener for ADDED_TO_STAGE in LevelOne, where the stage variable would have no longer been null, so you can remove your class variable _stage entirely.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top