# Lesson 17: Movement and Rotation

In a few of the previous lessons we've encountered code that moves objects around on the screen. It's time to explore the various methods that motion can be achieved using vectors, degrees, radians, and rotation.

At some point you're going to need * trigonometry* when making games. I know, I know, that word sounds scary and it's often at this point where budding game programmers give up. Searching the Internet for information on how to add motion and physics to games can be mind numbing. Many times the solutions provided by individuals is cryptic and down-right confusing because they assume you already have a grasp of higher math functions. That was my issue when I started writing games. The answers were there but presented in such a way that it confused me. You're not alone. The highest math I took in high school was Algebra II and by the time I was writing games those lessons were a faded memory. In this lesson I hope to break these concepts down to something everyone can understand. The math involved is surprisingly easy once you get your head wrapped around it.

Don't let the math turn you away. If you are having trouble understanding the concepts presented in this lesson head on over to the QB64 Forum and ask for help. **There are no stupid questions!**

# Vectors

All objects on a computer screen use coordinates to identify where they are located. The **CIRCLE** statement requires a single set of coordinates to identify its center location on the screen. The **LINE** statement requires two sets of coordinates to identify the start and end locations of the line segment on the screen. Yet another command we will investigate shortly is **_MAPTRIANGLE** that requires three coordinate pairs. By modifying an object's coordinates you can effectively move an object around the screen. The direction in which an object moves is known as a * vector*.

A * vector* is a

**directed quantity**that contains a length and direction but

**not position**. For example lets place a circle at coordinate

**200,100**on the screen. In this case the circle's X coordinate is 200 and its Y coordinate is 100. If you want to move the circle up and to the right five pixel coordinates you would need to add 5 to the X coordinate and subtract 5 from the Y coordinate. This moves the circle to the right (X = X + 5) and up (Y = Y - 5). If placed into a loop the circle will continue to move in this direction or

*:*

**vector****x = 200 ' circle's x coordinatey = 100 ' circle's y coordinateDO CIRCLE(x, y), 30 ' draw circle x = x + 5 ' move circle to the right 5 pixels y = y - 5 ' move circle up 5 pixelsLOOP**

This code snippet set up two vectors for the circle. The circle has an **x** vector of **5** and a **y** vector of **-5**. It doesn't matter where the circle's coordinates start since all that matters to a vector is how long it is (* the quantity*) and the direction it travels in (

*). The circle could be placed at*

**the quantity's sign****300,300**but these vector quantities will always result in the circle moving up and to the right. The vector quantities can be placed in their own variables like so:

**x = ****300**** ' circle's x coordinatey = **

**300**

**' circle's y coordinate**

Vx = 5 ' x vector of 5 (right)

Vy = -5 ' y vector of -5 (up)

DO

CIRCLE(x, y), 30 ' draw circle

x = x +

Vx = 5 ' x vector of 5 (right)

Vy = -5 ' y vector of -5 (up)

DO

CIRCLE(x, y), 30 ' draw circle

x = x +

**Vx**

**' move circle**

**x vector direction**

**y = y**

**+ Vy**

**' move circle**

**y vector direction**

**LOOP**

By varying the values of **Vx** and **Vy** you can effectively have the circle move in any direction you wish. Here is a simple example showing this in practice. The file **BallVectorDemo.BAS** can be found in your **.\tutorial\Lesson17\** directory.

Lines 15 and 16 of the code set up random vector quantities of -5 to 5 for both the X and Y vectors. Lines 20 and 21 update the circle's position by adding these vector quantities to the circle's current position. If the circle hits the side of the screen as determined by lines 22 and 25 the * sign* of the vector is changed. This effectively reverses the circle's direction by altering the vector by 180 degrees.

In the example code above the speed of the circle is a fixed quantity. In order to change the speed of the circle the length of the vectors (* the quantity*) needs to be changed. This is typically done by multiplying the vector quantity by a given speed. However the code above produces vector quantities in the range of

**-5**to

**5**and multiplying by a fixed speed value will produce an inconsistent result. The best way to handle this is to have vectors stay within the range of

**-1**to

**1**producing a speed that is consistent. This is done by

*the the vectors into*

**normalizing***with values between*

**unit vectors****-1**and

**1**.

To normalize a vector you simply set up a right triangle using the vector quantities. Then use the Pythagorean Theorem to calculate the length of the vector (* the hypotenuse*) and finally divide the original vector quantities by the calculated length.

**Figure 1**below demonstrates this:

**Figure 1: Normalizing vector quantities**

The **Vx** and **Vy** vector quantities are calculated by subtracting the x values and y values to obtain the vector lengths. You may be wondering why bother since we already know the vector quantities. We'll get to that a little later in the lesson. **Vx** and **Vy** are now side A and side B of the right triangle. The length of the vector is calculated using the Pythagorean Theorem. Finally, that length is used to divide the original **Vx** and **Vy** vector quantities producing a result of **-1** to **1**. Now a speed multiplier can properly be applied to the vector quantities as the following example program illustrates. This program **BallSpeedDemo.BAS** can be found in your **.\tutorial\Lesson17\** directory.

In lines 18 through 22 we used the formula in **Figure 1** above to normalize the vectors to between **-1** and **1**. In lines 34 and 35 the vector quantities are added to the circle's location just like before but this time the value in **speed%** is multiplied to the vector quantity effectively increasing the number of pixels the circle moves in the same direction. The value in **speed%** is kept between **1** and **20** guaranteeing 1 to 20 pixel movements for the circle. In the first code example this could not be guaranteed because the vectors were not normalized. Each time the code would have been run the maximum speed would have varied wildly.

# The _HYPOT Statement

The **SQR** statement (square root) was used in the previous two code examples to calculate the length of the vector using the Pythagorean Theorem. **SQR** is used to calculate the hypotenuse of the triangle that the theorem works with. However, **SQR** is a very slow statement which is why QB64 offers the **_HYPOT** statement. The **_HYPOT** statement calculates the hypotenuse given the other two sides of the triangle:

**Length! = _HYPOT(SideA!, SideB!) ' calculates the hypotenuse**

You simply supply the side lengths and don't need to worry about squaring them first. **_HYPOT** is faster than using **SQR** so for the rest of this course **_HYPOT** will be used in lieu of **SQR** for length and distance calculations. The previous two code examples only control one object on the screen and you would not be able to tell the difference between **SQR** and **_HYPOT**. However, when you start creating games that control hundreds of objects on the screen these optimizations make a huge difference.

# Smart Vectors

Up to this point all of the example code has had an object rambling around with no purpose other than to bounce off the sides of the screen. In games you want enemies to chase you and their bullets to fire in your direction. You also want to be able to shoot your bullets in any given direction you desire. Using vectors is one of the simplest methods of achieving this. Remember these calculations in **Figure 1** above?

**Vx = x2 - x1Vy = y2 - y1**

These two statements now come into full use when you want to make a vector that points toward another object. Instead of using the coordinate (**0, 0**) for that start of the vectors as **Figure 1** demonstrates you would use the coordinates of the object that you want to get a vector * from*. The end of the vectors are the coordinate of the object you are pointing

*.*

**to****Remember, a vector does not care about location as it only contains length and direction.** So a vector coordinate starting at one object and ending at another object's coordinates is perfectly fine, it's still a vector, a simple * directed quantity*. You simply make a right triangle between the two objects and solve for the equation in

**Figure 1**above. The result will be a normalized vector pair that can be applied to another object, such as a bullet, that flies from the first object to the second one. Or you can use the vector pair to direct the

*object towards the*

**from***object as the following example code illustrates. This code can be found as*

**to****TagVectorDemo.BAS**in your

**.\tutorial\Lesson17\**directory.

**Figure 2: Tag, You're it!**

By calculating the vector between the two circles and applying that vector to the red circle it becomes "**smart**" and can directly follow the green circle that you control. Before we get into the code a few things to note:

Line 36 ends in an underscore (

**_**) character which means the remainder of the statement is contained in line 37. Remember, an underscore can be used to segment large lines of code into multiple lines for easier viewing.The formula in

**Figure 1**has been turned into a function called**P2PVector**that takes two x,y coordinate pairs as input and returns a normalized vector pair.**P2PVector****FromPoint, ToPoint, NormalizedVector**

Since vectors come in pairs a

**TYPE**definition named**XYPAIR**has been created to easily handle them. This same**TYPE**definition can also hold**x,y**coordinate pairs so we get bonus double duty from it.

Lines 8 through 12 create a **TYPE** definition for a circle object containing an **x,y** coordinate pair, an **x,y** vector pair, and a radius. The **x,y** coordinate pair is a circle's current location and the **x,y** vector pair is the direction a circle is traveling in.

Lines 14 and 15 are setting up the player and enemy circle objects that can be manipulated around the screen.

The player's position is updated and drawn in lines 28 through 32.

Line 33 is where the magic happens:

**P2PVector**** RCir.loc, GCir.loc, RCir.vec**

The red circle and green circle's positions are passed to the function where the vector normalizing formula is performed. The normalized vectors are then returned and placed into **RCir.vec**. **P2PVector** is a subroutine and unlike a function it can't return a result in its name so **RCir.vec** that is passed by reference is modified within the subroutine and those changes are returned. The red circle's vector values have now been altered and point directly at the green circle.

In line 38 a function called **P2PDistance** is passed both circle's locations and if the distance between the circles is greater than both radii added together the red circle's location is updated in lines 39 and 40. Line 38 is a basic circle collision detector. Lines 39 and 40 use the updated vector values to move the red circle in the direction of the green circle.

Loop back around and do the whole process again. No matter how often the green circle is moved around line 33 will guarantee that the normalized vectors are calculated to keep the red circle traveling toward the green circle.

The white line inside the red circle that always points towards the green circle is created in line 36 (and 37). A line is drawn from the center of the red circle to a point in the same direction as the red circle's vector value multiplied by its radius. It's the same concept as multiplying the vector by a speed, just in this case we use the circle's radius as one big leap.

**Controlling Multiple Objects**

Using vectors along with arrays allows you to control many directed objects on the screen at once as the following example code illustrates. Move the cross hair around the screen with the mouse and use the left mouse button to fire a bullet. Hold the left mouse button to increase the fire power and speed of the bullet. This code can be found as **VectorShootDemo.BAS** in your **.\tutorial\Lesson17\** directory.

**Figure 3: The start of a bullet hell game**

All of the action controlled on the screen is done with nothing more than normalized vectors. All of the variables needed to manipulate each individual bullet is held in a dynamic array named **Bullet()**. The dynamic array is allowed to grow as needed to accommodate more bullets and reset when no active bullets are present. Each bullet's location ( **Bullet().loc** ), vector ( **Bullet().vec** ), speed ( **Bullet().speed** ), color ( **Bullet().col** ), and status ( **Bullet().active** ) are all maintained in the array using the **TYPE** definition **BULLET**.

The **DrawBullets** subroutine is used to draw active bullets onto the screen with the information provided in the array. If the subroutine detects there are no active bullets left the **Bullet()** array it is reset back to a zero index. This ensures that the array only grows as large as needed for any given amount of bullets on the screen.

The **FreeIndex** function scans the array for any indexes where the bullets have become inactive and returns that index value to place the next bullet into. If the function detects that there are no free index values available it increases the array size by one and passes that new index value back to place the next bullet into. By reusing inactive indexes and only increasing the array size when necessary the array size is kept as small as possible at all times. If you are familiar with "Bullet Hell" games you know there can literally be hundreds of bullets flying around the screen at any given time. Using a fixed static array would be possible to track them all but the method of using an array that can adjust to the amount of objects needed is ideal.

**Where are the variable type identifiers?**

If you haven't noticed yet you don't need to use variable type identifiers, such as **%** for integer and **!** for single, to identify a variable's type. The first two code examples use type identifiers on all of the variables. However the following two code examples did not. These two lines mean exactly the same thing:

**DIM Count%DIM Count AS INTEGER**

As well as these:

**DIM KeyPress$DIM KeyPress AS STRING**

You can even control the size of strings by doing this:

**DIM KeyPress AS STRING * 1 ' a string variable with a length of one**

We discussed in an earlier lesson that the variable declarations inside of **TYPE** definitions require that variables type identifiers be spelled out:

**TYPE XYPAIR x AS SINGLE Y AS SINGLEEND TYPE**

However this method of identifying variable types can be used everywhere. **This is a personal preference of the programmer.** The main advantage of using type identifiers is that it makes it easy to know the type a variable is no matter where it resides in the source code. When code starts getting very large all of the type identifiers can make code seem cluttered (*in my opinion, perhaps not another programmer's*). From this point on all example code will have variable type identifiers spelled out.

# Degrees and Radians

Vectors are perfect for setting objects in motion and pointing an object toward a **known point** but what if you want your object to travel at a precise 34.5 degree angle? Which vector quantity values would you need to use to achieve this? The answer lies with incorporating * radian* and

*values found around the perimeter of a circle.*

**degree**A circle contains * radian* points on its perimeter ranging in value from

**0**to

**6.2831852**, or

**0**to 2 times the value of Pi (

**3.1415926**). A

*is a direct relationship between the radius of the circle and its arc. If you want to read more about that relationship you can visit this page. All you need to know to incorporate this knowledge into game programming is that these values exist as shown in*

**radian****Figure 4**below.

**Figure 4: Radians, degrees, and the associated conversion formulas**

The points around a circle's perimeter can also be expressed in * degrees* also shown in

**Figure 4**above. The two formulas needed to convert between the two systems are given as well. QB64 makes the conversion process simple as it offers two statements to perform the calculations for you.

# The _D2R and _R2D Statements

The **_D2R** statement takes a given degree value from **0** to **359.9999** and converts it to the equivalent radian:

**Radian! = _D2R(Degree!) ' convert degree to radian**

and the **_R2D** statement takes a given radian value from **0** to **6.2831852** and converts it the equivalent degree:

**Degree! = _R2D(Radian!) ' convert radian to degree**

# Degrees and Radians to Vector

Once you have either a desired degree or radian heading you can then convert that value to a vector as shown in **Figure 5** below.

**Figure 5: Radian and degree to vector conversion**

Radians can be converted directly to vector quantities using the **SIN()** (sine) and **COS()** (cosine) functions. Degrees will need to be converted to radians first as shown in the **DEGREE TO VECTOR** conversion in **Figure 5**. The degree to radian conversion formula seen in **Figure 4** is embedded within the **SIN()** and **COS()** functions. Using **_D2R** the conversions would look like this:

**Vx! = SIN(_D2R(Degree!)) ' calculate the x vector quantityVy! = -COS(_D2R(Degree!)) ' calculate the y vector quantity**

This lesson isn't going to go into any discussion about sine and cosine and how they relate to radians. Again, all you need to know for game programming is that these functions are used to convert radian and degree points around the perimeter of a circle to vector quantities. If you wish to read more about sine and cosine you can visit this web site.

# Vector Graphics

Ok, enough with the formulas for now. Let's put this information to practical use with an example program. Use the **RIGHT** and **LEFT ARROW** keys to rotate the space ship. Use the **UP ARROW** key to move the ship in the direction it is facing. The following program named **RadianShipDemo.BAS** can be found in your **.\tutorial\Lesson17\** directory.

**Figure 5: A ship made with radians and vectors (Asteroids)**

This program allows you to envision the underlying imaginary circle that controls everything. The center of the ship is the center of the circle and the ship's vertices are simply radian values on that circle. The radian that creates the ship's nose point is used to calculate a vector quantity from. Which ever direction the nose is pointing is the direction the ship will travel because the vectors are calculated using this radian.

Lines 30 through 34 fill the **Rad()** array with **72** radian values spaced evenly **5** degrees apart from each other. Lines 35 through 37 identify the radian points on the circle where the ships lines are to be drawn creating the outline of the ship. **Rad(0)** is the front of the ship, **Rad(28)** is the lower right corner of the ship, and **Rad(44)** is the lower left corner of the ship. These three array index values are held in the **Ship()** array.

When the ship is rotated to the right these three values are increased by one. If one of the index values should happen to pass the highest index value of **71** it is reset back to **0** which now points to the beginning of the circle. Likewise when the ship is rotated to the left the three values are decreased by one. If one of the index values should happen to pass the lowest index value of **0** it is reset back to **71** which now points to the end of the circle. The left and right motion is handled in lines 55 through 62 within the **FOR ... NEXT** loop.

Also within the **FOR ... NEXT** loop in lines 48 through 63 each of three values has a vector calculated from it. Lines 49 and 50 use the radian value stored in the **Rad()** array to calculate a vector. Remember, vectors don't care about * location*, only a

*and*

**length****direction**and these two lines of code calculate that for us.

The * location* is now added to these vectors in lines 64 through 67. The

*and*

**length***of each vector is multiplied by*

**direction****ShipSize**and then added to the ship's

**x**and

**y**coordinates.

**ShipSize**is nothing more than the radius of the imaginary circle that follows the ship around. This brings the three points out to the perimeter of the circle where the

**LINE**command is used to "connect the dots" of the three points to draw the ship.

Lines 75 through 82 of the code control the motion of the ship. When the **UP ARROW** key is pressed lines 76 and 77 use the vector quantity information stored in **Ship(1).Vx** and **Ship(1).Vy** to calculate a new ship location. The **Ship(1)** vector quantities are related to the front of the ship so the ship moves in the current direction the ship is pointing.

This method of calculating vector quantities from radian points to draw lines on the screen is often referred to as Vector Graphics and was used in early arcade games such as Asteroids and Tempest. By using radians to point in a given direction and then converting that radian value to vector quantities you can now control in which direction an object points and moves without the need to reference another point as is required for vector math alone.

The example above works perfect for objects that fit neatly into a circle such as the ship did. With a bit of modification this method can also be used for irregular shapes that do not fit neatly into a circle. The next code example shows how irregular shaped objects can be stored in an array and then used later on to create the shape in any position, size, or rotation desired. The following source code can be found as **RadianAsteroidDemo.BAS** in your **.\tutorial\Lesson17\** directory.

**Figure 7: Beware, falling rocks ahead**

Each point on the asteroids was created from a combination of a radian and radius length values. **Figure 8** below describes this process.

**Figure 8: Storing an irregular shaped object**

The asteroid object **x,y** vector points are stored in line 88 of the code as a **DATA** statement. The **FOR ... NEXT** statement in lines 36 through 40 **READ**s each set of values in and then converts them to a radius (length) and radian value. The next **FOR ... NEXT** statement in lines 41 through 47 sets up the **Asteroids()** array that contains each asteroid's location ( **Asteroid().Loc.x/y** ), the radian direction of travel ( **Asteroid().Dir** ), the asteroid speed ( **Asteroid().Speed** ), and finally the size of each asteroid ( **Asteroid().Size** ).

This information is then used in the **FOR ... NEXT** loop contained in lines 61 through 83. Lines 62 through 66 takes the first set of values in **Object(1)**, converts the radian to a vector quantity, and then calculates the position on screen and saving the results in **P1.x** and **P1.y**. The **PSET** statement is used to draw a pixel at the location as a * place-holder* for the

**LINE**statements that will follow.

The **FOR ... NEXT** loop in lines 67 through 73 cycle's through the remaining **Object(2-10)** values. Just like the first point these values are used to create the remainder of the screen positions. This time however a **LINE** statement is used to continue from the last screen position used and "**connect the dots**".

Line 74 completes the outer perimeter of the asteroid by joining the last point back to the first with a **LINE** statement.

Lines 75 through 78 then creates a motion vector using the radian value found **Asteroid().Dir** and adds those vector quantities to the **x** and **y** locations of the asteroid. Lines 79 through 82 detect if the asteroid is leaving the screen and if so wraps it around to the opposite side.

If the user presses the space bar to active asteroid rotation the variable **Spin** is set to **TRUE** which then activates the **IF** statement in line 55.

The **FOR ... NEXT** statement in lines 56 through 59 cycles through each **Object()**'s radian value and adds the value in **SPINRATE** to it, effectively causing the radian to move clockwise ever so slightly. Line 58 ensures that if the radian value exceeds the value of **2 * PI** the value is wrapped back around to the beginning of the radian range by subtracting **2 * PI**.

It's an amazingly small piece of code that achieves so much. To keep the code to a minimum for the tutorial purposes however a trade off was made. The spin of each asteroid can't be independently controlled since there is only one master **Object()** array to work with. To allow for independent spin rates and directions for each asteroid a separate **Object()** array for would be needed for each asteroid significantly increasing the size of the code. This will also allow for a greater variety of asteroids instead of just the one depicted on screen but for display and learning purposes this example code gets the point across very well.

# A Trigonometry Visual Aid

Some people learn best by reading and doing, others through lectures, and still others through visual instruction (like the author). To this end the following program was created for the tutorial to help those who may benefit from seeing the actual math and graphics in motion in real time. The source code to the program **TrigDemo.BAS** can be found in your **.\tutorial\Lesson17\** directory. You'll also need to make sure the files **glinputtop.BI** and **glinput_noerror.BI** are in the same directory as **TrigDemo.BAS**. The **BI** files are library add-ons needed for the program to run. (You'll learn about libraries in a later lesson.)

**Figure 9: The relationship between radians, degrees, and vectors**

**Figure 10: Showing the relation between two objects**

**Figure 9** above shows the screen as it appears when you first run the program. The radian will sweep across the circle at first in an animated sequence. In the upper left hand corner you can enter a degree, radian, or vector and that graphical representation will appear within the circle along with all the math formulas filled out with the correct results.

**Figure 10** above shows the second page. This page will allow you to enter two coordinate values and the relationships between them will be shown graphically within the grid window. The "from" coordinate is shown as the center of the circle and the "to" coordinate lies on the circle's perimeter. This relationship illustrates how the circle is still present as described on the first page.

This program also makes a handy little reference to have at your side to remember all the formulas and how to set them up.

# Sprite Rotation

The previous asteroid example isn't the only way to rotate a set of points around a common center. Another method is to use something called a * rotation matrix*. A

*is an advanced trig concept but basically it's used to perform a rotation in a given space. This lesson is not going to go into*

**rotation matrix***detail but if you're interested you can visit this page to read more.*

**rotation matrix**The rotation matrix converts to these four lines of code:

**SINr! = SIN(-Angle! / 57.2957795131) ' get the sine of the radianCOSr! = COS(-Angle! / 57.2957795131) ' get the cosine of the radianVx! = x! * COSr! + SINr! * y!) ' calculate new x vectorVy! = y! * COSr! - x! * SINr!) ' calculate new y vector**

**x!** and **y!** are the vectors where the point currently lies. **Angle!** is the * degree* in which to rotate the

**x!**and

**y!**vectors toward. The calculation

**-Angle! / 57.2957795131**in the first two lines are converting the angle degree into a radian. Finally,

**Vx!**and

**Vy!**are the new vector coordinates for the point. These four lines will only work when it's assumed that the center of rotation is coordinate

**(0, 0)**.

In the next code example this rotation matrix is used to rotate the four corners of an image. Once rotated the **_MAPTRIANGLE** command is used to map the original image onto a new image surface using the rotated **Vx!** and **Vy!** coordinate locations. The code named **SpriteRotateDemo.BAS** can be found in your **.\tutorial\Lesson17\** directory.

**Note:** The four lines of code above were written by the original author of QB64, Rob (Galleon).

**Figure 11: Rotating the bee image and setting it free**

It's important to remember that a sprite's dimensions, the width and height, will change as it transitions through the rotation. If you replace line 38 with this code:

**_PUTIMAGE (Bee.x, Bee.y), RotImg ' image not centered**

you'll be able to see the size differences as the image will appear to wobble as it is drawn. You always need to use the center point of a sprite you wish to rotate to ensure the rotation looks correct. Lines 38 and 57 correct this:

**_PUTIMAGE(Bee.x - _WIDTH(RotImg) /2, Bee.y - _HEIGHT(RotImg) / 2), RotImg**

by moving the image to the left half of it's width and up half of it's height to ensure that **Bee.x** and **Bee.y** are truly the center point of the sprite.

For the best possible sprite rotations it's always best to use sprite images that have widths and heights that are not divisible by 2 (odd numbers). Sprites with these dimensions will have a true center point to work with and rotate as smoothly as possible.

In the **RotateImage** subroutine this centering of the sprite also has to be taken into account. Lines 105 through 114 retrieves the width and height of the image passed in. Four vector pairs are then created, **px(0),py(0)** through **px(3),py(3)**, that create an area equal to the size of the image that has the coordinate **(0,0)** as the center point. The rotation matrix algorithm needs the center point to be **(0,0)** to rotate the four vector quantities around the center.

Lines 115 and 116 pre-calculate the sine and cosine of the radius used to rotate the four points. Lines 117 through 127 then loops through all four vector pairs which applies the matrix rotation algorithm them in lines 118 and 119. Lines 122 through 125 record the lowest and highest values for x and y coordinates seen. As stated earlier the size of the rotated sprite will change and lines 122 through 125 record this change.

Lines 128 and 129 then calculates the new rotated image width and height dimensions and are used to create the new image holder for the rotated image in line 138.

The center point however is still coordinate **(0,0)** so all vector points need to be shifted to the right and down half of the image width and height to put coordinate **(0,0)** back into the upper left corner of the image. This is performed in lines 133 through 137.

Finally the original image needs to be mapped onto the new image using the new vector quantities as the four points for the image. The **_MAPTRIANGLE** statement is used to do this. **Figure 12** below shows this process.

**Figure 12: Using _MAPTRIANGLE**

**_MAPTRIANGLE** is used to grab any three coordinate points of an image and then map the resulting triangular image to any three subsequent points. It can even handle 3D drawing. Check out the **_MAPTRIANGLE** Wiki page for more information and abilities of this statement.

As an added bonus since you know the degree angle of rotation for the sprite you can use that information to set a vector for sprite motion. Lines 52 through 56 takes the degree angle and converts it to a radian. Vector quantities are then created from the radian value and finally added to the bee's location multiplied by a desired speed. You can now set your rotated sprites free.

Here's some code that puts everything covered in this lesson into use. The code named **ZombieRotate.BAS** can be found in your **.\tutorial\Lesson17\** directory.

**Figure 13: They're coming to get you Barbara!**

This example makes use of sprites, a sprite sheet, sounds, and animation. Looks like a good start to a Zombie stalker game. Move the brain around on the screen with the mouse and watch the Zombie hungerly chase it. Again, it's amazing how little code is required to create something like this.