A Flash Developer Resource Site

Results 1 to 11 of 11

Thread: [RESOLVED] Array[i].gotoAndPlay("frame label") doesn't work

  1. #1
    Juvenile Delinquent CVO Chris's Avatar
    Join Date
    Jul 2002
    Location
    Ulster, UK
    Posts
    520

    resolved [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 0bombArray.lengthi++) {
                   
    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.

  2. #2
    Juvenile Delinquent CVO Chris's Avatar
    Join Date
    Jul 2002
    Location
    Ulster, UK
    Posts
    520
    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!

  3. #3
    FK Romeo martiansam's Avatar
    Join Date
    Oct 2001
    Location
    Bombay, India
    Posts
    223
    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!!

  4. #4
    Juvenile Delinquent CVO Chris's Avatar
    Join Date
    Jul 2002
    Location
    Ulster, UK
    Posts
    520
    That's far better, thanks Martiansam

  5. #5
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    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.

  6. #6
    FK Romeo martiansam's Avatar
    Join Date
    Oct 2001
    Location
    Bombay, India
    Posts
    223
    Quote Originally Posted by CVO Chris View Post
    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!!

  7. #7
    Juvenile Delinquent CVO Chris's Avatar
    Join Date
    Jul 2002
    Location
    Ulster, UK
    Posts
    520
    Quote Originally Posted by 5TonsOfFlax View Post
    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.

  8. #8
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    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.

  9. #9
    Juvenile Delinquent CVO Chris's Avatar
    Join Date
    Jul 2002
    Location
    Ulster, UK
    Posts
    520
    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.

  10. #10
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    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));
    

  11. #11
    Juvenile Delinquent CVO Chris's Avatar
    Join Date
    Jul 2002
    Location
    Ulster, UK
    Posts
    520
    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
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center