March 10, 2010

AS3 MOUSE SPEED AND THROWING OBJECTS

I was trying to make a sectional view of water-like waves, like this neat demonstation, and I came up with a class that determines and returns the mouse's speed. To determine how big of a wave to make, I needed to know how fast the mouse was traveling. As things progressed, and I temporarily (perhaps permanently) dropped the water level project, I decided to make something to exhibit my mouse speed catcher.

Enter the fantastic ball thrower. It...throws a ball. The ball's initial velocity is determined by your mouse's speed, and friction is applied with an ENTER_FRAME event, to slow it down. (I discovered early on that when this thing gets going fast, it's kind of hard to click). Speed is determined by taking the position of the mouse at a specific frame and comparing it to the mouse's position during the previous frame. Instead of using the Pythagorean theorum, as I probably should, I'm just setting the ball's x and y speed individually.

Here she is:

Here's the "MouseSpeed" class:

  package util
  {

	  import flash.display.*;
	  import flash.events.*;
  	
	  public class MouseSpeed extends Sprite
	  {
		  private var newY:Number = 0;
		  private var oldY:Number = 0;
		  public var ySpeed:Number;
		  private var newX:Number = 0;
		  private var oldX:Number = 0;
		  public var xSpeed:Number;
  		
		  public function MouseSpeed()
		  {
			  this.addEventListener(Event.ENTER_FRAME, calculateMouseSpeed);
		  }
  		
		  private function calculateMouseSpeed(e:Event)
		  {
			  newY = mouseY;
			  ySpeed = newY - oldY;
			  oldY = newY;
  			
			  newX = mouseX;
			  xSpeed = newX - oldX;
			  oldX = newX;
		  }
  		
		  public function getYSpeed():Number
		  {
			  return ySpeed;
		  }
  		
		  public function getXSpeed():Number
		  {
			  return xSpeed;
		  }
  		
	  } //ends class
  	
  } //ends package

Here's the code in my FLA, if you want to reproduce exactly what I have:

  import fl.controls.NumericStepper;
  import util.*;	// for MouseSpeed class

  var ms:MouseSpeed	= new MouseSpeed();
  var xSpeed:Number	= 0;
  var ySpeed:Number	= 0;
  var friction:Number	= 0.96;
  var offsetX:Number	= 0;
  var offsetY:Number	= 0;

  var ns:NumericStepper	= new NumericStepper();
  ns.maximum		= 1;
  ns.minimum		= 0;
  ns.stepSize		= 0.02;
  ns.value		= 0.96;
  ns.x			= 36;
  ns.y			= 300;
  addChild(ns);
  ns.addEventListener(Event.CHANGE, changeFriction);

  object.buttonMode = true;
  object.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
  object.addEventListener(Event.ENTER_FRAME, throwobject);

  function mouseDownHandler(e:MouseEvent):void
  {
	  stage.addEventListener(Event.ENTER_FRAME, drag);
	  stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
	  offsetX = mouseX - object.x;
	  offsetY = mouseY - object.y;
  }

  function mouseUpHandler(e:MouseEvent):void
  {
	  stage.removeEventListener(Event.ENTER_FRAME, drag);
	  stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
	  xSpeed = ms.getXSpeed();
	  ySpeed = ms.getYSpeed();
  }

  /*
  The offset x and y variables are just to remember where on the box you clicked.
  Without it, when the "MOUSE_DOWN" is registered there would be a little jump as 
  the box moved to the exact mouseX and mouseY coordinates.
  */

  function drag(e:Event):void
  {
	  object.x = mouseX - offsetX;
	  object.y = mouseY - offsetY;
  }

  function throwobject(e:Event)
  {
	  // move object and apply friction
	  object.x += xSpeed;
	  object.y += ySpeed;
  	
	  xSpeed *= friction;
	  ySpeed *= friction;
  	
	  // keep object within bounds (stage borders)
	  if(object.x > stage.stageWidth - object.width / 2)
	  {
		  object.x = stage.stageWidth - object.width / 2;
		  xSpeed *= -1;
	  }
	  if(object.x < object.width / 2)
	  {
		  object.x = object.width / 2;
		  xSpeed *= -1;
	  }
	  if(object.y > stage.stageHeight - object.height / 2)
	  {
		  object.y = stage.stageHeight - object.height / 2;
		  ySpeed *= -1;
	  }
	  if(object.y < object.height / 2)
	  {
		  object.y = object.height / 2;
		  ySpeed *= -1;
	  }
  }

  function changeFriction(e:Event):void
  {
	  friction = e.target.value;
	  trace(e.target.value);
  }

download the .fla and the .as files.

Posted in actionscript

Comments:


I'd been looking on the internet for something like this for days! Finally! Thanks!

Maria | July 2, 2010 @ 3:58 pm

This is cool but i don't understand the algorithm in this code

Herman | July 2, 2010 @ 9:24 pm

Great post, really useful for lots of different things. I tried to get something like this going last week but couldnt get anything that runs as smoothly as thing.

Cheers dude

Klaus | July 16, 2010 @ 9:31 am

What a handy little mouse speed class! I always have to go back and re-look up basic physics stuff. You've laid it out beautifully here. 

Many thanks!

hebchop | September 22, 2010 @ 12:10 pm

My movie now has an added cool factor.  And it's much more fun to use.  Thanks for figuring this out!  I tried using a Timer and MouseMove event, but it just wasn't happening.  Using the Enter Frame event seems to work.

Ksafez | September 24, 2010 @ 12:29 am

Question - when switching this projec to AIR 2.5 tje kinetic force of the throw degrades extremely more rapidly than it does when its built to Flash. Any thoughts on why?

CG | January 5, 2011 @ 4:29 pm

@CG

The only thing I can think of is that the force degradation is based on the enter-frame event, and maybe at higher rates, this slows more rapidly.  Choosing a slower frame-rate might help (I think this is using 30 or 31 frames-per-second).  Other than this, I don't know.  Never worked with AIR.


@Herman

Here's some basic pseudocode for the main FLA:

while(swf is running)
	ball += xSpeed
	ball += ySpeed
end while

if(mouse down event fires)
	ball should follow mouse (with offset considered) until mouse up fires
end while

if(mouse up event fires)
	ball should stop following mouse
	xSpeed and ySpeed should be recorded
end if

For the MouseSpeed class, it just uses an Enter Frame event, and on each firing of the event, it records the new coordinates and compares these to the old ones.

jay | January 17, 2011 @ 12:19 pm

I used your code, modified for something diff,  gave you credit and posted it.
hope that is cool
http://rcolepeterson.posterous.com/scroll-content-by-dragging-it
Thanks
CP

rcolepeterson | February 21, 2011 @ 3:36 pm

@CG Hey, I got the same problem, just multiply xSpeed and ySpeed *10 in the throw object function. Great and simple code

AG | September 13, 2011 @ 11:42 am

im getting  1172:definition fl.controls:NumericStepper could not be found.

using CS4

what am i doing wrong?

Jon | September 22, 2011 @ 9:11 am

Very simple and very useful. Thank you for sharing!

Fabiano | December 9, 2011 @ 6:38 am

Nice :)
Your post  saved me time/money.
Thanks

fonky fonk | March 27, 2012 @ 4:43 pm

Hi. Great Work. Your class really helped me.
I was wondering how you can use the same thing for touch events. Apparently i cant do it.. Would love some help. Thanks

Somebody | March 24, 2013 @ 1:06 pm

i downloaded, open the file, ctrl + enter and get 

...MouseSpeed.as, Line 1	5001: The name of package 'util' does not reflect the location of this file. Please change the package definition's name inside this file, or move the file. C:\Users\...\Desktop\...\fla\MouseSpeed.as

salvador | April 18, 2013 @ 11:40 pm

how you can use in touch events? please help me

Zafir | May 11, 2013 @ 5:04 am

Thank you very much for this class, it really works well and I don't have to use those mechatics formulas to get the acceleration. :D

However, for me mouseDownEventHandler is called only once(when I click), so I added offset update in drag() function to update it as nesessary(to prevent stuttering). Otherwise, nice example!

DuckOfDoom | July 16, 2013 @ 4:06 am

Thanks buddy.....! It helped a lot, simple but very effective codes.

Ashish | August 30, 2013 @ 10:59 pm

@salvador When I download and open the .as and .fla I get the same error. And when I type the code in myself I get the same error as @jon "NumericStepper could not be found". I'm wonder what's going on. This code is exactly what I need for the flash movie I'm developing.

AmbroseSTF | November 5, 2013 @ 1:05 pm

@Guys who have the problem:
Line 1	5001: The name of package 'util' does not reflect the location of this file. Please change the package definition's name inside this file, or move the file.

Create a new folder name it util besides your *.Fla file and move MouseSpeed.as inside it.

Alan | April 16, 2014 @ 9:16 pm

I think this site is awesome.  Thanks, dude!!

Sue | April 4, 2015 @ 1:53 am

Very nice, but a couple of basic improvements:

put this line
    object.addEventListener(Event.ENTER_FRAME, throwobject);
inside the MOUSE_UP handler, so that you're not tying up the CPU with needless ENTER_FRAME work

and once the xSpeed and ySpeed (which are not really speeds, but distances) reach a certain small value (maybe 0.1 ?) remove the ENTER_FRAME call to 'throwobject()'

Craig Umanoff | April 9, 2016 @ 4:38 pm

What do you think?

(All fields required. Only your name and comment will be stored.)
Name:

Email:

Code:
validation image
Message: