How to remove the child inside movieclip - actionscript-3

I have a MovieClip on stage named scenePage, and a MovieClip named char_panel which consists of character MCs. One of these is the char1_mc.
When I clicked on char1_mc, this create a new instance(newChar), adding a child in scenePage. I also have a button named btn_remove on stage that should removes the newChar on scenePage when clicked. The problem is, the child(newChar) inside the scenePage does not removes when I clicked the button.
I tried using
scenePage.removeChild(newChar);
But it gives me an error saying, "Parameter child must non-null." Is there any other way to access the instance inside the scenePage? I really need to have access on the child on scenePage.
Here's the script inside char_panel where the char1_mc is, character1 is the class name of char1_mc after I exported it for AS3:
import flash.display.MovieClip;
var newChar: MovieClip;
char1_mc.addEventListener(MouseEvent.CLICK, showChar1);
function showChar1(e:MouseEvent):void
{
newChar = new character1();
newChar.height = 215;
newChar.width = 220;
newChar.x = 20;
newChar.y = 202.60;
MovieClip(root).scenePage.addChild(newChar);
}
And this is the script for btn_remove which is in the main timeline.
btn_remove.addEventListener(MouseEvent.CLICK, remove_character);
function remove_character(e:MouseEvent):void
{
scenePage.removeChild(newChar);
}
Thanks in advance :)

Your issue is one of scope.
The main timeline and your char_panel have different scopes. This means vars in one are not available in the other.
To get to newChar from the main timeline, you'll have to drill down to the appropriate scope.
Let's assume char_panel is the instance name of an object on the main timeline. If so, you'd have to do this on your main timeline code:
scenePage.removeChild(char_panel.newChar);
Which is saying "remove the newChar object that is part of the char_panel scope"

Related

How do I access dynamic text on the stage from inside a movieclip which is inside another moveclip in AS3?

Before asking, I've read other articles for similar issues and have not been able to get it working. I have a dynamic text on the stage with the instance name of txtX. Then in action script in frame 1 of the main timeline I add an existing movie clip, mc1, using code:
var mc = new MC();
addChild(mc);
I then add another movieclip, mc2, with action script on frame 1 of the main timeline I add it as a child to mc1.
var mc2 = new MC2();
mc.addChild(mc2);
Now, in the class (created class for export AS) for mc2 I am trying to modify the text of the dynamic text but cannot for the life of me figure out how to reference it. I want to say:
stage.txtX.text = "blah blah";
or even
parent.parent.txtX.text = "blah blah";
but I usually get an error similar to:
Access of possibly undefined property txtX through a reference with static type flash.display:DisplayObjectContainer.
The error above is for the parent.parent.txtX.text line. Please tell me what I'm doing wrong. Thanks. Also I know that the variable names are nonsensical but it's just for my example. In my code the names make much more sense.
When you put a text field on your main timeline and give it an instance name of txtX, it actually is not a direct child of stage. The stage would be it's grandparent (the main/root timeline would be it's parent).
As such, if mc1 & mc2 are it's siblings (also on the main timeline), you could access your text field like so:
MovieClip(parent).txtX.text = "Hello";
Alternatively, you can access the root (main) timeline with the root keyword:
MovieClip(root).txtX.text = "Hello";
And that should work on any timeline no matter how deep/nested.
I figured it out finally. Not sure if it was the correct way to do it but in the parent MoveieClip, I created a TextField in code:
import flash.text.TextField;
import flash.text.TextFormat;
public var txtX:TextField;
txtX = new TextField(); txtX.x=0; txtX.y=0; addChild(txtX);
public function changeTxt( t )
{
tf = new TextFormat();
tf.size=4;
tf.color = 0xFFFF00;
txtX.text = t;
txtX.setTextFormat(tf);
}
Then in my MovieClip child class I called the parent's method like this:
MovieClip(parent).changeTxt( "Hello" );
A lot more work than I'd hoped for but it seems to work.

Dynamically Loading a Movie Clip AS3

I'm trying to add a movie clip to the stage dynamically. In the library of the main .fla I have a movie clip called "menuBar". I have a class called menuBar.as with the following code:
package
{
import flash.display.MovieClip;
public class menuBar extends MovieClip
{
public function menuBar()
{
var menuBar:MovieClip = new MovieClip ;
stage.addChild(menuBar);
menuBar.x = 319.9;
menuBar.y = 10.4;
}
}
}
The class path is set correctly, but I'm stuck at this point. I don't know how to get the movie clip onto the stage. Thanks in advance for any help.
In the library you have to go to the properties of your clip menuBar and export it for actionscript, just check the corresponding case, in class name field enter MenuBar for exemple. Check the export in frame 1 option too. After that, anywhere in your code you can create a MenuBar with this code:
var myMenuBar:MenuBar = new MenuBar();
addChild( myMenuBar );
if you enter as class name MyOtherItem you could create it with this code:
var myItem:MyOtherItem = new MyOtherItem();
addChild( myItem );
Hope this helps
PS: try using capital letter for first letter of class names and lowercase letter for first name of variables name it's more clear for everyone. (ex: MyClassName, myVarName)
You should do the other way. You are trying to make menuBar class to add itself to stage, but the stage is only known to Main, not menuBar. You should declare a variable in the Main class, on the timeline or elsewhere, and then you add that one to stage.
// timeline code. Put this in Main
var menubar:menuBar=new menuBar(); // declare
menubar.x=320;
menubar.y=10; // position
addChild(menubar); // add
The menuBar constructor should remain empty, as you are apparently designing your menu bar in the Flash CSx editor.
Also note that you might not need to add your menu bar to stage, you can easily just add it to the main class addChild(menubar) instead of stage.addChild(menubar).

AS3 Add event listener to a movieclip within a movieclip

I currently have two movieclips one called mcInvFrame, and one called btnCloseInv (It is a movieclip, and I know the naming convention is wrong). btnCloseInv is located inside mcInvFrame. I have two files Inventory.as and my main document class. I can load the mcInvFrame just fine to the stage and everything works as expected. However when I try to access the btnCloseInv movieclip i get errors. Here is the code for Inventory.as I have commented out my most recent failed attempt
package{
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class Inventory extends MovieClip
{
public var inv:MovieClip = new mcInvFrame;
public function Inventory()
{
addChild(inv);
/*var invClose:MovieClip = inv.btnCloseInv;
invClose.addEventListener(MouseEvent.CLICK, CloseInventory);
function CloseInventory($e:MouseEvent):void
{
this.parent.removeChild(inv);
}*/
}
}
}
What I need to know is can/should i create a variable within inventory.as for the button that I can access from the main document? If so how?
P.S. I have been searching the forums and trying various solutions but I either didn't understand the implementation or they were not suitable for this situation. The most common error I receive is "Error #1009: Cannot access a property or method of a null object reference." Occasionally I will receive an error stating that an object has no properties.
you cant register event on stage.movieclip.movieclip2 , i have tried to do the same thing before, but it wont work, try to create btnCloseInv outside, then use this code
btnCloseInv.x = mcInvFrame.x + numberHere;
btnCloseInv.y = mcInvFrame.y + numberHere2;
if you doesn't want to use this code, AS3 - Button inside MovieClip triggers MC's event
EDIT: if you set mcInvFrame.buttonMode = true it will not work

How do you access script on your ActionScript class from inside a movie-clip?

I want to be able to access a private var from inside a movieclip, does anyone know how I would go about doing that?
I want to be able to access my public function counter(numPoints:int) that is inside the ActionScript class file from inside a movieclip on my main swf. Whenever I try to access it, it comes up as undefined, but how to access it from inside the movieclip is the problem(I know the variables are all defined properly because it works when it isn't inside of a movieclip). Any idea are appreciated ^^;, Thanks!
unlock3.addEventListener(MouseEvent.CLICK, fl_ClickToGoToAndStopAtFrame_3);
function fl_ClickToGoToAndStopAtFrame_3(event:MouseEvent):void
{
MovieClip(parent).gotoAndStop(8);
addScore(1);
}
I want to make it so the addScore function works properly, but it always comes out undefined. This script here is inside of the movieclip. The navigation works fine, but I don't know how to target the score.
It's still unclear what exactly you are doing, your function is named counter but you are calling addScore. See if this helps.
In your document class (lets assume it is called Main) you would have something like:
private var _currentScore:int;
public function addScore(scoreToAdd:int):void
{
_currentScore += scoreToAdd;
trace("New Score: "+_currentScore);
}
Then within your object class which extends MovieClip you would have:
function fl_ClickToGoToAndStopAtFrame_3(event:MouseEvent):void
{
Main.addScore(1);
}

Stage and classes

I am new to AS3 and am trying to lean its OOP ways. What I am having problems with is understanding how to access the stage with separate classes.
Here is an example of what I am trying to do:
package game{
import flash.display.*;
public class Main extends MovieClip{
function Main(){
var player = new Player();
var playerBullets = new playerBullet();
addChild(player.players);
}
}
package game{
import flash.display.*;
public class Bullet extends Main // also tried with MovieClip and Sprite{
function Bullet(){
// empty
}
function blah(){
var someSprite = new someSprite();
Main.addChild(someSprite);
stage.addChild(someSprite);
root.addChild(someSprite);
}
}
}
I have Omitted another class which calls the blah method as I feel it is not relevant.
Basically what I want to know is how to add things to the stage in classes as it lookes like I am missing something crucial.
*EDIT TO INCLUDE ERROR*
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at game::Bullet/blah()
at game::Player/fire()
You shouldn't necessarily be extending main to create something like a bullet class, this can be it's own class that extends Sprite or MovieClip. The stage object is considered a global object, as it is a singleton (except in the case of Adobe AIR where you can have one stage per NativeWindow that you spawn). So any object that extends DisplayObject or has DisplayObject in it's inheritance chain will by default have a reference to the stage via a getter, which is populated automatically when a displayObject is added to the display list. This can happen by either adding a clip directly to the root stage object or by adding a clip as a child of another clip, that eventually connects to the stage. For example:
var clip1:MovieClip = new MovieClip();
stage.addChild(clip1); //Clip 1 can now access the stage reference internally.
ver clip2:MovieClip = new MovieClip(); //Right now, clip2 cannot access the stage reference interally.
clip1.addChild(clip2); //Now clip2 can access the internal stage reference because it has been connected to the display list through clip1.
The other mistake people make is accessing stage within a DisplayObject typed class (such as your Main class) without first ensuring that the object itself has been added to the stage. You do this by listening for the Event.ADDED_TO_STAGE event within the constructor of the class, like so:
public class Main extends MovieClip{
function Main(){
if(stage){
//The stage reference is present, so we're already added to the stage
init();
}else{
addEventListener(Event.ADDED_TO_STAGE, init);
}
var player = new Player();
var playerBullets = new playerBullet();
addChild(player.players);
}
private function init(e:Event = null)
{
trace("Added to stage, the stage reference is now populated and stage can be accessed");
}
}
This could be the problem you're having, but it's hard to say since you have not specified any errors. However, this is likely an issue or will be for you, since it's quite common. Inside the init() method you can then set a flag so that when external classes call your Main.blah() method, you can ensure that the stage reference exists before attempting to add something to the stage. Take note however that within your Main class when you simply say:
addChild(someChild);
or
this.addChild(someChild);
you're not adding that child to the stage, but rather to the Main object, which is a MovieClip or Sprite based object that is itself attached to the stage automatically when you set it as the Document class. Hope this info helps.
Update
To explain the display list a little more:
Think of all your movieclips as dishes, and the stage as the table. You can only access the table from the dish, if the dish is placed directly on the table, or if a dish is stacked on top of another dish that touches the table. If you have 10 plates stacked on top of each other, they all touch the table eventually, via their connection to each other. This is essentially a visualization of the flash display list. The way you put dishes on the table is by using addChild(dish). If you have not placed an object somewhere on the table, and try to access the table from that object, you're going to fail. You're getting the "access to undefined" error because you're calling the "blah()" method, which accesses the stage (table) before the bullet (dish) has been added to the stage (table). So you must first either directly add the bullet to the stage, or add it to another object that has already been added to the stage. Change your code like so:
var myBullet:Bullet = new Bullet();
stage.addChild(myBullet);
//Or, if this class, assuming it's the player class, has already been added to the stage, just do this:
this.addChild(myBullet);
myBullet.blah();
Even so, you should still have some error checking within your "blah" method to ensure that the stage is available:
function blah(){
var someSprite = new someSprite();
if(stage){
Main.addChild(someSprite);
stage.addChild(someSprite);
root.addChild(someSprite);
}else{
trace("error, stage not present");
}
}
However you should also note that by adding this child to Main, then stage, then root all in sequence, this does not duplicate the someSprite object. When you add a display object to a new parent object, the object is automatically pulled from it's current parent and moved to the new one. So all this code will do is eventually add someSprite to root, which I believe will fail because root is not a display object, but rather a global reference mainly used to access global objects such as the stage and the Loader object used to load the SWF.
You shouldn't ever be calling stage.addChild. There should be only one child of the Stage, and that's the document class.
You make a MovieClip display on the screen by adding it to the stage's display list.
Stage
+ Main Timeline
+Anything
+Else
+You
+Want
So assuming that Main is your document class for the main timeline...
// inside of Main's constructor...
public function Main(){
var anything:MovieClip = new MovieClip();
var Else:TextField = new TextField();
var you:SimpleButton = new SimpleButton();
var want:Sprite = new Sprite();
this.addChild(anything);
this.addChild(Else);
this.addChild(you);
this.addChild(want);
}
Then in order to add children even lower, for example if you want something to be a child of "Anything" such that you have....
Stage
+ Main Timeline
+Anything
+And
+Everything
+Else
+You
+Want
public function Main(){
var anything:MovieClip = new MovieClip();
var Else:TextField = new TextField();
var you:SimpleButton = new SimpleButton();
var want:Sprite = new Sprite();
this.addChild(anything);
this.addChild(Else);
this.addChild(you);
this.addChild(want);
var And:Sprite = new Sprite();
var everything:Sprite = new Sprite();
anything.addChild(And);
anything.addChild(everything);
}
EDIT: Ascension Systems asks why you should never add any display object directly as a child of the stage. The simplest answer is that you can't ever guarantee that what you believe you're creating as a document class, or as a main timeline in fact actually is going to be used as such. Your use of the stage may later preclude your swf from being loaded as a child of a larger application depending on what it is you've done, exactly. Relying directly on the stage can mean that you're making some assumptions about the nature of the display list that may not hold in the future. That's the way in which it breaks modularity (which is not the same as breaking oop).
Why add to the stage when you could just create your entire application as a MovieClip that is completely self-contained with no reliance on the concept of a "stage" beyond that which is required for learning world coordinates? That way you can be much more modular in your design and you sacrifice nothing.
In some people's work this may be considered an edge case. In my work this has happened both to me when I've created applications that I thought at the time were purely stand-alone that ended up being repurposed later to be a module, and also to swfs that other people created that were intended to be strictly stand-alone, but that I was then to integrate as a module into a larger application. In all cases there were some nasty side effects to contend with. That's where I learned not to rely too closely on the stage for much beyond world coordinates.
Every display object has a property called stage, which is null until that object is added to the display tree.
When you are unsure if an object has been added to the stage, there is a listener you can employ for that purpose:
public class Main extends MovieClip
{
import flash.events.Event;
public function Main():void
{
if(stage) {
init();
} else {
this.addEventListener(Event.ADDED_TO_STAGE,init);
}
}
private function init(evt:Event = null):void
{
this.removeEventListener(Event.ADDED_TO_STAGE,init);
//object is now definitely on the display tree
}
}
I'm gonna take a wild stab in the dark here.
stage is a property implemented something like so:
public function get stage():Stage {
var s:DisplayObject = this;
while(s.parent) s = s.parent;
return s as Stage;
}
root is very similar but stops a level below stage (root is a child of stage).
These properties only work when the object you're calling them on is on the stage somewhere. Doesn't matter where, because the while loop will walk up the hierarchy to get to the stage node at the top. But if it's not on the stage, then parent will be null.
So if your movieclip is not on the stage, then its reference to stage will be null. Same goes for root.
I'm guessing that you're calling blah before the bullets are added to the stage? In which case your call stage.addChild(someSprite) will be a Null Reference error (stage is null).
So you either need to add the bullets to stage first, or you need to pass stage in as a parameter:
function blah(s:Stage){
var someSprite = new someSprite();
s.addChild(someSprite);
}