Reputation: 5
I have two classes; my Main class and a class called BlockPlace. I want to use my Main class to run BlockPlace, but for some reason it isn't working. I've tried changing both codes, but it only results in errors. I know for a fact that the code works because I tested it in the timeline. Should I restructure the entire thing or is there a different solution? Here are my classes:
Main Class:
package
{
import flash.display.*;
import source.map.*;
public class Main extends MovieClip{
public function Main()
{
BlockPlace();
}
}
}
BlockPlace:
package source.map{
import flash.display.MovieClip;
import flash.display.Stage;
public class BlockPlace extends MovieClip{
public function BlockPlace(){
var db:MovieClip = new dbox();
stage.addChild(db);
db.x = stage.stageWidth / 2;
db.y = stage.stageHeight / 2;
}
}
}
Upvotes: 0
Views: 149
Reputation: 18546
You've got a couple of problems that I can see, which might explain the behavior you are seeing.
First, you are calling this like is a function, not a constructor.
If you want to statically reference this function, then you want to change things up a bit:
package source.map{
import flash.display.Stage;
public class BlockPlace {
public static function create(stage:Stage){
var db:MovieClip = new dbox();
stage.addChild(db);
db.x = stage.stageWidth / 2;
db.y = stage.stageHeight / 2;
}
}
}
And then invoke it using:
BlockPlace.create(stage);
Notice that the class no longer extends MovieClip, and the method is marked as static, meaning it can be referenced directly from the class, without a instance of the class. Also notice that the functions signature has changed. It now accepts one argument -- the stage -- that gets passed in from the outside.
Using this approach, you give the reference to the stage from your Main
instance into this utility function to do some work. This is probably the most straight-forward solution to your problem.
Conversely, if you want to keep this as a class that extends MovieClip -- there are some implications of what that means -- then you need to instantiate an instance of the class:
var blockPlace:BlockPlace = new BlockPlace();
Then, you need to get it on the sage:
this.addChild(blockPlace);
But you've still got a bit of a chicken/egg problem with the stage. When you instantiate the class, in its constructor you are referencing the stage
property. At this point of its construction however, it hasn't been added to any DisplayObjectContainers
who are attached the stage. So the stage
property will be null
. As such, you can't add anything to the stage or get the stageHeight
or stageWidth
.
You'll need to wait until that has happened -- which wont happen until addChild(blockPlace)
gets evaulated.
So you need to re-think your architecture a bit, you can either move the logic into another function that will get explicitly called by you once you are sure that its has been attached to the stage. Something like:
package source.map{
import flash.display.Stage;
public class BlockPlace {
public function BlockPlace() {
}
public function initialize():void {
var db:MovieClip = new dbox();
stage.addChild(db);
db.x = stage.stageWidth / 2;
db.y = stage.stageHeight / 2;
}
}
}
And then consumed using something like :
var blockPlace:BlockPlace = new BlockPlace();
addChild(blockPlace);
blockPlace.initialize(); // safe to call because its on the stage now given that `this` is on the stage
A more idiomatic approach however would be to use events to wait until the MovieClip has been added to the stage, and then perform some work. For example:
package source.map{
import flash.display.Stage;
public class BlockPlace {
public function BlockPlace() {
this.addEventListener(Event.ADDED_TO_STAGE, stageAvailable);
}
private function stageAvailable(e:Event):void {
var db:MovieClip = new dbox();
stage.addChild(db);
db.x = stage.stageWidth / 2;
db.y = stage.stageHeight / 2;
}
}
}
Notice that the constructor now sets up an event listener which says, "When I get added to the stage, go do the work that's in this other function called stageAvailable
."
There are some minor caveats that you have to be aware of, it is possible for display objects to be constructed directly on the stage -- the flash IDE does this. so the event will not fire for those items, because by the time the event gets attached, its already on the stage, and thus will not fire. The most defensive way to write it is this:
package source.map{
import flash.display.Stage;
public class BlockPlace {
public function BlockPlace() {
if(stage) stageAvailable()
else this.addEventListener(Event.ADDED_TO_STAGE, stageAvailable);
}
private function stageAvailable(e:Event = null):void {
if(event) this.removeEventListener(Event.ADDED_TO_STAGE, stageAvailable);
var db:MovieClip = new dbox();
stage.addChild(db);
db.x = stage.stageWidth / 2;
db.y = stage.stageHeight / 2;
}
}
}
In the constructor, it checks to see if there is a stage, and if so then it immediately calls the function. If not, then it sets up a listener to wait until that happens. Then in the handler, if it was called because of an event, then clean up after itself and remove the listener.
Upvotes: 4
Reputation: 27886
Change:
BlockPlace();
to:
var blockPlace:BlockPlace = new BlockPlace();
You need to actually instantiate it.
Upvotes: 1