# Shooting in All Directions

April 16, 2001
by Will Turnage

Dear Handyman,

I am making a game that is based on space invaders. I have a ship which is controlled by arrow keys and which can be rotated both anticlockwise and clockwise. The ship fires bullets at the stars and kills them. What I want to know is, is there a way that I can make the bullet fire in the correct direction when the ship is rotated? Maybe it has something to do with angles? Any help would be appreciated.

Thanks,

Bridget

Bridget,

You're absolutely right about it having to do with angles. If you have a point on the screen and an angle, then that gives you a line, and you can calculate that line using Director's sin and cos functions. But before we get into that, let's look at the sample movie.

The movie is pretty simple. The ship can turn in either direction and when you press the space bar, it fires a bullet in the current direction that the ship is facing. There's a behavior on the ship that handles all the keyboard commands. When the user hits the space bar, the following code is executed:

sendSprite (pBulletSpriteNum, #fireBullet, sprite (me.spriteNum).rotation, sprite (me.spriteNum).loc)

In this code, pBulletSpriteNum is a variable representing the sprite number for one of the bullet sprites in the score, and that sprite is sent the fireBullet command. When firing the bullet, the ship sends along its present location and rotation, so the bullet knows where to start firing from and what direction to move. Here is the first part of the code on the bullet's behavior:

property pFired
property pMovePoint

on beginSprite me

pFired = false

end

on fireBullet me, direction, startingPoint

if pFired = false then
pFired = true
rotationInRadians = (direction * pi ()) / 180.0
tempH = 10 * cos (rotationInRadians)
tempV = 10 * sin (rotationInRadians)
pMovePoint = point (tempH, tempV)
sprite (me.spriteNum).loc = startingPoint + (2 * pMovePoint)
end if

end

When the behavior begins, it sets the pFired variable to false, meaning that the bullet isn't currently moving. When the ship tells the bullet to fire, the behavior on the bullet first checks to see if it is currently flying through the air or not. If it's not, then it starts calculating which direction to move in.

The first step in these calculations is to take the rotation of the ship and convert it into radians instead of degrees. A radian is just another way of measuring angles, but it's the measurement that Director uses in its sin and cos functions, so we have to make the conversion. There are 360 degrees in a full circle, and there are 2 * p () or 6.2832 radians in a full circle. To convert between the two:

1 radian = 180 / pi () or 57.2958 degrees

1 degree = pi () / 180 or 0.0175 radians

In this case, you're converting degrees to radians, so you multiply the number of degrees by pi () and divide the result by 180. Now that you have the rotation of the ship in radians, you can calculate the direction your bullet will travel using sin and cos. Most people can get to this point on their own, but the specifics of sin and cos are what throws them off. To help you better understand the relationship, look at the following diagram:

This diagram shows you the ship in its initial position. Surrounding it, you can see lines representing some different rotations of the ship. For each rotation, it also shows the sin and cos value for that angle. From here, you can figure out how to use sin and cos to move your bullets. When you look at the code above, you'll see that the amount the bullet should move horizontally is equal to the cos of the ship's rotation, and the amount that the bullet should move vertically is equal the sin of the ship's rotation.

Once you have these two values calculated, you combine them into a single point value that is used to move the bullet. In this code example, the point is multiplied by a factor of 10 so that the bullet will appear to move quickly across the screen in your movie. If you want it the bullet to move slower or faster, then you can decrease or increase the value of this number to affect the bullet's speed.

Finally, the last part of the fireBullet handler sets the initial location of the bullet equal to the location of the ship, plus the new point representing the bullet's movement. This step is done to make the bullet look like it's coming out of the tip of the ship instead of the actual location of the ship sprite -- which is in the ship's center. Once the bullet has been fired, you can constantly update the location of the bullet by using this handler in your behavior:

on exitFrame me

if pFired then
sprite (me.spriteNum).loc = sprite (me.spriteNum).loc + pMovePoint
if not inside (sprite (me.spriteNum).loc, rect (0,0,320,240)) then
pFired = false
sprite (me.spriteNum).loc = point (5000,5000)
end if
end if

end

On every frame, this handler checks to see if the sprite has been fired. If the sprite has been fired, it continues to move the sprite in the direction established when the sprite was initially fired. Finally, the handler checks to see if the bullet is still on screen. If the bullet has moved off screen, then it resets the pFired variable and moves the sprite off screen.

A sample Director 7 movie is available for download in Mac or Windows format.

Will Turnage is a multimedia programmer based in New York City. In addition to his weekly role as Director Online's Multimedia Handyman, he is also the Technology Director for Sony Music's Client Side Technologies Group. You can read more about his work at http://will.turnage.com/.