Search code examples
actionscript-3flashswapmovieclipgraphic

Flash AS3: Swapping Parts within Movieclips


I have a Movieclip (level 1, MC) with around 10 frames. There is a different movieclip (level 2, Move Jump etc animation) on each frame. Inside each of the level 2 movieclips, there are about 30 movieclip symbols (level 3, Head Arm etc) each spamming about 100 frames with around 30-50 keyframes. Each level 3 symbol has around 10 frames, on each frame I have a particular skin graphic.

I have all the level 2 and level 3 symbols instance named (same label across timeline for the same object), and I have the right frames stop(); and labelled. I also understand that everytime I enter a new frame in not just level 1 but also level 2, I have to reset all the level 3 symbols to the desired frame, because my previous settings will be destroyed upon leaving frame.

I got it working by doing level1.gotoAndStop(level2name) ---> level1.level2.level3.gotoAndStop(skintype) and then loop over a nasty nasty number of poses X bodyparts. AND this process needs to be performed in an ENTER_FRAME event since everything will be reset again. Needless to say, I really really don't want to do it this way.

One of the alternatives is breaking the graphics up and have many many level 2 poses movieclips inside my level 1 MC movieclip (mage hit by warrior 3rd attack, warrior hit by rogue 4th attack...). That's what I used to do before. But for this project, a simple calculation tells me I need to make 200+ animations that way, which is not feasible. I can also get rid of level 1 MC and have the poses saved into an array, but the bodyparts still need to be refreshed every frame.

I'm hoping that there's a relatively quick fix to this that I managed to miss, as it seems like such a basic feature, I'm sure many flash games will have to go through it (dress up, or anything with customization + animation really). Yet somehow I've been searching for days and can't find a cure. The author-time ability to simply swap out graphics within a symbol to replace every frame of every animation in the entire file also suggests that there's gotta be a more universal approach to these swapping. I hope you can prove me right!

I do have 2 things that I don't know if I should even bother trying: 1) Drag the MC onto frame1 (my only frame), where I currently have nothing but code. 2) Declare each bodypart individually AND declare MC, then have MC's parts link to these bodyparts. Basically, I just need a viable method to keep these bodyparts from resetting everytime the animation goes to a new frame, my flash knowledge is not enough to tell me whether if it's even possible to have these "global graphics bank independent of frames".

And yes I know I'm probably not doing it in the most clean way possible, but I simply animate better with visuals, so while I CAN start from shapes and animate everything using strictly code I REALLY want to move away from it. The art style is pretty important in this project.

UPDATE: For now, I went for the ugly route. Everytime the MC changes animation, I do:

MovieClip(DisplayObjectContainer(MC.getChildByName(MC.move))).Hand.gotoAndStop(MC.skinname);

And repeat that for all 35 body parts. Turns out that flash replaces all frames of hand in the MC.move, which makes life a lot easier. The alternative is to poll for every single frame, but the direct consequence is MUCH slower fps. Instead, right now I only need to switch graphics whenever there is a change to the moves.

This works, but I'm aware that it slows down performance quite a bit. In fact it can slow down performance in the same magnitude as the actual vector rendering. Limiting the swapping to only move changes is really not optional but mandatory.


Solution

  • Please look at this: http://zdg.ru/tmp/animation.swf
    The source can be downloaded here: http://zdg.ru/tmp/animation.fla

    If I got your description correct, I did the animation in the same way. The main timeline has a single frame with a character symbol. A character symbol has a timeline within it with two animation points "stand" and "jump". The character consists of symbols "head", "body", "left_hand", "right_hand", "left_leg", "right_leg". Each of these symbols is animated independently. Charater animation timeline contains both keyframes and tweens. All symbols are named consistently in all frames.

    Each character part, in turn, has a timeline of 2 frames, corresponding to skin 1 and skin 2.

    As you can see, the skin is not destroyed during the animation and there is no need to correct it in every frame.

    The code on the main timeline is:

    var char_body_parts:Array = new Array(
        mv_char.body, mv_char.head, mv_char.left_hand, mv_char.right_hand,
        mv_char.left_leg, mv_char.right_leg
    );
    
    var skin_num:int = 1;
    
    mv_char.gotoAndStop("stand");
    setSkin(char_body_parts, skin_num);
    
    btn_jump.addEventListener(MouseEvent.CLICK, doJump);
    btn_skin.addEventListener(MouseEvent.CLICK, doSkin);
    
    function doJump(evt:MouseEvent):void {
        mv_char.gotoAndPlay("jump");
    }
    
    function doSkin(evt:MouseEvent):void {
        skin_num++;
        if (skin_num > 2) skin_num = 1;
        setSkin(char_body_parts, skin_num);
    }
    
    function setSkin(parts:Array, skin_num:int):void {
        for (var i:int = 0; i < parts.length; i++) {
            (parts[i] as MovieClip).gotoAndStop(skin_num);
        }
    }
    

    ================== UPDATE ====================
    This is the updated animation: http://zdg.ru/tmp/animation3.swf
    The source can be downloaded here: http://zdg.ru/tmp/animation3.fla
    Now my setup is identical to yours.
    I have a 2-frame char, one frame contains "stand" movieclip and the other frame contains "jump" movieclip. Indeed, when you gotoAndStop for any of animations, skins get lost. But you don't have to update them every frame. You need to update them only in the first frame of animation, i.e. right after gotoAndStop("animation"). I still have a list of body parts to bulk assign the skin but now they are accessed by name. So the main code changes are:

    var char_body_parts:Array = new Array(
        "body", "head", "left_hand", "right_hand",
        "left_leg", "right_leg"
    );
    
    function setSkin(char:MovieClip, parts:Array, skin_num:int):void {
        for (var i:int = 0; i < parts.length; i++) {
            char.mv_animation.getChildByName(parts[i]).gotoAndStop(skin_num);
        }
    }
    
    function setAnimation(char:MovieClip, anim_name:String):void {
        char.gotoAndStop(anim_name);
        setSkin(char, char_body_parts, skin_num);
    }
    

    There are also two more solutions, I didn't code them but they are easily described.

    1. In frame 1 of each skin movieclip, add gotoAndStop((root as MovieClip).skin_num). It works as follows: whenever a skin gets reset, it starts from frame 1. In frame 1 it will gotoAndStop to the current skin automatically. So you dont need to do anything else.

    2. Put your animation movieclips not in the timeline, but in the same single frame. Name each animation lke "stand", "jump" etc. Switch animations not by gotoAndStop, but by making selected animation visible and others invisible. The skin would have to be set once for each skin change.