actionscript-3actionscriptanimationdisplayobject

Moving movieclips across the stage on FrameEnter


I'm making an image gallery and I want to have a bunch of thumbnails on the bottom of the screen that smoothly slide from side to side when the mouse moves.

I'm working with a custom class for the container (Tiles) and a custom class for the thumbnails (ImageIcon).

I have a ComboBox which allows users to to choose a gallery. When the user chooses a gallery, the following code is run and the thumbnails should reload. The problem here is that the icons appear on top of each other instead of side by side, also switching categories should remove the old one (see the first for loop), but it does not. Also, the Icons are not animating properly. The animation code is below as well. Right now, only one of the icons will move. The icons should move in order from side to side, stopping when the last few icons hit the edge of the screen, so that they don't get "lost" somewhere off to the side.

Gallery Loader Code:

public function loadCategory(xml:XML = null) {
    if (xml != null) {
        dp = new DataProvider(xml);
        for (var k:int = 0; k < this.numChildren; k++) {
            this.removeChild(this.getChildAt(k));
        }

        var black:DropShadowFilter = new DropShadowFilter(0, 45, 0x000000, 1, 3, 3, 1, 1);
        var white:DropShadowFilter = new DropShadowFilter(0, 45, 0xFFFFFF, 1, 2, 2, 1, 1);

        for (var i:int = 0; i < dp.length; i++) {
            var imgicon:ImageIcon = new ImageIcon();
            imgicon.addEventListener(MouseEvent.CLICK, showImage);
            imgicon.width = 100;
            imgicon.x = (i * (imgicon.width + 20));
            imgicon.path = dp.getItemAt(i).data;
            imgicon.loadIcon();
            imgicon.filters = [black, white];

            stage.addEventListener(Event.ENTER_FRAME, moveIcon);
            this.addChild(imgicon);
        }
    } else {
        //Failed to load XML
    }
}

Icon Animation Code:

public function moveIcon(e:Event){
    var speed = 0;
    speed = Math.floor(Math.abs(this.mouseX/20));

    var image = this.getChildAt(k);

    var imagebox = image.width + 20;

    var edge:Number = (800/2);

    if (this.mouseX > 0) {
        for (var k:int = 0; k < this.numChildren; k++) {
            if (image.x - (imagebox/2) + speed < -edge + (k * imagebox)) {
                speed = 0;
            }

            image.rotationY = Math.floor(image.x/20);
            image.x -= Math.floor(speed);
        }
    } else {
        for (var j = this.numChildren; j >= 0; j--) {
            if (image.x + speed > edge - ((imagebox * j) )) {
                speed = 0;
            }

            image.rotationY = Math.floor(image.x/20);
            image.x += Math.floor(speed);
        }
    }
}

Solution

  • As I see it, you have three questions (You should have put these at the end of your question instead of "What is wrong with my code?"). One of the main principles of programming is breaking problems into smaller parts.

    1. How do I line up the ImageIcon beside each other?
    2. How do I remove the old ImageIcon, when switching categories?
    3. How do I animate ALL the ImageIcons together, based on the mouse position, with constraints on either side?

    Question 1

    I can't see anything wrong, but just check that when you are setting imgicon.x, that imgicon.width is actually set.

    Question 2

    Instead of relying on numChildren and getChildAt(), I would create a currentIcons array member variable, and when you create a new ImageIcon, just push it onto the array. Then when you want to remove them, you can just loop through the array like this:

    for each (var cIcon:ImageIcon in currentIcons) 
    {
        cIcon.removeEventListener(MouseEvent.CLICK, showImage);
        removeChild(cIcon);
    }
    currentIcons = [];
    

    As you can see, I am also removing any listeners that I have added. This is best practice. Then clearing the array when I have removed all the icons.

    Question 3

    I can see a few things wrong with your code. First, in the line where image is set, k is not set yet!

    Here you can also use the currentIcons array, but you probably can't use a for each in loop, because that gives you the items out of order. Just a normal for loop will be better.

    I haven't tested this code for the moveIcon method, but the idea should work. You may have to tweek it though:

    public function moveIcon(e:Event):void 
    {
        var speed:Number = Math.floor(this.mouseX / 20); // Removed "abs".
        var imageBox:Number = currentIcons[0].width;
        var edge:Number = 800 / 2;
    
        for (var i:int = 0; i < currentIcons.length; i++) 
        {
            var image:ImageIcon = currentIcons[i] as ImageIcon;
            image.x += speed;
            image.rotationY = Math.floor(image.x / 20);
    
            var min:int = -edge + (i * imagebox);
            if (image.x < min) image.x = min;
    
            var max:int = edge - (imagebox * i);
            if (image.x > max) image.x = max;
        }
    }
    

    EDIT* Sorry, it was supposed to be a greater than in the last if statement, but I had a less than by accident.