【问题标题】:AS3 - Referencing the Stage after Preloader ImplementationAS3 - 在预加载器实现后引用阶段
【发布时间】:2014-03-06 19:44:35
【问题描述】:

我刚刚完成了一个小游戏的基本结构并将简单的预加载器保存到最后。傻我。

经过大量教程后,我发现这个对我有用 - Pre Loader in Flash Builder

预加载器工作,游戏在舞台上,但立即冻结。在我的 LevelOne 代码中对 stage 的任何引用都会引发错误。 错误 #1009:无法访问空对象引用的属性或方法。

在实现 Preloader 之前,我的应用程序类 (RookiesGame) 被用作关卡切换器。每个级别都包含在一个 Sprite 中。 RookiesGame 首先将 LevelOne 添加到阶段,然后一旦玩家完成它,RookiesGame 将删除 LevelOne 并将 LevelTwo 添加到阶段等。

关卡类使用 _stage 变量引用舞台。

自从我学习这个结构以来,preloader变成了应用程序类而RookiesGame变成了另一个类,这让我很困惑。 _stage 变量不应该仍然有效吗?将 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 类

很多 #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 类参考舞台,将不胜感激。

【问题讨论】:

    标签: actionscript-3 flash flash-builder preloader stage


    【解决方案1】:

    您正在将一个空的 stage 从您的 RookiesGame 类传递给 LevelOne。每当您实例化RookiesGame 时,构造函数将首先运行,它尚未添加到显示列表中,因此它对stage 的继承引用是null。您需要做的是在RookiesGame 类中为ADDED_TO_STAGE 添加一个事件监听器:

    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 变量如果您将这些类添加到显示列表中。

    您还拥有LevelOne 中的ADDED_TO_STAGE 的侦听器,其中stage 变量将不再为空,因此您可以完全删除您的类变量_stage

    【讨论】:

    • 谢谢,效果很好。您也完全删除了 _stage 变量是对的。我一直在学习的文本使用 _stage var 和 ADDED_TO_STAGE?奇怪的。再次感谢!
    猜你喜欢
    • 2017-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多