Search code examples
for-loopactionscript-3actionscriptaddeventlistener

How to get a loop to load movieclips with eventlisteners


I wanted the scene load 5 different movie clips (named B1-B5). Each movie clip is placed on a specific x and y. Each movie clip grows/shrinks on roll over/roll out....

I got the code working by typing everything out and duplicating each section per time but it's messy and I'd like to clean up the code by getting a loop to do it (if it's possible?).

This is the code that works but I'd have to duplicate it per movie clip (changing the obvious bits)...

var scene1:MovieClip = new B1();
    addChild(scene1);
    scene1.x = 170.30;
    scene1.y = 231.15;
    scene1.addEventListener(MouseEvent.MOUSE_OVER, onRollOverEvent1);
    scene1.addEventListener(MouseEvent.MOUSE_OUT, onRollOutEvent1);

function onRollOverEvent1(e:MouseEvent) {
    scene1.width=25.9;
    scene1.height=25;
 }

function onRollOutEvent1(e:MouseEvent) {
    scene1.width = 20.9;
    scene1.height = 20;
 }

Below is what I've tried out but have been stuck for a good while...

for (var i:int=1; i<5; i++){
    var scene[i]:MovieClip = new "B"+i();
    addChild("scene"+i);
    //var scene[i]:MovieClip = new B[i]();
    scene[i].addEventListener(MouseEvent.MOUSE_OVER, onRollOverEvent);
    scene[i].addEventListener(MouseEvent.MOUSE_OUT, onRollOutEvent)

    function onRollOverEvent(e:MouseEvent) {
    scene[i].width=25.9;
    scene[i].height=25;
 }
    function onRollOutEvent(e:MouseEvent) {
    scene[i].width = 20.9;
    scene[i].height = 20;
 }
}

scene1.x = 170.30;
scene1.y = 231.15;
scene2.x = 284.30;
scene2.y = 250.75;
scene3.x = 377.30;
scene3.y = 280.15;  
scene4.x = 444.30;
scene4.y = 321.15;
scene5.x = 196.30;
scene5.y = 172.15;

Solution

  • First, lets go through your mistakes.

    new "B"+i();
    

    At the very best that translates to calling a number i as function and adding the result to "B" as a String. But even new "B1"() is not the same as new B1(). There is, in fact, a method getDefinitionByName(..) that allows to address a class via its name, but I don't recommend to use it because it is advanced topic.

    var scene[i]:MovieClip
    

    You just cannot define variables scene1, scene2, etc this way. The closest thing you can actually devise is the square bracket notation: this["scene" + i] = ....

    addChild("scene"+i);
    

    The argument must be a DisplayObject instance, not a String.

    for (...)
    {
        ...
        function onRollOverEvent(e:MouseEvent)
        ...
    }
    

    Do not define functions inside other functions or loops.

    scene[i].width = 20.9;
    scene[i].height = 20;
    

    By the end of your loop i will be equal to 5, so, what do you think such a record will address?

    Then, the solution.

    When you come to scaling your working solution to multiple instances, you are to go algorithmic. Loops and Arrays are your friends.

    // Lets devise a list of classes and (x,y) coordinates.
    var Designs:Array = [
        null, // the 0-th element
        {id:B1, x:170, y:230},
        {id:B2, x:285, y:250},
    ];
    
    for (var i:int = 1; i < Design.length; i++)
    {
        // Retrieve a record for the future object.
        var aDesign:Object = Designs[i];
    
        // Get a reference to the object's class.
        var aClass:Class = aDesign.id;
    
        // Create the object. Yes, you CAN omit () with
        // the "new" operator if there are no mandatory arguments.
        var aThing:Movieclip = new aClass;
    
        // Set coordinates from the design record.
        aThing.x = aDesign.x;
        aThing.y = aDesign.y;
    
        // Add to the display list.
        addChild(aThing);
    
        // Subscribe the event handlers.
        aThing.addEventListener(MouseEvent.MOUSE_OVER, onOver);
        aThing.addEventListener(MouseEvent.MOUSE_OUT, onOut);
    
        // Save the object's reference for the later use.
        // If you'd need to address, say, 3rd object,
        // you do it as following:
        // Designs[3].instance
        aDesign.instance = aThing;
    }
    
    function onOver(e:MouseEvent):void
    {
        // You subscribed all of the objects to this one event handler.
        // This is the correct way to learn, which one of the objects
        // is under the mouse and is dispatching the said event.
        var aThing:MovieClip = e.currentTarget as MovieClip;
    
        // Change the object's size.
        aThing.width = 26;
        aThing.height = 25;
    }
    
    function onOut(e:MouseEvent):void
    {
        // Get the source of the dispatched event.
        var aThing:MovieClip = e.currentTarget as MovieClip;
    
        // Change the object's size.
        aThing.width = 21;
        aThing.height = 20;
    }