Remove Child created by class as3 - actionscript-3

I've been learning AS3 for a class project for just over a few months, most of what I know is by looking at how others problems were solved on here.
To the point.
I've got a class called Generate so I import that to my main timeline, in that class it creates a child and adds it.
Now I can't figure out how to remove it, it always says it's null:
"TypeError: Error #2007: Parameter child must be non-null."
package {
import MonsterOne;
import MonsterTwo;
import MonsterThree;
import MonsterFour;
import flash.display.*;
public class Generate extends MovieClip{
public static var monsterID = String(monsterID);
monsterID = Math.ceil(Math.random() * 4).toString();
public function Generate(parent:Object){
if (monsterID == 1){
var monsOne:MonsterOne = new MonsterOne();
monsOne.name = "monsterOne";
parent.addChild(monsOne);
monsOne.x = 100;
monsOne.y = 200;
trace("spawn1");
}
This is how it's generated. There is a little more code for monsTwo, three and four. Same code different names. That's all that is in the file.
I've tried all sorts to remove the code but always with an error and no actual removal of the child.
stage.removeChild(monsOne);
monsOne.parent.removeChild(monsOne);
removeChild(monsOne);
And who knows how many others.
Am I missing something or just doing it completely wrong.
Thank you
--EDIT--
if(o.monHP <= 0) {
turnTimer.stop();
turnTimer.removeEventListener(TimerEvent.TIMER, CounterA);
var monsOne:MovieClip = getChildByName('monsterOne') as MovieClip;
var monsTwo:MovieClip = getChildByName('monsterTwo') as MovieClip;
var monsThree:MovieClip = getChildByName('monsterThree') as MovieClip;
var monsFour:MovieClip = getChildByName('monsterFour') as MovieClip;
parent.removeChild(monsOne);
parent.removeChild(monsTwo);
parent.removeChild(monsThree);
parent.removeChild(monsFour);
gotoAndStop('win');
}
How I'm trying to remove the child.
package {
import MonsterOne;
import MonsterTwo;
import MonsterThree;
import MonsterFour;
import flash.display.*;
public class Generate extends MovieClip{
public static var monsterID = String(monsterID);
monsterID = Math.ceil(Math.random() * 4).toString();
public function Generate(parent:Object){
if (monsterID == 1){
var monsOne:MonsterOne = new MonsterOne();
monsOne.name = "monsterOne";
parent.addChild(monsOne);
monsOne.x = 100;
monsOne.y = 200;
trace("spawn1");
}
if (monsterID == 2){
var monsTwo:MonsterTwo = new MonsterTwo();
monsTwo.name = "monsterTwo";
parent.addChild(monsTwo);
monsTwo.x = 100;
monsTwo.y = 200;
trace("spawn2");
}
if (monsterID == 3){
var monsThree:MonsterThree = new MonsterThree();
monsThree.name = "monsterThree";
parent.addChild(monsThree);
monsThree.x = 100;
monsThree.y = 200;
trace("spawn3");
}
if (monsterID == 4){
var monsFour:MonsterFour = new MonsterFour();
monsFour.name = "monsterFour";
parent.addChild(monsFour);
monsFour.x = 100;
monsFour.y = 200;
trace("spawn4");
}
}
}
}
Full Generate File

There's so many things wrong with your code that it's not easy to know where to begin. You lack very basic understanding of the display list and most important scope.
Display List:
when you do something like this:
var monsOne:MovieClip = getChildByName('monsterOne') as MovieClip;
parent.removeChild(monsOne);
That can be translated to "no idea what I'm doing here". Why? Because the code means it expects a DisplayObject named "monsterOne" to exist in the display list of "this" (the display list in scope) and then tries to remove that object from "parent". None of this makes sense, if the object exist in display list A then remove it from display list A not from display list B.
Programming:
You are using variable and parameters that mirror existing properties, ex: "parent". Are you sure at your level of programming you can afford to confuse yourself with that kind of dangerous programming behavior? The answer is no, don't mirror properties names.
Scope:
You keep losing scope all over the place but keep writing code like scope doesn't even exist. Stop that. A variable named monsOne in one scope doesn't exist in any other scope, period.
More weirdness:
public static var monsterID = String(monsterID);
monsterID = Math.ceil(Math.random() * 4).toString();
You do not know what this does obviously or else you would not do it that way.
What does your code do?:
It creates one and one only movieclip type and each time it creates it it gives it the exact same name and add it to a phantom "parent" we know nothing about. Then when you try to remove it you don't even know or remember what this phantom parent is and you can't really use getChildByName() either cos you need to know the parent in order to do that and even worse by then so many MovieClip might be there and all have the same name.
How to fix?
This section will be filled later as you ask specific questions on how to fix what.

The Generate class generates only one monster. In the gameOver function you are trying to remove all 4 monsters and you get an error that the monster doesn't exist. You should add condition:
if (monsOne) removeChild(monsOne);
if (monsTwo) removeChild(monsTwo);
if (monsThree) removeChild(monsThree);
if (monsFour) removeChild(monsFour);

Related

Referring to a variable in the target file from a class AS3

I've researched this all day and I'm stuck! I want to know how to use a variable from a target path to move something. Here is the code:
// Target file
var speed:int = Number(1);
var container:MovieClip = new MovieClip;
var objects:Objects = new Objects();
container.addChild(objects);
and
// Class for Objects
package {
import flash.display.MovieClip;
public class Objects extends MovieClip {
public function Objects() {
this.x += speed;
trace(this.x);
}
}
}
When I run it, I get an error like this:
Objects.as, Line 6 1120: Access of undefined property speed.
Thanks!
The most simple way to do it is to pass the speed variable to that class. See, classes are like stand alone objects in the space, and they (mostly) don't know about each other, or at least they don't know about the variables that you define in them.
So if you create a class inside another one (new Objects()), the most easy way is this:
var objects:Objects = new Objects(speed);
Then, inside Objects class, you will have:
public class Objects extends MovieClip {
var _speed:Number;
public function Objects(speed:Number) {
_speed = speed; // save it to a local member variable
this.x += _speed;
// start working with the local one,
// which will be accessible in the whole class
}
It's like passing some defined values, so that class can use them. And the class saves them inside itself so it can be used through the whole file (scope).

AS3 using addChild() with a variable taken from a XML

I made a function that would add a child from my library using a variable made from an xml.
var ChosenGraphic:String = units.unit.(#titel==k1).graphic;
var mc:MovieClip = new ChosenGraphic;
addChild(mc);
I know I can't use :String for this, but I don't have a clue what to use. I'm trying to get it to work for 2 hours now, and it's getting really frustrating.
Everything else works, I've tested that.
You want to use the getDefinitionByName() top level function.
Below is an example of using it, lifted straight from the documentation that I linked to. Note that the class name string must be the fully qualified class name (ie: it includes the package name as well as the class).
package {
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.utils.getDefinitionByName;
public class GetDefinitionByNameExample extends Sprite {
private var bgColor:uint = 0xFFCC00;
private var size:uint = 80;
public function GetDefinitionByNameExample() {
var ClassReference:Class = getDefinitionByName("flash.display.Sprite") as Class;
var instance:Object = new ClassReference();
instance.graphics.beginFill(bgColor);
instance.graphics.drawRect(0, 0, size, size);
instance.graphics.endFill();
addChild(DisplayObject(instance));
}
}
}

as3 - passing a library image name to function which then adds to stage

I'm using the following function to add some images from the library to the stage.
function AddImage(image_name:String):void {
if(image_count == 4) return;
// change the following line so it uses "image_name"
var defaultImage:added_1 = new added_1(100, 100);
var tmpImage:Bitmap = new Bitmap(defaultImage);
tmpImage.x = 124.5 + (108.5 * image_count);
tmpImage.y = 1511.9;
addChild(tmpImage);
image_count++;
}
What I'd like to be able to do is pass the image name as a string parameter to the function but can't seem to figure out how to do this.
Can someone help me out?
What you want to do is get the Class Definition via using getDefinitionByName so that you can create an instance, the following code is how you do that :
// you'll need to add this import to use getDefinitionByName
import flash.utils.getDefinitionByName;
function AddImage(image_name:String):void {
if(image_count == 4) return;
// this next line gets the class definition of the image_name
var imageClass:Class = getDefinitionByName(image_name) as Class;
// this is how you create an instance of that class
var defaultImage:BitmapData = new imageClass(100, 100);
var tmpImage:Bitmap = new Bitmap(defaultImage);
tmpImage.x = 124.5 + (108.5 * image_count);
tmpImage.y = 1511.9;
addChild(tmpImage);
image_count++;
}
The changes are the import :
import flash.utils.getDefinitionByName;
and these two lines :
var imageClass:Class = getDefinitionByName(image_name) as Class;
var defaultImage:BitmapData = new imageClass(100, 100);
Note ---
Also wanted to mention that in certain cases you might run into an issue if you are compiling with Flex as opposed to the Flash IDE, where you get the following error :
ReferenceError: Error #1065: Variable <YourImageClassName> is not defined.
The way to handle that situations is by declaring a variable in your class variable declarations for the compiler, so it recognizes that symbol.
So if your two images class names were image_1 and image_2, in your class declarations you would do something like :
private var forCompiler1:image_1;
private var forCompiler2:image_2;
If you have a ton of images, that might be a pain, but that's the only way I've found to get the compiler to recognize them. :/ haha

Noob AS3 question regarding using event handlers to remove MovieClip object from stage

I'm an AS3 noob just trying to get more comfortable working with event handlers in Flash and build interactivity into my application.
In the code below, I have created an instance of the DrawLineChart class called LineChart1. When I test the movie, it shows up on the stage just fine and when I click on it, I can use a trace command to get a string statement written to the output window.
However, now I want to be able to click on LineChart1 on the stage and have it be removed. When I do that, I get an error message 1120: Access of undefined property LineChart1.
Could someone please explain to me why I'm unable to refer to my instance LineChart1 and what I need to do so that I can refer to it and remove it when it gets clicked? Also, I'd love to know why the trace statement works when I click on LineChart1 during runtime, but not the removechild command.
I'm sorry if this question is too simple, but thank you all for your help in advance. I really appreciate it.
package{
import flash.display.*;
import flash.events.*;
public class Main extends MovieClip{
var recWidth:Number = 250;
var recHeight:Number = 550;
var recX:Number = 50;
var recY:Number = 50;
var recScaleY:Number = 30;
public function Main(){
var LineChart1 = new DrawLineChart(recX, recY, recWidth, recHeight, recScaleY);
LineChart1.addEventListener(MouseEvent.CLICK, onClickHandler);
addChild(LineChart1);
}
function onClickHandler(e:Event):void{
trace("hello"); // This works. When I click on the LineChart1 MovieClip on the stage during runtime, I get "hello" as an output.
removeChild(LineChart1); // throws an error 1120: Access of undefined property LineChart1. Why?
}
}
}
Your variable is scoped locally to Main, you need to declare it as an instance variable (class level), to properly define its scope.
private var _lineChart1:DrawLineChart;
//main function
_lineChart1 = new DrawLineChart(...
//handler function
this.removeChild(_lineChart1);
For more information about scope in AS3 = check out the livedocs.
Cheers
Your problem is that you have defined LineChart1 as a local variable. This means that because you declare it inside a function, it is only visible within that function.
Make LineChart1 a property of your class, then you will be able to see it from your event handler. Alternatively, use e.target as DrawLineChart.
All answer's is good but if u have more then one on the stage what can u do ?
You can use an Array to take a list of your mc's and then u can use that Array to remove mc's on the stage.
Here is a Simple Example:
package
{
import flash.display.*;
import flash.events.*;
public class Main extends MovieClip{
private var recWidth:Number = 250;
private var recHeight:Number = 550;
private var recX:Number = 50;
private var recY:Number = 50;
private var recScaleY:Number = 30;
private var lineArray:Array = new Array();
public function Main()
{
for(var i:int = 0;i<10;i++)
{
var LineChart1 = new DrawLineChart(recX, recY, recWidth, recHeight, recScaleY);
LineChart1.addEventListener(MouseEvent.CLICK, onClickHandler);
LineChart1.name = line+i.toString(); // u can use whatever u want for name's
lineArray.push(lineChart1);
addChild(LineChart1);
}
//if u want to place this 10 LineChart1 u can set x and y values like recX += recX and ect.
}
private function onClickHandler(e:Event):void
{
//when u click one of your LineChart1 and want to remove it from stage u can use this
trace(e.currentTarget.name); // if u want to see what is the name of ur mc
var myId:String = e.currentTarget.name.substring(4,10);
removeChild(getChildByName("line"+myId));
}
}
hope it works for u

Actionscript 3: Array Scope in a Document Class

I have the following function to set up cards in a game. I created one array to hold the kind of cards, and another array to hold the position of the cards.
private function setPlayerCard(cardNumber:int, cardPos:int):void{
for (var i:int = 1; i < _CardGridInstance.numChildren+1; i++) {
var _position:MovieClip = MovieClip(_CardGridInstance.getChildByName("Position_" + i));
cardPositions[i] = _position;
cardPositions[i].pos_name.text = "position" + i;
cardPositions[i].id = ["pos"+i];
}
for (var j:int = 1; j < numCards+1; j++) {
var _c:Class = getDefinitionByName("Card_" + j) as Class;
var _cardInstance:MovieClip = new _c();
cards[j] = _cardInstance;
}
cards[cardNumber].x = _CardGridInstance.x + cardPositions[cardPos].x - 1;
cards[cardNumber].y = _CardGridInstance.y + cardPositions[cardPos].y;
addChild(cards[cardNumber]);
}
So if I want to set the card number "3" in position "5" I just write:
setPlayerCard(3,5);
The problem I can see is that every time I'd like to place a card, I am creating two arrays every time. I would like to make the arrays "global" (i.e. create it in my constructor in my document class) and reuse it in the function "setPlayerCard" however I am getting errors when I try to do so.
Any suggestions?
This is a perfect case for a Singleton static class data model. You can get the instance of the Singleton from throughout the application as it is a static class, and it can contain the two arrays without duplication.
pixelbreaker has a nice basic Singleton AS3 example that you can build from.
It's a little difficult to answer accurately without knowing how you are creating the variables and what errors you're getting. Can you post the entire class and the errors?
I can, however, recommend that you do not use the Singleton pattern. This is not a perfect case for a Singleton. The Singleton pattern has no place in OOP, it's procedural programming wrapped up like OO, but that's an argument for elsewhere.
This is, though, a perfect case for a class level variables. The following is a simple example. There are a few missing variable declarations though (numCards), as I don't know where you're creating and setting them.
package{
import flash.display.Sprite;
public class CardGame extends Sprite{
private var cardPositions:Array = new Array();
private var cards:Array = new Array();
public function CardGame(){
for var i:uint = 1; i <= _CardGridInstance.numChildren; i++) {
var position:MovieClip = MovieClip(_CardGridInstance.getChildByName("Position_" + i));
cardPositions[i] = position;
cardPositions[i].pos_name.text = "position" + i;
cardPositions[i].id = ["pos"+i];
}
for(i = 1; i <= numCards; i++) {
var c:Class = getDefinitionByName("Card_" + i) as Class;
var cardInstance:MovieClip = new c();
cards[i] = cardInstance;
}
}
private function setPlayerCard(cardNumber:uint, cardPos:uint):void{
cards[cardNumber].x = _CardGridInstance.x + cardPositions[cardPos].x - 1;
cards[cardNumber].y = _CardGridInstance.y + cardPositions[cardPos].y;
addChild(cards[cardNumber]);
}
}
}
This way you only create and populate the arrays once and you can access them from anywhere within the CardGame Class. They are not global but they are within the scope of the setPlayerCard method.
You may get errors as objects might not be instantiated when the Document Class' constructor gets called, but that can be worked around.
What is the need for the variable to be public and static?
Static means that the variable is on the Class, not instances of the Class. So every "CardGame" instance will share the same static variable. I presume, because this is the Document Class, that you will not have more than one instance of it. So there is no reason for that.
The only other reason, because you declared it public, is to make the variable accessible from outside the Class through CardGame.cardPositions. This is bad practice as you shouldn't allow other objects to directly manipulate a Classes internal data. That breaks encapsulation. Since this is the Document Class and the top of the hierarchy, you should pass a copy of the data to whichever object needs it and wait for an event to retrieve the updated data. That way you can sanitise the data before using it and you're not just blindly trusting other objects to respect your data.
http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming)
I tried using the Singleton class, but since I had to reference MovieClips that were already on the display list, I opted for a different solution from "Actionscript 3 Tip of the Day":
http://www.kirupa.com/forum/showthread.php?p=2110830#post2110830
package {
public class ClassName {
public static var myArray_1:Object = new Object;
public static var myArray_2:Object = new Object;
public function ClassName() {
//constructor
Whatever();
DoStuffWithWhatever();
}
private function Whatever() {
// put stuff into the array here
}
private function DoStuffWithWhatever():void {
// do stuff with the array values here.
}
}
}