3 Replies Latest reply on Nov 13, 2010 2:31 AM by wagsteroid

    IK, MovieClips and lip sync

    wagsteroid

      I've got my head around bones now, which isn't too bad once you get used to it.  I have ten minutes of dialog which I have created mouth movements for in Lipsync MX, these are imported as a swf and then placed within my character's Head MovieClip.

       

      Problem is, IK insists on using MovieClips instead of graphics.  This means that the lip sync doesn't stay in touch with the main timeline - it only stays in sync until the main timeline is paused or jumps to a different point.

       

      Is there an established method which allows you to embed a lip sync symbol within part of an armature and ensure it keeps pace with the main timeline, or am I going to have to code it somehow?

        • 1. Re: IK, MovieClips and lip sync
          wagsteroid Level 1

          So here's my fix. My animation already extends a class called InteractiveAnimation which overrides the standard timeline manipulation methods to make it easier to control using standard transport controls.

           

          To this class I added a function that recursively searches every MovieClip on the first frame for one with a name of "lip_sync".  It then calls gotoAndStop / gotoAndPlay etc on the lipsync MovieClip every time these methods are called on the main timeline.

           

          If anyone knows a better approach I'd love to hear it.

           

          Code here:

           

          package com.pictureandword.movingtoys
          {
              import flash.display.MovieClip;
              import flash.events.Event;

           

              public class InteractiveAnimation extends MovieClip
              {
                 
                  private static var STOPPED:String = "stopped";
                  private static var PLAYING:String = "playing";
                  private var state:String;
                  private var lip_sync:MovieClip;
                         
                  public function InteractiveAnimation()
                  {
                      super();
                      stop();
                      state = STOPPED;
                      getLipSync(this);

           

                      //root.addEventListener(AnimationEvent.ANIMATION_PAUSEPOINT, pausePointHandler);
                  }
                 
                  // When play() is called, dispatch an event so the pause/play button knows what state to be in
                  // then recursively start all child MovieClips
                  override public function play():void
                  {
                      addEventListener(Event.ENTER_FRAME, enterFrameHandler);
                      dispatchEvent(new AnimationEvent(AnimationEvent.ANIMATION_PLAY, currentFrame/totalFrames));
                      playChildren(this);
                      super.play();
                      state = PLAYING;
                  }
                 
                  // When stop() is called, dispatch an event so the pause/play button knows what state to be in
                  // then recursively stop all child MovieClips
                  override public function stop():void
                  {
                      removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
                      dispatchEvent(new AnimationEvent(AnimationEvent.ANIMATION_STOP, currentFrame/totalFrames));
                      stopChildren(this);
                      super.stop();
                      state = STOPPED;
                  }
                 
                  // As above for gotoAndPlay
                  override public function gotoAndPlay(frame:Object, scene:String = null):void
                  {
                      addEventListener(Event.ENTER_FRAME, enterFrameHandler);
                      dispatchEvent(new AnimationEvent(AnimationEvent.ANIMATION_PLAY, currentFrame/totalFrames));
                      playChildren(this);
                      super.gotoAndPlay(frame, scene);
                      trace("Jumping");
                      if (lip_sync) {
                          trace("Lip sync jumping to: " + frame);
                      lip_sync.gotoAndStop(frame);
                      }
                      state = PLAYING;
                  }
                 
                  // As above for gotoAndStop
                  override public function gotoAndStop(frame:Object, scene:String = null):void
                  {
                      removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
                      stopChildren(this);
                      trace("Stopping");
                      if (lip_sync) {
                          trace("Lip sync stopping at: " + frame);
                      lip_sync.gotoAndPlay(frame);
                      }
                      super.gotoAndStop(frame, scene);
                  }
                 
                  // Dispatch event to tell the playhead where it should be, stop at end of animation
                  private function enterFrameHandler(e:Event):void
                  {
                      dispatchEvent(new AnimationEvent(AnimationEvent.ANIMATION_PROGRESS, currentFrame/totalFrames));
                  }
                 
                  public function pause():void
                  {
                      removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
                      stopChildren(this);
                      super.stop();
                  }
                 
                  public function resume():void
                  {
                      if (state == PLAYING)
                      {
                          addEventListener(Event.ENTER_FRAME, enterFrameHandler);
                          playChildren(this);
                          super.gotoAndPlay(currentFrame - int(currentFrame == totalFrames));
                      }
                  }
                 
                 
                  // Recursively stop all children that are MovieClips
                  // Don't call stop on this one though - or there'll be a recursion loop
                  private function stopChildren(mc:MovieClip):void
                  {
                        for (var i:int = 0; i < mc.numChildren; i++)
                       {
                           if (mc != this)
                           {
                               mc.stop();
                           }
                           if (mc.getChildAt(i) is MovieClip)
                           {
                               stopChildren(MovieClip(mc.getChildAt(i)));
                           }
                       }
                  }
                 
                  // Recursively start all children that are MovieClips
                  // Don't call start on this one though - or there'll be a recursion loop
                  private function playChildren(mc:MovieClip):void
                  {
                        for (var i:int = 0; i < mc.numChildren; i++)
                       {
                           if (mc != this)
                           {
                               mc.play();
                           }
                           if (mc.getChildAt(i) is MovieClip)
                           {
                               playChildren(MovieClip(mc.getChildAt(i)));
                           }
                       }
                  }
                 
                  private function getLipSync(mc:MovieClip):void
                  {
                      for (var i:int = 0; i < mc.numChildren; i++)
                       {                
                           if (mc.getChildAt(i) is MovieClip)
                           {
                               trace(mc.getChildAt(i).name);
                               if (mc.getChildAt(i).name == "lip_sync")
                               {
                                   trace("Found it!!!");
                                   lip_sync = MovieClip(mc.getChildAt(i));
                               }
                               getLipSync(MovieClip(mc.getChildAt(i)));
                           }
                       }
                  }
              }
          }

          • 2. Re: IK, MovieClips and lip sync
            Justin Putney Level 2

            Hi Wagsteroid,

             

            This is an interesting issue. I didn't realize that was the case with IK.

             

            You may be interested in SmartMouth (http://smartmouth.ajarproductions.com), an extension I've developed that does automatic lip syncing right in Flash. It also allows you to export lip sync data to an XML file that can then be read in with ActionScript. This could make it easier to sync your animation.

            • 3. Re: IK, MovieClips and lip sync
              wagsteroid Level 1

              Ooooo - I like the look of that.  Much better workflow than LipsyncMX.  I'll give it a whirl next project and see how I get on with it.

               

              I've modified the class above so that any MovieClip with the instance name "sync_to_main_timeline" will sync to the main timeline - useful for all sorts of IK/MovieClip/sync issues.