Cant access nested MovieClip AS3 - actionscript-3

I'm trying to create a intro screen then a start screen after the intro screen is done playing.
I thought the easiest way of doing this would be on scene 1 frame 1, I would create a
MovieClip.
By the way this is a separate document file. So I gave it a document class name of mcStartGameScreen and linked it to Flash Develop for actions.
Now the MovieClip that is on frame 1, I gave an instance name of startMenu then inside the startMenu MovieClip there is a MovieClip that I wanted the buttonMode enabled to be true. I add this MovieClip which is called mcStart on frame(65) inside my startMenu.
Now in my Actions I have this:
public class mcStartGameScreen extends MovieClip
{
private var mcStart:MovieClip;
private var startMenu:MovieClip;
public function mcStartGameScreen()
{
startMenu.mcStart.buttonMode = true; //This is giving me the ERROR!
mcStart.addEventListener(MouseEvent.CLICK, startOnClick);
}
private function startOnClick(e:MouseEvent):void
{
dispatchEvent(new Event("START_GAME"));
}
public function hideScreen():void
{
this.visible = false;
}
public function showScreen():void
{
this.visible = true;
}
}
When I test the movie I get this
error: Cannot access a property or method of a null object reference.
Does anyone know what I am doing wrong?

If you already have a MovieClip with instance name startMenu placed on the stage, so no need for,
private var startMenu:MovieClip; you remove this from your code.
And always have the stage instance first and then proceed.
So modify your constructor like so:
public function mcStartGameScreen()
{
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
private function onAddedToStage(e:Event):void
{
startMenu.mcStart.buttonMode = true; //Now this will not give the ERROR!
startMenu.mcStart.addEventListener(MouseEvent.CLICK, startOnClick);
}

Related

added MovieClip to stageChild and rootChild but still not visible, modifying index doesn't work as well

I am new to action script and working with .fla file add an indicator to my audio recorder,
The following is the code for my Main class initializer, which earlier used to record sound with no mic feedback, then I decided to mess with it by adding a movieClip to display feedback
public function Main()
{
Security.allowDomain("*");
try {
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
drawStartPlayButton();
drawStopPlayButton();
drawStartButton();
drawStopButton();
this.micIndicator = new ActivityBar(this.stage, this);
this.setChildIndex(this.micIndicator, 0);
recorder.thisStage = this.stage;
recorder.thisActivity = this.micIndicator;
start_play_sound_button.addEventListener(MouseEvent.CLICK, onPrepare);
addChild(start_play_sound_button);
addChild(micIndicator);
start_record_button.addEventListener(MouseEvent.CLICK, onStart);
addChild(start_record_button);
stop_record_button.addEventListener(MouseEvent.CLICK, onStop);
addChild(stop_record_button);
recorder.thisActivity = micIndicator;
micIndicator.stop();
micIndicator.x = 0;
micIndicator.y = 0;
this.addChild(micIndicator);
trace("added to stage");
if (checkJavaScriptReady()) {
} else {
var readyTimer:Timer = new Timer(100, 0);
readyTimer.addEventListener(TimerEvent.TIMER, timerHandler);
readyTimer.start();
}
} catch (error:SecurityError) {
//ExternalInterface.call("sendToJavaScript", error.message);
} catch (error:Error) {
//ExternalInterface.call("sendToJavaScript", error.message);
}
}
Now my ActivityBar is extends MovieClip
package org.bytearray.micrecorder {
public class ActivityBar extends MovieClip {
public function ActivityBar(stage:Stage, parent:Sprite) {
super();
this.name = "micIndicator";
this.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
stage.addChild(this);
}
public function onAddedToStage(e:Event):void {
this.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
this.width = 150;
this.height = 30;
this.gotoAndStop(1);
}
public function goToFrame(e:Event):void {
trace("calling goToFrame");
}
}
}
The ActivityBar is supposed display a .fla movie file with 58 frames in it.
The buttons are drawn in the current state, but activity despite being initialized and added to stage, doesn't display
I am using FlashDevelop with flex SDK to develop this code
The buttons are drawn, but when I setChildIndex(micIndicator) higher, the output is blank
There is error in playing MovieClip standalone,
The height and width of movie wont change even in constructer
Why can't I display MovieClip, when I see the published swf of .fla file, I can see that ActivityBar is included in classes, so Its linked correctly.
What is the right way to do this?
Is there some tutorial I can refer too,
this is my first action script project.
public function stage_EnterFrame(e:Event)
{
var num:Number = _microphone.activityLevel;
trace("in the stage_entrance");
trace(thisStage.getChildByName("micIndicator"));
trace("===========================");
thisActivity.play();
if (thisStage.getChildByName("micIndicator") == null) {
trace("no recorder movie clip");
thisStage.addChild(thisActivity);
}
trace(thisActivity.currentFrame);
thisActivity.gotoAndStop(uint((num/100)*29));
}
The function above goes to frame corresponding to mic level.
There is nothing wrong with the linkage. Will try to hint you...
public function ActivityBar(stage:Stage, parent:Sprite) {
super();
this.name = "micIndicator";
this.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
stage.addChild(this); //<-----
}
Q: Where are you adding the child to?
A: stage
this.micIndicator = new ActivityBar(this.stage, this);
this.setChildIndex(this.micIndicator, 0);
Q: What object are you calling setChildIndex() on?
A: instance of Main
Q: Is stage the same as the instance of Main?
A: No
Q: Can you use instance_of_main.setChildIndex(...) and expect it will rearrange the index of the child that belongs to stage?
A: No
Q: Aaaaand, do you know why you are not thrown a runtime error there? Despite the fact that you should see one as you are calling setChildIndex with a child that is not the child of main?
A: Cos you are using a try/catch block - it has ABSOLUTELY no place there as there is no code there that could throw you an error that you should catch.
Got it? ;)
Also bytearray.org is not your domain, why would you use it as a package name?
PS: Your main (document) class should extend either Sprite or MovieClip.

object's stage reference lost when re-instantiated after being removed from memory & displaylist

I'm building a game. When you die or win a level you're prompted to continue or return to the main menu. If you chose to go to the main menu you can start a new game. When you start a new game, the game is object is created again & it's children have lost their reference to the stage. I'm not sure why this is happening and I've spent over a week trying to figure out why. Here's some code (and descriptions of the code) from the game that should hopefully provide enough insight as to why the problem may be occurring:
if the "new game" button is clicked on the startMenu the NavigationEvent.START event is dispatched. a LevelEvent.COMPLETE event is dispatched by WeeBeeGame when the level is completed.
public class DocumentClass extends MovieClip {
public var startMenu:StartMenuGenerator = new StartMenuGenerator();
public var weeBeeGame:WeeBeeGame;
public var youWonBox:YouWonBox = new YouWonBox();
public function DocumentClass() {
// constructor code
addChild(startMenu);
startMenu.addEventListener(NavigationEvent.START, startGameHandler);
}
public function startGameHandler(e:NavigationEvent) : void {
this.removeChild(startMenuBG);
removeChild(startMenu);
weeBeeGame = new WeeBeeGame();
this.addChild(weeBeeGame);
weeBeeGame.addEventListener(LevelEvent.COMPLETE, levelCompleteHandler);
}
public function levelCompleteHandler(e:LevelEvent) : void {
youWonBox.x = this.stage.stageWidth/2;
youWonBox.y = this.stage.stageHeight/2;
addChild(youWonBox);
youWonBox.addEventListener(MouseEvent.CLICK, mouseClickHandler);
}
private function mouseClickHandler(e:MouseEvent) : void {
if(e.target.name === "mainmenubtn"){
mainmenuHandler();
}
}
private function continueHandler() : void {
youWonBox.removeEventListener(MouseEvent.CLICK, mouseClickHandler);
}
private function mainmenuHandler() : void {
youWonBox.removeEventListener(MouseEvent.CLICK, mouseClickHandler);
WeeBeeGame.collisionDOC.removeChildren();
removeChild(weeBeeGame);
weeBeeGame = null;
this.addChild(startMenuBG);
addChild(startMenu);
removeChild(youWonBox);
}
}
the code that dispatches a LevelEvent.COMPLETE event is not shown but it dispatches when the level is complete. collisionDOC needs to be static because it's needed in a lot of other classes and holds the display objects needed for a 3rd party pixel-level collision detection.
public class WeeBeeGame extends MovieClip {
public var bee: Bee;
public var beeHurt:BeeHurt;
public var spawningDaemon:SpawningDaemon;
public static var collisionDOC:DisplayObjectContainer;
public function WeeBeeGame() {
this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler, false, 0, true);
}
private function addedToStageHandler(e:Event) : void {
this.removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
collisionDOC = new MovieClip();
addChild(collisionDOC);
bee = new Bee();
collisionDOC.addChild(bee);
beeHurt = new BeeHurt(bee.x, bee.y);
addChild(beeHurt);
beeHurt.visible = false;
spawningDaemon = new SpawningDaemon(currentLevel);
this.addEventListener(LevelEvent.COMPLETE, levelCompleteHandler, false, 0, true);
}
private function levelCompleteHandler(e:LevelEvent) : void {
removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
}
the first line to throw a 1009 error (Cannot access a property or method of a null object reference) is the line containing stage.mouseX because the stage reference is null.
public class Bee extends MovieClip {
public function Bee() {
this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
}
private function addedToStageHandler(e:Event) : void {
this.removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
this.x = this.stage.stageWidth / 2;
this.y = this.stage.stageHeight - this.stage.stageHeight / 9;
this.addEventListener(Event.ENTER_FRAME, enterFrameHandler, false, 0, true);
}
private function enterFrameHandler(e:Event) : void {
if(stage == null){
trace('stage is null' + stage.mouseX);
}
}
}
When the swf is first opened and a new WeeBeeGame is created its children have references to the stage. But when WeeBeeGame and it's children are removed from the display list and memory they lose reference and even if they're re-instantiated their references are still lost. How do I fix this? I'm very confused. Thank you all!!
ENTER_FRAME handlers continue to execute even when the display object is removed form the stage. So when you removeChild(weeBeeGame) those ENTER_FRAME handlers are still trying to access stage.mouseX each frame. You need to stop the ENTER_FRAME handlers.
Probably the easiest fix is to add an Event.REMOVED_FROM_STAGE handler to remove the Event.ENTER_FRAME handlers.
A better fix IMO is to not add any ENTER_FRAME handlers from your game objects, but rather expose a public function like update() which gets called from a single ENTER_FRAME handler in your WeeBeeGame when the game is running. Then to stop the game completely you can stop all updates by simply removing that single ENTER_FRAME handler. This is a common practice.

AS3 | 1120: Access of undefined property stage

My goal is to create rectangle as MovieClip with stage size, but Flash gives me this error: 1120: Access of undefined property stage. (on line 6,7,14)
My code:
package {
import flash.display.MovieClip;
public class main {
var mc_background:MovieClip = new MovieClip();
var stageW:Number = stage.stageWidth;
var stageH:Number = stage.stageHeight;
public function main() {
drawBackground();
}
public function drawBackground():void {
mc_background.beginFill(0xFF00CC);
mc_background.graphics.drawRect(0,0,stageW,stageH);
mc_background.graphics.endFill();
stage.addChild(mc_background);
}
}
}
i had a similar problem, the thing is, the stage hasn't really been setup yet, so you need to wait to get data from it or stuff in it. just add this:
protected function addedToStageHandler(event:Event):void
{
//do stuff
}
protected funcion init():void
{
addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
//more stuff
}
hope it helps
The stage property of an object isn't defined until the object has been added to the Stage or another object on the Stage.
The constructor of a class is called when the class instance is created, and that is before the instance could have been added to the Stage. So, you can't access stage within code you call from the constructor, or when you define the instance variables stageW and stageH.
To access the stage property as soon as the object is added to the stage, allow the object to handle the ADDED_TO_STAGE event:
package {
import flash.display.MovieClip;
import flash.events.Event;
public class main
{
var mc_background:MovieClip = new MovieClip();
public function main()
{
addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
}
private function addedToStageHandler(event:Event):void
{
// Generally good practice to remove this listener from the object now because it stops addedToStageHandler from being called again if the object is removed and added back to the stage or display list.
removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
drawBackground();
}
private function drawBackground():void {
mc_background.beginFill(0xFF00CC);
mc_background.graphics.drawRect(0,0,stage.stageWidth, stage.stageHeight);
mc_background.graphics.endFill();
addChild(mc_background);
}
}
}

AS3 How to add a Class on the stage from a timer?

lots of help from you guys :). My next question is here :).
I have timer in class MyTimer.as and Thief1_mc.as movie clip.
How can I addChild(Thief1_mc) on the stage from MyTimer? Everything looks simple, the only problem is "stage" property. MyTimer class cannot send "stage" as an argument because is not on the stage itself. I tried adding MyTimer on the stage in Main class like addChild (MyTimer), the trace says MyTimer is on the stage but I still cannot pass the stage argument to the Thief1_mc. I need this argument to be sent because the class Thief1_mc has to add itself on the stage using the property "stage".
The code:
public class Thief1_mc extends MovieClip
{
//this variable type Stage will contain stage
private var stageHolder:Stage;
public function Thief1_mc()
{
//constructor
}
//function that creates this object with passed "stage" argument from the caller
public function createItself(st):void
{
//variable that contain the stage so I can use this argument anywhere in the class
stageHolder = st;
//i have to refer to the stage by passed "st" parameter to create this object
stageHolder.addChild(this);
//initial position
this.x = 380;
this.y = 230;
}
}
}
MyTimer class and "_thief1.createItself(stage)" caller with stage arument
public class MyTimer extends Sprite
{
private static var nCount:Number = 120;
private static var currentCount:Number;
private static var _timer:Timer = new Timer(1000,nCount);
private static var _timerDispather:Timer;
private static var _thief1:Thief1_mc = new Thief1_mc ;
public function MyTimer()
{
// constructor code
}
//another timer
private static function increaseInterval(interval:int):void
{
_timerDispather = new Timer(interval);
_timerDispather.addEventListener(TimerEvent.TIMER, onUpdateTimeAnotherTimer);
_timerDispather.start();
}
//another timer;
private static function onUpdateTimeAnotherTimer(e:Event):void
{
_thief1.createItself(stage);//the most important part
}
public static function activateTimer():void
{
currentCount = nCount;
_timer.addEventListener(TimerEvent.TIMER, onUpdateTime);
_timer.start();
}
public static function deactivateTimer():void
{
_timer.removeEventListener(TimerEvent.TIMER, onUpdateTime);
_timer.stop();
_timer.reset();
currentCount = nCount;
//another timer
_timerDispather.removeEventListener(TimerEvent.TIMER, onUpdateTimeAnotherTimer);
_timerDispather.stop();
_timerDispather.reset();
}
private static function onUpdateTime(e:Event):void
{
currentCount--;
if (currentCount == 0)
{
_timer.removeEventListener(TimerEvent.TIMER, onUpdateTime);
_timer.stop();
_timer.reset();
}
}
}
}
Your code is backwards in a few places. It does not flow very nicely, and the issues you having now are going to be tenfold at some stage in your project.
Firstly, your MyTimer class should not be extending Sprite. It does not get rendered and does not represent anything graphically.
Secondly, your timer class is taking on more than it should. I would revise it to manage your timers and timer events only. Create a list within your timer class that will contain some other elements which can have a method triggers to do other stuff, like creating and adding Thief1_mc.
A simplified version of this might look like:
public class Updater
{
private var _timer:Timer;
private var _toUpdate:Vector.<IUpdatable> = new Vector.<IUpdatable>();
public function Updater()
{
_timer = new Timer(60);
_timer.start();
_timer.addEventListener(TimerEvent.TIMER, _notifyUpdatables);
}
private function _notifyUpdatables(e:TimerEvent):void
{
for each(var i:IUpdatable in _toUpdate)
{
i.update(this);
}
}
public function addUpdatable(updatable:IUpdatable):void
{
_toUpdate.push(updatable);
}
public function removeUpdatable(updatable:IUpdatable):void
{
var index:int = _toUpdate.indexOf(updatable);
if(index >= 0) _toUpdate.splice(index, 1);
}
}
From here we need to create an interface which we will implement on classes that we want to be able to call update() on each time the Updater timer ticks:
public interface IUpdatable
{
function update(updater:Updater):void;
}
Now what I would do in your case is have a class that does extend Sprite and manages the graphics of the application / game. It will implement the IUpdatable interface like I have described and also could deal with adding your Thief1_mc:
public class View extends Sprite implements IUpdatable
{
public function update(updater:Updater):void
{
// Create a Thief.
var thief:Thief = new Thief();
updater.addUpdatable(thief);
addChild(thief);
}
}
Your Thief can take advantage of the IUpdatable interface we have and be added to the update queue when it is created, as I've done above. Just to have a complete example, here's the Thief class:
public class Thief extends Sprite implements IUpdatable
{
public function update(updater:Updater):void
{
// Make this Thief so some stuff.
//
}
}
And here's how you can tie it all together in your document class:
public class App extends Sprite
{
private var _updater:Updater;
private var _view:View;
public function App()
{
_updater = new Updater();
_view = new View();
_updater.addUpdatable(_view);
stage.addChild(_view);
}
}
This might be a bit overwhelming at first, and seem like a lot of work, but you now have a nice clean foundation to add more elements easily.
Rather than having your one class trying to manage timers and add Thieves like you had initially, we've separated the responsibilities and tightened up the flow a little. The Updater deals purely with storing IUpdatable instances and calling their update() method each time the Timer within it ticks. The View class manages the graphics and will also add a Thief each time it is updated via the Updater. The View was added to the stage initially, so all you need to do is add the thieves into itself to have them show up.
If you take this and restructure how the timers work within Updater, I think you'll be where you wanted but with a significantly better understanding and structure.

AS3 reference custom property in a custom class for a library symbol

So I've done a fair amount of searching through SO and couldn't quite find the answer to this question. I have a movieclip in my symbol library that's exported for actionscript, and I've written a custom class for it. It mostly works great except for when I try to access a custom private property after I've added the movieclip to the stage. Below's an example:
package {
public class MyMovieClip extends MovieClip {
private var _isEnabled:Boolean = false;
public function MyMovieClip():void {
trace(this);
}
public function set isEnabled( b:Boolean ):void {
_isEnabled = b;
}
public function get isEnabled():Boolean {
return _isEnabled;
}
}
}
And then I have another class where I am adding instances of the movieclip to the stage in a loop:
package {
public class MyOtherClass extends MovieClip {
public var myMC:MyMovieClip;
public var docClass:*;
public function MyOtherClass( docRef:* ):void { // passing in a reference to the DocumentClass so I can access the stage
docClass = docRef;
init();
}
public function init():void {
for(var i:int=0; i<6; i++) {
var myMC:MyMovieClip = new MyMovieClip; // instantiate the movieclip which is exported for actionscript and has a custom class
//set a few native properties
myMC.name = "myMC" + i; //setting the name so I can reference this movieclip after it's been added to stage
myMC.y = myMC.height * i + 20;
myMC.x = 20;
myMC.alpha = .7;
}
dispatchEvent(new Event(MyOtherClass.MOVIECLIPS_ADDED)); // just to be safe, let's dispatch a custom event when all movieclips have been added
}
public function traceEnabled():void {
trace(docClass.stage.getChildByName("myMC1").isEnabled); // this throws: 1119: Access of possibly undefined property isEnabled through a reference with static type flash.display:DisplayObject
}
}
}
And finally I instantiate MyOtherClass inside my document class:
package {
public class DocumentClass extends MovieClip {
public var myOtherClass:MyOtherClass;
public function DocumentClass():void {
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
public function onAddedToStage(e:Event):void {
myOtherClass = new MyOtherClass(); // upon instantiation, init is called in MyOtherClass and all of my movieclips are added to the sage
}
}
}
What gives? Why can't I access the MyMovieClip property, isEnabled, after it's been added to the stage? Is there another way? (Thanks in advance for any help)
Internally all children of a DisplayObjectContainer are referenced as DisplayObject, so when you use getChildByName, it returns a DisplayObject.
In order to access your custom properties without causing a compile-time error, you would need to cast the result of getChildByName as the Class of your custom properties. See the code below.
That however isn't your only issue (though it's the reason for the error, once you correct you will get runtime errors as well).
In your creation loop, your not adding myMC to the display list, so calling stage.getChildByName() will return null because your clips aren't on the stage.
Your also not adding your myOtherClass to the display list in the posted code.
Also, storing a reference to the document class isn't really needed. Just add the addedToStage listener in MyOtherClass and have the handler be init.
HERE IS SOME UPDATED CODE
For your MyOtherClass:
public function MyOtherClass():void {
if(stage){
init(); //if stage is ready, call init, if not wait for the added to stage event
}else{
addEventListener(Event.ADDED_TO_STAGE,init);
}
}
public function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE,init);
for(var i:int=0; i<6; i++) {
var myMC:MyMovieClip = new MyMovieClip;
myMC.name = "myMC" + i; //setting the name so I can reference this movieclip after it's been added to stage
myMC.y = myMC.height * i + 20;
myMC.x = 20;
myMC.alpha = .7;
addChild(myMC); //!!!! add to the displayList
}
dispatchEvent(new Event(MyOtherClass.MOVIECLIPS_ADDED)); // just to be safe, let's dispatch a custom event when all movieclips have been added
}
public function traceEnabled():void {
var myMC:MyMovieClip = this.getChildByName("myMC1") as MyMovieClip; //!!! cast it as MyMovieClip so you have access to all the properties/methods in that class
if(myMC){ //myMC will be null if the cast failed
trace(myMC.isEnabled);
}
}
/*
getChildByName is slow and cumbersome. Most people generally only use it for accessing things put on the timeline in the Flash IDE. Using events is a much better way of accessing your items. If traceEnabled was caused by a mouse event attached to myMC, then this would be a much better implementation:
*/
public function betterTraceEnabled(e:Event):void {
var myMC:MyMovieClip = e.currentTarget as MyMovieClip;
if(myMC){
trace(myMC.isEnabled);
}
}
AND YOUR DOCUMENT CLASS:
public class DocumentClass extends MovieClip {
public var myOtherClass:MyOtherClass;
public function DocumentClass():void {
if(stage){
onAddedToStage(null); //most of the time stage is already populated in the constructor of your document class
}else{
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
}
public function onAddedToStage(e:Event):void {
myOtherClass = new MyOtherClass(); // upon instantiation, init is called in MyOtherClass and all of my movieclips are added to the sage
addChild(myOtherClass); //add it to the displayList
}
}