Free ActionScript

Flash AS2 & AS3 Tutorials, Game Code, Effects, Source Files & Sample Downloads

Mouse follow with easing & smooth rotation – v2

7 Comments »

Totally rewrote my previous AS3 smooth follow and rotation script.

This version fixes all the previous issues and optimizes everything. No more “jumpy” rotation.

Click and hold to make the player smoothly rotate to and follow the mouse:

View Code ACTIONSCRIPT
/**
 * Player Movement - Follow Mouse on click with Easing and smooth rotation
 * ---------------------
 * VERSION: 2.0
 * DATE: 1/18/2011
 * AS3
 * UPDATES AND DOCUMENTATION AT: http://www.FreeActionScript.com
 **/
package
{
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.MouseEvent;
 
	public class Main extends MovieClip
	{
		// player settings
		private var _moveSpeedMax:Number = 1000;
		private var _rotateSpeedMax:Number = 15;
		private var _decay:Number = .98;
		private var _destinationX:int = 150;
		private var _destinationY:int = 150;
 
		// player
		private var _player:MovieClip;
 
		// global
		private var _isActive:Boolean = false;
 
		private var _dx:Number = 0;
		private var _dy:Number = 0;
 
		private var _vx:Number = 0;
		private var _vy:Number = 0;
 
		private var _trueRotation:Number = 0;
 
		/**
		 * Constructor
		 */
		public function Main()
		{
			// create player object
			createPlayer();
 
			// add listeners
			stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
			stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUpHandler);
			stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDownHandler);
		}
 
		/**
		 * Creates player
		 */
		private function createPlayer():void
		{
			_player = new Player();
			_player.x = stage.stageWidth / 2;
			_player.y = stage.stageHeight / 2;
			stage.addChild(_player);
		}
 
		/**
		 * EnterFrame Handlers
		 */
		private function enterFrameHandler(event:Event):void
		{
			updatePosition();
			updateRotation();
		}
 
		/**
		 * Calculate Rotation
		 */
		private function updateRotation():void
		{
			// calculate rotation
			_dx = _player.x - _destinationX;
			_dy = _player.y - _destinationY;
 
			// which way to rotate
			var rotateTo:Number = getDegrees(getRadians(_dx, _dy));	
 
			// keep rotation positive, between 0 and 360 degrees
			if (rotateTo > _player.rotation + 180) rotateTo -= 360;
			if (rotateTo < _player.rotation - 180) rotateTo += 360;
 
			// ease rotation
			_trueRotation = (rotateTo - _player.rotation) / _rotateSpeedMax;
 
			// update rotation
			_player.rotation += _trueRotation;
		}
 
		/**
		 * Calculate Position
		 */
		private function updatePosition():void
		{
			// check if mouse is down
			if (_isActive)
			{
				// update destination
				_destinationX = stage.mouseX;
				_destinationY = stage.mouseY;
 
				// update velocity
				_vx += (_destinationX - _player.x) / _moveSpeedMax;
				_vy += (_destinationY - _player.y) / _moveSpeedMax;
			}
			else
			{
				// when mouse is not down, update velocity half of normal speed
				_vx += (_destinationX - _player.x) / _moveSpeedMax * .25;
				_vy += (_destinationY - _player.y) / _moveSpeedMax * .25;
			}
 
			// apply decay (drag)
			_vx *= _decay;
			_vy *= _decay;
 
			// if close to target, slow down turn speed
			if (getDistance(_dx, _dy) < 50)
			{
				_trueRotation *= .5;
			}			
 
			// update position
			_player.x += _vx;
			_player.y += _vy;
		}
 
		/**
		 * Mouse DOWN handler
		 * @param	e
		 */
		private function onMouseDownHandler(e:MouseEvent):void
		{
			_isActive = true;
		}
 
		/**
		 * Mouse UP handler
		 * @param	e
		 */
		private function onMouseUpHandler(e:MouseEvent):void
		{
			_isActive = false;
		}
 
		/**
		 * Get distance
		 * @param	delta_x
		 * @param	delta_y
		 * @return
		 */
		public function getDistance(delta_x:Number, delta_y:Number):Number
		{
			return Math.sqrt((delta_x*delta_x)+(delta_y*delta_y));
		}
 
		/**
		 * Get radians
		 * @param	delta_x
		 * @param	delta_y
		 * @return
		 */
		public function getRadians(delta_x:Number, delta_y:Number):Number
		{
			var r:Number = Math.atan2(delta_y, delta_x);
 
			if (delta_y < 0)
			{
				r += (2 * Math.PI);
			}
			return r;
		}
 
		/**
		 * Get degrees
		 * @param	radians
		 * @return
		 */
		public function getDegrees(radians:Number):Number
		{
			return Math.floor(radians/(Math.PI/180));
		}
 
	}
 
}
Download Fla Sample

Download Fla Sample

7 Responses

Huge improvement!

Have you thought about adding your vector info to the DisplayObject so you do not have to define them one by one?

_player.dx = value ect.
as well as _player.x = value

Thanks for the post

  • Thanks UsusIpse!

    Ideally, Player should be its own class that holds these values.

    Since I kept everything in one class (for simplicity’s sake), I also left the vector values there.

    Thank you for your input. Highly appreciated!

  • Does not compile. Player() is an undefined method. I’m kinda new at this. Is there something I’m missing, or is there a class file missing from the download?

  • iburry,

    Player() is an exported movieclip in the library of the fla.

  • Wow! Thank you! I had a problem rotating my object. My gun class was moving the other way when it passed the 270 degree mark and the rotation went back to -90, messing up the difference between the desired rotation destination and actual rotation.
    But thank to a few lines of your code (where you correct the mistake by taking or adding 180 degrees, i was able to make it work properly!
    Thank you!

  • Ghosti, that’s a tricky issue to figure out (took me a while!). Glad it helped :)

    -PR

  • I’m kinda new in this whole programming business. Thanks to your scripts I have learned a lot.
    Now I’m courious about one thing. If you click between two consecutive frames there is no effect, i.e. player is not moving toward new direction. Was that your intention?
    I have written few lines of code to “fix” this. If you are interested I could send this file to you.

  • Leave a Reply

    You must be logged in to post a comment.