-
Juvenile Delinquent
[RESOLVED] Array[i].gotoAndPlay("frame label") doesn't work
I have an array that contains the instance names of movieclips I want to reference. I'm using the following code:
PHP Code:
function onKeyPress(e:KeyboardEvent):void{ // THROW BOMB UPON PRESSING SPACE BAR if (e.keyCode == Keyboard.SPACE) { for (var i:int = 0; i < bombArray.length; i++) { bombArray[i].gotoAndPlay("bomb"); // problem line } } }
I only have 1 item in the array for testing purposes. When I trace bombArray I get enemy14. I changed the line to the following:
PHP Code:
enemy14.gotoAndPlay("bomb");
This is exactly the same thing and it works fine. Why does it not work if I reference the same instance name in the array? I get an error "TypeError: Error #1006: value is not a function.
at Untitled_fla::MainTimeline/onKeyPress()".
Anyone got any ideas?
Last edited by CVO Chris; 01-14-2011 at 11:40 AM.
-
Juvenile Delinquent
Nevermind, got it. I was adding items to the array using:
MovieClip(this.root).bombArray.push(this.name);
Taking out the .name fixed the issue:
MovieClip(this.root).bombArray.push(this);
Tracing the Array I get [object_Enemy_1] rather than the instance name. For some reason you can write the instance name in the code and it works but not reference it through the array.
As long as it works!
-
FK Romeo
The following would have worked.
Code:
function onKeyPress(e:KeyboardEvent):void{
// THROW BOMB UPON PRESSING SPACE BAR
if (e.keyCode == Keyboard.SPACE) {
for (var i:int = 0; i < bombArray.length; i++) {
this[bombArray[i]].gotoAndPlay("bomb"); // problem line
}
}
}
bombArray[i] returns the name of the movieclip as you said and is a string...so it wont play. When I write this[bombArray[i]]...I am playing a movieclip by providing a dynamic name.
sameer rao
there...you see!!
-
Juvenile Delinquent
That's far better, thanks Martiansam
-
No that is NOT better. Why would you think it's better to store a String, then look up the instance by property name instead of just storing the instance in the first place?
Also, that solution will break if the item you are looking for is not a property of "this". That could well be the case if it was dynamically created and added to the displaylist, but not set as a property.
It is far better to store the actual reference to the thing you want. Not only do you avoid relying on names, and the extra lookup, but it is more robust too.
-
FK Romeo
Originally Posted by CVO Chris
Why does it not work if I reference the same instance name in the array?
Anyone got any ideas?
You have a point there 5Tons. Also, my attempt was only to clear this doubt above.
Furthermore, the 'this' in this code worked for him and was a way to show him the difference why it would work now versus why it did not work before. All depends on the reference of that movieClip and the hierarchy.
Often people overlook the side effects of the coding in a particular style to gain momentary shortcuts.
For example, my thoughts always revolve around the performance of the application. Especially in larger application where there are many modules interacting with each other.
If I store a string in an array and then look up for the object (in this case movieclip) by using that string as a name, yes I am adding a couple of lines of to my code (which at first look seem unnecessary). But as soon as my work is done with that movieclip...I am done. The movieclip is ready for garbage collection.
As compared to above, if I store directly the movieclip reference in the array, I anyway have to clear that array element too if at all I have to think about memory management once I am done with that movieclip. The more such direct references we add, the more lines of code in clearing those references. And in case we forget to clear even one reference to that object (movieClip), that object would never be cleared which results in memory leakage.
Having said above, its often the style we develop while writing the code that makes it a good code or a bad code. No matter if the application we are working on is big or small, our code writing style remains the same unless we put thoughts and conscious efforts in modifying the code style for each application we write.
I hope you get the point.
sameer rao
there...you see!!
-
Juvenile Delinquent
Originally Posted by 5TonsOfFlax
No that is NOT better. Why would you think it's better to store a String, then look up the instance by property name
I'm slightly confused.
Using my other method that worked I get [object_Enemy_1]. When I tested with more than 1 instance (enemy14 instance and enemy15 instance), the array traced as [object_Enemy_1],[object_Enemy_1]. As these are both the same how do I differentiate between them? (ie: I wish to remove 1 item from the array but don't know it's position). MartianSam's method traced as enemy14,enemy15 allowing me to remove from the array by instance name. How can this be done without storing the name of the instance I wish to target?
NB - There will be no dynamically added movieclips (all instances are created on their own keyframes in the main timeline).
Last edited by CVO Chris; 01-19-2011 at 06:56 AM.
-
The output from trace is the same, but they are not the same objects. You could override the toString method in the Enemy_1 class to also print the name and see that, but you don't need to do that to distinguish the objects.
You never remove anything from bombArray in the code above. If you were removing stuff in a loop, then you already know which it is by the index. Also, even if you have the instancename of the thing, that won't tell you the index in the array. I'm just very confused by what you think the name helps with.
Your original code was perfectly fine. You just have to put the actual instances in bombArray, not their names.
Since you say these are created at various times, right after creating each, shove it in the array.
Code:
bombArray.push(enemy4); //or whichever enemy.
Obviously, this is a lot nicer when the enemies ARE dynamically created.
Code:
function makeEnemy():void{
var enemy:Enemy = new Enemy();
addChild(enemy);
bombArray.push(enemy);
}
Then you could call makeEnemy anywhere at any time and have a new Enemy. As many as you want.
If these enemies you're talking about are not the bombs, please post your enemy code, I'll fix it to work without names.
-
Juvenile Delinquent
Wow, thanks for the offer 5ToF. I've posted the relevant sections of the code below. I have not used classes.
MAIN TIMELINE:
Actionscript Code:
// PETROL BOMB CODE var bombArray:Array = new Array(); // FOLLOWING FUNCTION IS CALLED WHEN ENEMY IS KILLED TO REMOVE THEM FROM THE ARRAY function removeBombArray(thearray,theItem):void{ for(var i:int=0; i<thearray.length;i++){ if(thearray[i]==theItem){ thearray.splice(i,1); trace(bombArray); } } } // KEYBOARD LISTENERS stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyPress); function onKeyPress(e:KeyboardEvent):void{ // THROW PETROL BOMB UPON PRESSING SPACE BAR if (e.keyCode == Keyboard.SPACE) { if (numberOfBombs >= 1) { petrolBombCount (-1); petrolBombAnimation.gotoAndPlay(2); // loop through all instances in array and play each movieclip at frame labelled "bomb" for (var i:int = 0; i < bombArray.length; i++) { this[bombArray[i]].gotoAndPlay("bomb"); } } else { // can't throw bomb } } else if (e.keyCode == 90) { // Z PRESSED } else if (e.keyCode == 88) { // X PRESSED } else if (e.keyCode == 67) { // C PRESSED } }
ENEMY MOVIECLIP TIMELINE:
Actionscript Code:
// First Frame - Add movieclip's instance name to Bomb Array MovieClip(this.root).bombArray.push(this.name);
// Frame Label "Hit" - Function enemyHit will cause this movieclip to play // from from this frame if user clicks (shoots) on enemy MovieClip(this.root).removeBombArray(MovieClip(this.root).bombArray,this.name); parent.removeChild(this);
// Frame Label "Bomb" - Function onKeyPress will cause this movieclip to play // from this frame if user presses space (bombs all enemies in the array) MovieClip(this.root).removeBombArray(MovieClip(this.root).bombArray,this.name); parent.removeChild(this);
Rather than add and remove items in the array on the main timeline, I have items added to the array within the movieclip timeline. Items are then removed by calling a function in the main timeline (but the instance name is passed to it from within the movieclip timeline). This way what goes in and out of the array is all controlled from within the movieclip and keeps everything tidy.
Last edited by CVO Chris; 01-19-2011 at 02:02 PM.
-
First, the code. I have not created a class here, though I would if I were writing this myself. Try it, they're not as scary as you think.
My comments and new/altered code are in blue.
Code:
var bombArray:Array = []; //Use [] literal instead of calling Array constructor.
//set up active and inactive listeners
addEventListener("bombActive", bombActiveHandler);
addEventListener("bombInactive", bombInactiveHandler);
function bombActiveHandler(e:Event):void{
bombArray.push(e.target); //add bomb (not name) to bombArray
}
function bombInactiveHandler(e:Event):void{
removeBomb(DisplayObject(e.target));
}
// FOLLOWING FUNCTION IS CALLED WHEN ENEMY IS KILLED TO REMOVE THEM FROM THE ARRAY
//Type your parameters. Also, you don't need theArray since you always call with bombArray.
function removeBomb(theItem:DisplayObject):void{
//instead of iterating over all of them, just use indexOf to find the right one.
var index:int = bombArray.indexOf(theItem);
if (index != -1){
bombArray.splice(index, 1);
removeChild(theItem);
}
trace(bombArray);
}
// KEYBOARD LISTENERS
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyPress);
function onKeyPress(e:KeyboardEvent):void{
//You could use a switch-case instead of if-else. But it's not that big a deal
// THROW PETROL BOMB UPON PRESSING SPACE BAR
if (e.keyCode == Keyboard.SPACE) {
if (numberOfBombs >= 1) {
petrolBombCount (-1);
petrolBombAnimation.gotoAndPlay(2);
// loop through all instances in array and play at bomb labelled frame
for (var i:int = 0; i < bombArray.length; i++) {
bombArray[i].gotoAndPlay("bomb");
}
} else {
// can't throw bomb
}
} else if (e.keyCode == 90) {
// Z PRESSED
} else if (e.keyCode == 88) {
// X PRESSED
} else if (e.keyCode == 67) {
// C PRESSED
}
}
Code:
//use events so that bombs don't have to know about the root at all.
// Frame 1 - notify listener(s) that this bomb is active. Use bubbling.
dispatchEvent(new Event("bombActive", true));
// Frame Label "Hit" - Remove instance if user clicks (shoots) on enemy
//notify listeners that this bomb has gone kablooey
dispatchEvent(new Event("bombInactive", true));
// Frame Label "Bomb" - Remove instance if user presses space (bombs all enemies in the array)
//same as "Hit"
dispatchEvent(new Event("bombInactive", true));
-
Juvenile Delinquent
Saw your reply late yesterday but only able to implement it this morning and it works perfect. I've not used dispatchEvent before but can see the advantages.
Thanks again (you've helped me before with mc casting on a different project)!
Will credit in the game when it's finished!
Last edited by CVO Chris; 01-20-2011 at 07:25 AM.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|