In the example above, we move the arrows using Math.cos and Math.sin, just like when we moved the ball in Rotate and Move an Object Using Sine/Cosin, AS2. The difference is that instead of using the LEFT and RIGHT arrow keys to change the angle of the object, we will be calculating the angle using the current position of the mouse cursor. We do this by using the atan2() function. First, let's take a look at the function that rotates our main arrow...
function rotateArrow(){
arrowAngle = Math.atan2(_root.arrow_mc._y-_ymouse,_root.arrow_mc._x-_xmouse);
arrowAngle = arrowAngle * (180/3.1415)-90;
_root.arrow_mc._rotation = arrowAngle;
}
First we call the Math.atan2 function, passing in the x and y positions of the arrow and the mouse. The returned value is stored in the variable arrowAngle, which we convert from radians to degrees. We then use this angle to rotate the actual object by assigning the arrowAngle to the object's _rotation.
These are all of the variables used in this example:
stop();
var throwfx:Sound = new Sound();
throwfx.attachSound("throwfx");
var hitfx:Sound = new Sound();
hitfx.attachSound("hitfx");
var ARROW_X = 125;
var ARROW_Y = 250;
var arrowAngle;
var arrowSpeed = 15;
var arrowFired:Array = new Array();
var arrowFiredAngle:Array = new Array();
for (i=1; i<=50; i++){
duplicateMovieClip(arrow_mc, "arrow_mc"+i, this.getNextHighestDepth());
_root["arrow_mc"+i]._y = 350; //move offscreen
arrowFired[i] = false;
}
First, we have two Sound objects that control the sound FX. Next, we have two constants that hold the value of our main arrow's x and y positions. arrowAngle and arrowSpeed are pretty self explanatory. Next is an array of Booleans called arrowFired which we will use later to test if a particular arrow is currently being fired or if it is ready to be fired again. The array arrowFiredAngle will hold a unique angle for each arrow fired. The last thing we need to do is decide how many arrows we want to be available, and then duplicate our main arrow that many times. After duplicating each arrow, we move it off screen and set the corresponding arrowFired Boolean to false.
Next, let's look at the function that actually moves each arrow...
function moveArrow(){
for(i=1; i<=50; i++){
if(arrowFired[i] && isArrowOnScreen(i)){
_root["arrow_mc"+i]._x += arrowSpeed * Math.cos(arrowFiredAngle[i]);
_root["arrow_mc"+i]._y += arrowSpeed * Math.sin(arrowFiredAngle[i]);
}
}
}
This function works by checking each arrow's corresponding Boolean arrowFired to see if it's active or not. If arrowFired is set to true, the corresponding arrow is moved using the variable arrowSpeed and it's unique arrowFiredAngle which was recorded in the mouse listener when the mouse button was clicked.
var mouseListener:Object = new Object();
mouseListener.onMouseDown = function(){
for(i=1; i<=50; i++){
if(!arrowFired[i]){
throwfx.start();
arrowFired[i] = true;
arrowFiredAngle[i] = Math.atan2(_ymouse-ARROW_Y,_xmouse-ARROW_X);
_root["arrow_mc"+i]._y = _root.arrow_mc._y; //move back
_root["arrow_mc"+i]._x = _root.arrow_mc._x; //move back on screen
_root["arrow_mc"+i]._rotation = arrowAngle;
break;
}
}
}
When the mouse is clicked we use a for-loop to search for the next available arrow. Once it is found, we set it's corresponding arrowFired Boolean to true, record the angle using Math.atan2 and the current x/y positions of the main arrow and mouse, and then move the now active arrow onto the screen and set it's rotation. Now it is ready to be fired and is eligible to be moved by the moveArrow function.
All that's left is, what to do with the arrow once it has hit it's target. In this example there is no actual target so we will just reset each arrow once it has landed off-screen.
function resetArrow(){
for(i=1; i<=50; i++){
if(!isArrowOnScreen(i)){
if(_root["arrow_mc"+i]._alpha == 100){
hitfx.start();
}
_root["arrow_mc"+i]._alpha -=1;
if(_root["arrow_mc"+i]._alpha <= 0){
_root["arrow_mc"+i]._alpha = 100;
_root["arrow_mc"+i]._x = ARROW_X;
_root["arrow_mc"+i]._y = 350; //hide off screen
arrowFired[i] = false;
}
}
}
}
The resetArrow function searches the array of arrows and checks to see if they are completely on the screen or not. If an arrow is off screen it's transparency is decreased until it is completely invisible. Once it is not longer visible it is moved off screen and it's values are set back to default. Notice that the sound effect is played only when the arrow is completely visible. This prevents the sound effect from playing more than one time per arrow.





