2010-12-31 3 views
0

Ich habe einen Wrapper um Sprite namens ClickableCircle erstellt, der sich bei der Instanziierung selbst zur Anzeigeliste hinzufügen soll. Hier ist eine Spielzeugversion:ActionScript: Wie wird eine Sprite-Unterklasse instanziiert, die sich selbst zur Bühne hinzufügt?

public class ClickableCircle extends Sprite { 
    protected var circle:Shape; 
    protected var myName:String; 

    public function ClickableCircle(name:String, x:uint, y:uint) { 
     super(); 
     circle:Shape = new Shape(); 
     circle.graphics.beginFill(0x00ACDC, 1); 
     circle.graphics.drawCircle(0, 0, 12); 
     this.myName = name; 
     this.x = x; 
     this.y = y; 
     this.addChild(circle); 
     this.addEventListener(MouseEvent.CLICK, reportClickedID); 
     // Here's the problematic line: can't add itself to display list 
     // Error #1009: Cannot access a property or method of a null object reference.         
     stage.addChild(this); 
     trace("Created " + name + " at " + String(x) + ", " + String(y)); 
    } 

    private function reportClickedID(e:MouseEvent):void { 
     trace("You just clicked on " + this.myName); 
    } 
} 

Das Problem ist, dass, wenn ein ClickableCircle aus der Hauptanwendung instanziiert wird, es stürzt ab, wenn es versucht, sich auf die Bühne hinzuzufügen, bc Stufe null ist. Wenn auf der anderen Seite die addChild() aus dem ClickableCircle Konstruktor kommentiert, und das instanziiert cs wird stattdessen auf die Anzeigeliste in der Hauptanwendungsebene hinzugefügt, funktioniert alles einwandfrei:

public class GreetingApp extends Sprite { 
    public function GreetingApp() { 
     var cs:ClickableCircle = new ClickableCircle("joe", 100, 200); 

     // If the child is added here, everything works. 
     stage.addChild(cs); 
    } 
} 

Da sowohl GreetingApp und ClickableCircle erweitern Sprite, ich würde denken, die Bühne wäre instanziiert und an beiden Orten zugänglich. Ich bin brandneu in ActionScript/Flex, also bin ich mir sicher, dass ich etwas Dummes mache. Kann mir jemand sagen, was es ist?

Antwort

2

Sie sind richtig, Bühne wäre null. Der Grund dafür ist, dass DisplayObjects nur dann einen impliziten Verweis auf die Bühne haben, wenn sie der Anzeigeliste hinzugefügt wurden. In Ihrem Fall schafft dies ein bisschen eine Fang-22.

Es gibt mindestens ein paar Möglichkeiten, dieses Problem zu umgehen.


Option 1: Übergeben Sie einen Verweis auf die Bühne in Ihrem Konstruktor. So etwas wie

var cs:ClickableCircle = new ClickableCircle("joe", 100, 200, stage); 

Jetzt in Ihrer ClickableCircle-Instanz haben Sie Zugriff auf die Bühne. Ich würde es in der Regel wie diese Option

public function ClickableCircle(name:String, x:uint, y:uint, target:*) { 
    ... 
    target.addChild(this); 
} 

verwenden 2. Sie eine statische Variable mit einem Verweis auf die Bühne aus Ihrer Hauptanwendungsklasse verwenden können. Sie können auch ein Singleton verwenden, das vor dem Erstellen des ClickableCircle instanziiert wurde, und den Verweis auf die Bühne an den Singleton übergeben. Dann können Sie von überall darauf zugreifen.

public static var STAGE:DisplayObjectContainer; 

Dann Sie Klasse unter der Annahme, Haupt genannt wird, können Sie dies in Ihrer ClickableCircle Klasse tun:

Main.STAGE.addChild(this); 

Wenn dies keinen Sinn macht, oder Sie weitere Hilfe benötigen, lassen Sie es mich wissen.

+0

Vielen Dank! Aus irgendeinem Grund habe ich die Tatsache übersehen, dass die Bühnenreferenz eines DisplayObject nur dann nicht-null wurde, wenn das Objekt explizit zur Display-Liste hinzugefügt wurde - ich dachte, dass es nur eine Bühne in einer Flash-App gibt. Aber jetzt zeigt ein kleines Googeln, dass der Grund, warum es nicht automatisch ist, wahrscheinlich AIR- und sicherheitsbezogen ist. Sehr geschätzt. – shanusmagnus

1

In der Tat ist ein nützliches Dienstprogramm eine Art StageManager, die von Ihrer Hauptanwendung Sprite/MovieClip/DisplayObject festgelegt wird. Sie können den Accessor für die Stufe als den passenderen Klassentyp eingeben.

private var _stage:Stage; 

public static function get stage() : Stage 
{ 
    if(stage == null) throw new Error("You must set the stage in your root before trying to access it.");  
    return stage; 
} 

public static function set stage(value:Stage) 
{ 
    _stage = value; 
} 

Dies ist ein sinnvoller Singleton zu machen, da es in jeder Anwendung nur eine Stage-Instanz gibt.