0
votes

Whenever I export the .swf file of my Flash game, I am receiving "TypeError: Error #1009: Cannot access a property or method of a null object reference.", along with a Runtime Shared Library Preloading Warning for my preloader. I have my timeline organized so that the first and third frames are both empty along with a stop(); command in the Actions layer. The second frame contains a single MovieClip that contains all of my exported assets, which are going to be initialized in the third frame of the timeline. None of my assets, except for the preloader, are exported in the first frame. What changes should I make to my Document Class for it to initialize the assets in the third frame?

Document Class:

package com.gameEngine.documentClass
{
    import flash.events.*;
    import flash.display.*;
    import flash.geom.Point;
    import com.gameEngine.assetHolders.*;
    import com.gameEngine.assetHolders.Levels.*;

    public class Document extends MovieClip
    {
        private static var _document:Document;
        private var preloader:Preloader;
        public var mcMain:Player;
        public var restartButton:RestartButton;
        public var spawnArea:SpawnArea;
        public var level_1:Level_1;
        public var level_2:Level_2;
        public var level_3:Level_3;

        public function Document()
        {
            addEventListener(Event.ADDED_TO_STAGE, init);
            _document = this;
            preloader = new Preloader(390, this.loaderInfo);
            this.addChild(preloader);
            preloader.addEventListener("loadComplete", loadAssets);
            preloader.addEventListener("preloaderFinished", showLogo);
            mcMain = new Player(this);
            restartButton = new RestartButton(this);
            spawnArea = new SpawnArea();
            level_1 = new Level_1(this);
            level_2 = new Level_2(this);
            level_3 = new Level_3(this);
            this.addChild(restartButton);
            this.addChild(spawnArea);
            this.preloader.x = 400;
            this.preloader.y = 250;
            restartButton.x = 822.95;
            restartButton.y = 19;
            spawnArea.x = 400;
            spawnArea.y = 250;
            trace ("Document Class Initialized");
            // constructor code
        }
        public static function getInstance():Document
        {
            return _document;
        }
        private function loadAssets(event:Event):void
        {
            this.play();
        }
        private function showLogo(event:Event):void
        {
            this.removeChild(preloader);
        }
        public function init(event:Event)
        {
            if (stage.contains(spawnArea))
            {
                addChild(mcMain);
            }
            mcMain.x = spawnArea.x;
            mcMain.y = spawnArea.y;
        }
    }
}

Preloader Class:

package com.gameEngine.assetHolders
{
    import com.gameEngine.documentClass.*;
    import flash.display.*;
    import flash.events.*;

    public class Preloader extends MovieClip
    {
        private var fullWidth:Number;
        public var loaderInfo:LoaderInfo;

        public function Preloader(fullWidth:Number = 0, loaderInfo:LoaderInfo = null)
        {
            this.fullWidth = fullWidth;
            this.loaderInfo = loaderInfo;

            addEventListener(Event.ENTER_FRAME, checkLoad);
        }

        private function checkLoad (event:Event):void
        {
            if (loaderInfo.bytesLoaded == loaderInfo.bytesTotal && loaderInfo.bytesTotal != 0)
            {
                dispatchEvent(new Event("loadComplete"));
                phaseOut();
            }

            updateLoader(loaderInfo.bytesLoaded / loaderInfo.bytesTotal);
        }

        private function updateLoader(num:Number):void
        {
            progressBar.width = num * fullWidth;
        }

        private function phaseOut():void
        {
            removeEventListener(Event.ENTER_FRAME, checkLoad);
            progressBar.gotoAndPlay(2);
            if (progressBar.currentFrame == progressBar.totalFrames)
            {
                phaseComplete();
            }
        }

        private function phaseComplete() : void
        {
            dispatchEvent(new Event("preloaderFinished"));
        }
    }
}
1

1 Answers

1
votes

You have a lot of race conditions going on here. Many of these events could occur at relatively random times in relation to one another . . . you have to think asynchronously. That is, there can be no assumption that any object exists. E.g., in Document.init(), you check is if the spawnArea exists, but it is almost guaranteed not to at that point, and you never check for it again.

Without making any specific changes, I can recommend a generic solution. For any object (objB) you want loaded after another object (objA) is loaded, have objB created in the objA's ADDED_TO_STAGE handler. A simple example would be:

var objA:Whatever;
var objB:WhateverElse;

[...]

objA = new Whatever();
objA.addEventListener(Event.ADDED_TO_STAGE, objAAddedHnd);

[...]

public function objAAddedHnd(event:Event)
{
    // remove the event, if no longer needed:
    objA.removeEventListener(Event.ADDED_TO_STAGE, objAAddedHnd);

    objB = new WhateverElse();
    objB.addEventListener(Event.ADDED_TO_STAGE, objBAddedHnd);
}

[...]

public function objBAddedHnd(event:Event)
{
    // remove the event, if no longer needed:
    objB.removeEventListener(Event.ADDED_TO_STAGE, objBAddedHnd);

    // and so on . . .
}

At this point, it shows that you would need to plan the timeline of object creation.