0

I have a frame-by-frame animation. I want to be able to click and drag on the stage back and forth and traverse through the animation. I.e. I want to click and drag from left to right to make the animation go forwards and right to left to make the animation go backwards.

How would I achieve this?

I am making an assumption that there will be some maths involved in calculating mouse position and traversing to the correct frame, but how would I do this?

Dan Hanly
  • 7,829
  • 13
  • 73
  • 134
  • Kodiak: Is there anyway that upon release you can add a deaccelerate feature, so that if you flick the drag then it will have a tween effect, fast then slowing down. Thank you. –  Aug 02 '11 at 05:33

2 Answers2

2

Here you are (edited version)

import flash.events.MouseEvent;
import flash.display.MovieClip;
import flash.display.Sprite;

var clickedMouseX:int;
var clickedFrame:uint;
var backgroundClip:Sprite = getChildByName("background") as Sprite;
var clip:MovieClip = getChildByName("animation") as MovieClip;
clip.stop();
clip.mouseEnabled = false;

backgroundClip.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
backgroundClip.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);


function onMouseDown(event:MouseEvent):void
{
    backgroundClip.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
    clickedMouseX = backgroundClip.mouseX;
    clickedFrame = clip.currentFrame;
}

function onMouseUp(event:MouseEvent):void
{
    backgroundClip.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
}

function onMouseMove(event:MouseEvent):void
{   
    var delta:int = backgroundClip.mouseX - clickedMouseX;
    var wantedFrame:uint = (clickedFrame + delta * clip.totalFrames / backgroundClip.width) % clip.totalFrames;
    while (wantedFrame < 1)
    {       
        wantedFrame += clip.totalFrames;
    }
    clip.gotoAndStop(wantedFrame);
}

Cheers!

Kodiak
  • 5,978
  • 17
  • 35
  • seems so simple now! Thanks mate! I'll give this a bash tomorrow morning when I'm back in work! – Dan Hanly Mar 15 '11 at 19:15
  • I've added a start position variable on mouse down and used the backgroundClip.mouseX value in the onMouseMove function to calculate a difference between the two. How do I account for backward movements? – Dan Hanly Mar 16 '11 at 09:16
  • So you have something like `var delta:Number = previousMouseX - backgroundClip.mouseX`? And then `var wantedFrame:uint = clip.currentFrame + delta * clip.totalFrames / backgroundClip.width;`? If you want to avoid negative frame numbers here's what you should write: `var wantedFrame:int = (clip.currentFrame + delta * clip.totalFrames / backgroundClip.width) % clip.totalFrames ;` so when your wantedFrame becomes negative it warps to the last frame available. – Kodiak Mar 16 '11 at 09:45
  • yes that's what I mean. Could you edit your Answer to add this code, it's a little difficult to understand in comments. I'll accept you then. – Dan Hanly Mar 16 '11 at 10:06
  • I didn't know the % clip.totalFrames thing. Thanks man, that's amazing. Before now I'd been using `if(currentFrame>totalFrames){currentFrame = 0}` etc. – Dan Hanly Mar 16 '11 at 10:07
  • Oh I'm sorry, I'm a bit wrong: % does not work for negative numbers. It's only operationnal if the left member is superior to the right member... You may have to write a test `if(currentFrame<0){currentFrame = totalFrames}`. Glad I helped! – Kodiak Mar 16 '11 at 10:20
  • put this code in your answer (will help me for future reference) and I'll accept your answer! Cheers mate, you've been a great help – Dan Hanly Mar 16 '11 at 10:22
0

It should be a matter of mapping the length of your drag area to the length of the timeline:

stage.addEventListener(MouseEvent.MOUSE_MOVE, updateAnimation);
function updateAnimation(event:MouseEvent):void {
    animation.gotoAndStop(Math.floor(mouseX/stage.stageWidth * animation.totalFrames));
}

Here's a commented version:

stage.addEventListener(MouseEvent.MOUSE_MOVE, updateAnimation);
function updateAnimation(event:MouseEvent):void {
    //take the ratio between the mouse position and stage width -> //a number from 0.0 to 1.0
    var mouseRatio:Number = mouseX/stage.stageWidth; 
    //'scale'/multiply that number to fit the animation frames  -> from a maximum of 1.0 to animation's total frames
    //also, we 'round down' because we need an integer for the frame number, not a fractional number
    var frame:int = Math.floor(mouseRatio * animation.totalFrames);
    animation.gotoAndStop(frame);
}

Also, not that MOUSE_MOVE gets triggered several frames per second. You could update on ENTER_FRAME and since you mentioned dragging, you could also have a variable to keep track if the mouse is pressed or released:

var mousePressed:Boolean;
stage.addEventListener(MouseEvent.MOUSE_DOWN, togglePressed);
stage.addEventListener(MouseEvent.MOUSE_UP, togglePressed);
stage.addEventListener(Event.ENTER_FRAME, update);

function togglePressed(event:MouseEvent):void {
    mousePressed = event.type == MouseEvent.MOUSE_DOWN;
}
function update(event:Event):void {
    if(mousePressed) animation.gotoAndStop(Math.floor(mouseX/stage.stageWidth * animation.totalFrames));
}

HTH

George Profenza
  • 50,687
  • 19
  • 144
  • 218