Flash CS5引用非文档类的构造函数中的显示对象

时间:2011-07-29 05:09:15

标签: flash actionscript-3 flash-cs5

在了解了除了文档类(找到in this thread)以外的类中访问Flash CS5中放置在舞台上的对象的这种优秀方法之后,我遇到了一个绊脚石。我正在使用

this.stage.getChildAt(0).greenLight1.visible=false;

在访问greenLight1(我的.fla中为位图指定的实例名称)时,将实例名称为greenLight1的符号变为不可见。这在我使用它的地方非常有效,它在几个不同类的子函数中。我遇到的问题是你不能在这些非文档类的构造函数中使用它,或者在构造函数直接调用的任何函数中使用它。如果我尝试这样做,我得到以下“错误#1009:无法访问空对象引用的属性或方法。”

所以我认为我没有正确访问这个并开始使用这个短语。当我把它切换到

this.getChildAt(0).greenLight1.visible=false;

我得到一个不同的错误“1119:通过带有静态类型flash.display:DisplayObject的引用访问可能未定义的属性greenLight1。”所以我显然在这里遗漏了一些东西。

现在我尝试了一种我在this thread中找到的另一种策略,我在上面提到的线程链接中也提到了这种策略。感谢Allan在我的另一个帖子中的评论,我实际上得到了这个方法。但是,当我尝试将该引用放入任何其他非文档类的构造函数类时,我实际上得到相同的“错误#1009:无法访问空对象引用的属性或方法”。但是如果我在子函数中使用它,它的工作正常。看来也是同样的问题。

我的项目包含一个Game.fla文件,该文件包含各种位图符号和几个按钮,我已将其放入我的库中并拖到舞台上(我已经为它们提供了所有唯一的实例名称)。我已经设置了我的文档类Game.as,在其中,我可以简单地使用它们的实例名称来访问所有这些项目。现在在我的子类叫Player.as中,我设置了一个名为lightsOut()的函数,它使用开关/案例关闭灯。我正在使用“this.stage.getChildAt(0).greenLight1.visible = false;”它工作得很好。这也是我设置上面提到的不同策略并尝试“Game.GL1.visible = false;”的地方。这也很有效。但是在我的子类Controller.as中我拥有所有的鼠标和键盘处理程序,我试图为我的一个阶段按钮设置一个事件监听器。所以我将它放在Controller构造函数中,我将所有其他事件监听器设置并且已经工作(它们使用“stage.addeventlistener ...”)并且在这里我开始看到错误。所以我想我会尝试让greenLight1关闭,因为我已经知道代码工作并尝试了“this.stage.getChildAt ....”行和“Game.GL1 ...”行看他们导致我上面提到的错误。所以我回到了我的Player.as类,并在它的Player构造函数类中尝试了它们,并再次得到了相同的错误,即使我在Player.as类中使用相同的行也不错。请注意,我已经将舞台传递给了Controller和Player,并且两者都使用得很好。我还尝试在名为Init()的构造函数中设置对另一个函数的调用;并且在尝试访问greenLight1时也遇到了同样的错误,但它仍然在lightsOut()中工作。也不确定它是否重要,但所有类都扩展了MovieClip。我不知道这是否会有所帮助,但这里是Player类的开头以及lightsOut函数我已经删除了其余代码,因为它不相关:

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

public class Player extends MovieClip {
    private var _stage:Object;
    private var _lights:uint;

    public function Player(stage:Object):void {
        this._stage = stage;
        this._stage.getChildAt(0).greenLight1.visible=false; //errors
        addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
    }
    private function lightsOut():void {
        switch(_lights) {
            case 1:
            this._stage.getChildAt(0).greenLight1.visible=false;//works
            break;
            case 2:
            this._stage.getChildAt(0).greenLight2.visible=false;//works
            break;
            case 3:
            this._stage.getChildAt(1).greenLight3.visible=false;//works
            break;
        }
    }

我在这里缺少什么?

编辑: 好的是文档类(至少对Controller和Player很重要):

public class Game extends MovieClip {
    private var _player:Player = new Player(stage);
    private var _controller:Controller = new Controller(_player, stage);

    public function Game():void {
        addChild(_player);
        addEventListener(Event.ADDED_TO_STAGE, added);

这是Controller类的重要部分,我添加了对失败的评论(我首先开始这篇文章的真正原因):

public class Controller extends MovieClip {
private var _stage:Stage;
private var _model:Object;

public function Controller(model:Object, stage:Stage):void {
    this._model = model;
    this._stage = stage;

    _stage.addEventListener(KeyboardEvent.KEY_DOWN, processKeyDown);
    _stage.addEventListener(KeyboardEvent.KEY_UP, processKeyUp);
    _stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
    this._stage.getChildAt(0).fireButton.addEventListener(MouseEvent.CLICK, onClick); //this is what isn't working
    this._stage.getChildAt(1).greenLight1.visible=false; //added this for testing

我最后一行只是添加了,看看我是否可以让绿色灯光变得不可见,就像我在Player.as中注意到的lightsOut()函数中调用它一样。但是当它放在构造函数中时它也不起作用。救命!!!!洛尔

3 个答案:

答案 0 :(得分:1)

你不能在类的构造函数中访问舞台上的实例,但是可以在类的另一个函数中调用(我稍后会调用),这使得我认为当你的构造函数不能用于你的构造函数时被召唤。

检查以确保您的Game.as文档类设置如此,尽管可能是因为您遵循了我的方法:

public function Game() {
    addEventListener(Event.ADDED_TO_STAGE, init, false, 0, true);
    //DO NOT CREATE CLASS INSTANCES IN HERE
}

private function init(e:Event):void{
    //In here is where we create instances of classes
}

此外,在您的Player类的constuctor的参数中将舞台数据类型设置为Stage而不是Object,以便进行良好的编码练习。

答案 1 :(得分:1)

您遇到的问题是,在将阶段对象传递给它之前,您要实例化控制器类。您必须等到ADDED_TO_STAGE事件被触发后才能实例化其他所有内容:

public class Game extends MovieClip {
    private var _player:Player;
    private var _controller:Controller;

    public function Game():void
    {
        addEventListener(Event.ADDED_TO_STAGE, added);
    }
    private function added(evt:Event):void
    {
        removeEventListener(Event.ADDED_TO_STAGE, added);
        _player = new Player(stage);
        _controller = new Controller(_player,stage);
        addChild(_player);
    }
}

有更好的方法

您不需要将舞台传递给您的播放器和控制器。如果您只是将引用传递给this,则会传递对文档类的引用。这是一个更好的实践,因为它为您准备更高级的编程方法,如design patterns

所以你会得到你的文档课:

public class Game extends MovieClip {
    private var _player:Player;
    private var _controller:Controller;

    public function Game():void
    {
        addEventListener(Event.ADDED_TO_STAGE, added);
    }
    private function added(evt:Event):void
    {
        removeEventListener(Event.ADDED_TO_STAGE, added);
        _player = new Player(this);
        _controller = new Controller(_player,this);
        addChild(_player);
    }
}

并在你的玩家类中:

public class Player extends MovieClip {
    private var docRef:Game;
    private var _lights:uint;

    public function Player($docRef:Game):void {
        this.docRef = $docRef;
        docRef.greenLight1.visible=false; //no longer needs to wait for player to be on the stage
    }
}

优势显而易见,因为你知道你的文档类在舞台上,玩家不需要在它可以与之交互之前就在舞台上。它不需要永远在舞台上。如果你需要阶段,比如像在Controller中那样添加监听器,你可以使用文档阶段属性:

docRef.stage.addEventListener ...

答案 2 :(得分:0)

stageDisplayObject的属性,只有在DisplayList添加后才可访问/定义(即 - 通过addChild()添加到某个内容中

除非是文档类,否则从类构造函数访问stage将没有任何好运。

如上所述,您可以将构造函数的内容转移到自定义函数,该函数在触发Event.ADDED_TO_STAGE后调用。

例如,这是一个演示类:

public class Thing extends DisplayObject
{
    /**
     * Constructor
     */
    public function Thing()
    {
        // Add listener
        addEventListener(Event.ADDED_TO_STAGE, _added);
    }

    /**
     * Called once this has been added to the display list
     * @param e Event.ADDED_TO_STAGE
     */
    private function _added(e:Event):void
    {
        // Discard listener
        removeEventListener(Event.ADDED_TO_STAGE, _added);

        // My initial code
        trace(stage + " is accessible");
    }
}

然后我们创建一个实例:

var thing:Thing = new Thing(); // nothing happens

然后添加到舞台/当前容器中:

addChild(thing); // output: [Object Stage] is accessible

至于访问greenLight1,这应该可以通过以下任何一种方式轻松实现:

stage.greenLight1;
stage["greenLight1"];

另外,您可能想要替换:

public function Player(stage:Object):void

使用:

public function Player(stage:Stage):void