在了解了除了文档类(找到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()函数中调用它一样。但是当它放在构造函数中时它也不起作用。救命!!!!洛尔
答案 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)
stage
是DisplayObject
的属性,只有在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