Tutorial details: Moving a movieclip to the position clicked using actionscript to obtain constant speed no matter what the distance.
Written by: Dennis Bale
Time: 20 Minutes.
Difficulty Level: Intermediate
Requirements: Flash 5
Assumed Knowledge: Basic actionscripting, using the actions window, using variables, creating symbols.

Download the source.


This tutorial is designed to teach you how to create a movie that will have an object move to the location that you last clicked with the mouse. The coding is different from some others, in that I have used a ratio system to move the object at a constant speed, rather than taking a set number of jumps to travel between points. The latter creates an inconsistant effect, which can be detrimental to the overall movie quality.

To start with, create a new movie clip. Make it not too big, containing just a square for example. Place an instance of it on the main stage, and give it the instance name of "bob". Next, select the movieclip, and then open the actions window. It is time to insert some code.

onClipEvent (mouseDown) {
xtarget=_root._xmouse;
ytarget=_root._ymouse;
xstart=this._x;
ystart=this._y;
}

The onClipEvent() handler is used to control actions in an instance of a movie clip, depending on what is happening in the total movie. The code onClipEvent (mouseDown) waits until the mouse button is pressed, anywhere in the movie, and then runs the code inside its curly brackets.

xtarget=_root._xmouse;
ytarget=_root._ymouse;

These are two variables being set. The code _root._xmouse; returns the value of the location of the x-axis of the mouse, and similarly _root._ymouse; will return the value of the location of the y-axis of the mouse. So this means that the variables xtarget and ytarget, will have the values of the mouse's location when we pressed the mouse down. This is the location that we want our movie clip to move to.

xstart=_root.bob._x;
ystart=_root.bob._y;

The code _root.bob._x; will return the value of the _x or horizontal position of the movie clip "bob". _root is a targeting code similar to this or _parent, _root targets the main timeline, and then looks for the movie clip instance named "bob". _root.bob._y does the same as _root.bob._x , except it returns the _y or vertical position of the movie clip.

Next, open the actual movie clip itself for editing, by either double clicking it in the library, double clicking it on the stage, or choosing Edit, from the rightclick menu when the movieclip is selected.

In the first frame of the movie clip, we have this code:

xtarget=_root.bob._x;
ytarget=_root.bob._y;

This code will only be run once, when the movie first begins. It sets the location that we want to move to, equal to the movie clip's current location, so that it doesn't start moving all over the place when the movie first is opened.

Into the second frame we put this code. This is the main part of the program, which creates the movement.

x=Math.abs(xstart - xtarget);
y=Math.abs(ystart - ytarget);

if(x>y){
xspeed=5;
yspeed=5*(y/x);
}else{
yspeed=5;
xspeed=5*(x/y);
}

with(_root.bob){
if(_x > (xtarget+2.5) || _x < (xtarget-2.5) ||_y > (ytarget+2.5) || _y <(ytarget-2.5)){
if(_x>xtarget){
_x = _x - xspeed;
}else{
_x = _x + xspeed;
}
if(_y>ytarget){
_y = _y - yspeed;
}else{
_y = _y + yspeed;
}
}
}

We will break this code up into several sections for ease of understanding. The first part:

x=Math.abs(xstart - xtarget);
y=Math.abs(ystart - ytarget);

The code: xstart - xtarget finds the horizontal distance between the original location of our movie clip, and the target point set in the onClipEvent(mouseDown) ,(xtarget, ytarget). ystart - ytarget does the same for the vertical distance. We need to find these distances, because they are used in finding the correct ratio of speed to move our movie clip. But depending on where you are moving to, these could be negative numbers, and to do this we need them both as positive numbers, or absolute values. So we use Math.abs(); which will convert them to the positive numbers that we need. The horizontal distance is then set as "x", and the vertical distance set as "y". The following diagram helps to explain this.


So, now that we have the distances, we can work out what the ratio of movement needs to be.

if(x>y){
xspeed=5;
yspeed=5*(y/x);
}else{
yspeed=5;
xspeed=5*(x/y);
}

We need to find out which distance is larger, the x or the y, so we put in this code, if(x>y), this evaluates what is inside the brackets, and finds out if it is true or not (if x is larger than y). If it is true, then it will carry out this code:

xspeed=5;
yspeed=5*(y/x);

This sets the distance moved along the x axis per increment to 5, and the distance moved along the y axis equal to 5 times the value of y/x. This is the ratio that creates the constant speed. If x is not a greater number than y, than the opposite code is carried out:

yspeed=5;
xspeed=5*(x/y);

The y incremental distance is set to 5, and the x distance becomes 5 times the value of x/y, the opposite ratio. The next code is what actually moves the movie clip.

with(_root.bob){
if(_x > (xtarget+2.5) || _x < (xtarget-2.5) ||_y > (ytarget+2.5) || _y <(ytarget-2.5)){
if(_x>xtarget){
_x = _x - xspeed;
}else{
_x = _x + xspeed;
}
if(_y>ytarget){
_y = _y - yspeed;
}else{
_y = _y + yspeed;
}
}
}

The line with(_root.bob){ is saying, "with the movie clip instance 'bob', located on the main timeline, do all this:". So everything contained within the curly brackets is about the the movie clip "bob".

if(_x > (xtarget+2.5) || _x < (xtarget-2.5) ||_y > (ytarget+2.5) || _y <(ytarget-2.5)){

This line is asking a question, "Is the movie clip higher or lower than 2.5 units to the target? Or is it greater than 2.5 units to the left or right of the target?". We use the value 2.5, because it is half of the maximum value that could be moved per turn, this way there is always an area big enough for the movie clip to move through, and not leap past. This in terms of a diagram is this:



The || is a notation meaning OR. So, if any of the "questions" above are true, then the following code will be carried out:

if(_x>xtarget){
_x = _x - xspeed;
}else{
_x = _x + xspeed;
}
if(_y>ytarget){
_y = _y - yspeed;
}else{
_y = _y + yspeed;
}

Basically, this code finds out if the movie clip is to the left or right of the target, and then moves it towards the target. It does this by setting the _x position of the movie clip, and adding or subtracting the xspeed value to it. This creates the horizontal movement. It then does the same for the _y position. Adding or subtracting yspeed from it depending on whether it is above or below the target.

Then, that is the end of that frame, and the movie clip will have been moved closer towards the xtarget and ytarget.

We then go to the third frame, and place this line:

gotoAndPlay (2);

This loops the movie clip back to the previous frame, and moves the movie clip closer to its target again. This loop does not stop when the movie clip reaches its destination, but because the xtarget/ytarget and the _x/_y positions are within 2.5 of each other, the third section of the second frame's code is not carried out.

You should now be able to test your movie, and the movieclip will move to the position where you click the mouse in the movie.

To increase or decrease the speed of movement, you can increase or decrease the number 5 in this code:

if(x>y){
xspeed=5;
yspeed=5*(y/x);
}else{
yspeed=5;
xspeed=5*(x/y);
}

The higher the number, the higher the speed of movement. You would also need to change the number 2.5 in this line, so that it is equal to half of the base speed set in the previous code.

if(_x > (xtarget+2.5) || _x < (xtarget-2.5) ||_y > (ytarget+2.5) || _y <(ytarget-2.5)){



So now you have moved a movie clip using action scripting, not tweening. This has many benefits, mostly in that it does not create the huge file sizes that motion tweening can do. It becomes reasonably easy to do all your motion tweens this way, and making them non reliant on mouse clicks. For example you can just have a keyframe action set the variables xtarget and ytarget, and so your movie clip would respond and move accordingly.

I hope that this helps you out. =)