Working with Friction

[ LiB ]

Friction is a force created when objects act in opposition to one another. It may not be obvious, but friction can be caused by air particles and other objects. If there were no friction, you would be able to literally throw a ball around the world. How crazy is that? To show you how realistic a main character can look with a little friction and a few other forces added, I have written up a demo. Open up GDA_PROG12.5.fla.

Figure 12.8 shows what you are about to experience. The demo starts off with a small aircraft in the center of the screen. The first thing you notice is generating ammo that appears on the screen right under the ship. There is also a bouncing enemy that annoys youshoot at it in order to gain points.

Figure 12.8. A physics demo

graphic/12fig08.gif


You can move the ship in two ways: You can use the arrow keys or you can drag it with the mouse. You can then shoot at the enemy with the spacebar. Move the ship around with the keyboard and experience all the forces you've learned about.

Let's start by dissecting all the code on the main Timeline; then we'll go into the buttons and Movie Clips. The following listing shows the code on the first frame of this movie.

 stop(); onLoad = function () {       attachMovie("ammo", "beam", 3);       beam.x = 0;       beam.y = 0;       beam.status = "passive";        attachMovie("enemy", "badguy", 2);       badguy.status = "alive";       badguy._y = Math.random()*(400-badguy._height);       badguy._x = Math.random()*(440-badguy._width);       badguy.dir_x = 10;       badguy.dir_y = 10;       unDieCount = 0;       // Make them invisible for the first frame       beam._visible = false;       badguy._visible = false; }; onUnload = function () {       beam.removeMovieClip();       badguy.removeMovieClip(); }; onEnterFrame = function () {       // Compute the ammo       if (beam.status == "passive") {              beam.x = player._x-9;              beam.y = player._y-20;       }       if (beam.status == "fired!") {              beam.y -= beam._height;              if (beam.y < -beam._height) {                     beam.status = "passive";                     beam.gotoAndPlay("fadein");              }       }       beam._x = beam.x;       beam._y = beam.y;       // Compute the bad guy       if (badguy.status == "alive") {              badguy._x += badguy.dir_x;              badguy._y += badguy.dir_y;              if (badguy._x  > (439-badguy._width))               badguy.dir_x = -badguy.dir_x;      if (badguy._x < 0)              badguy.dir_x = -badguy.dir_x;      if (badguy._y > (399-badguy._height))              badguy.dir_y = -badguy.dir_y;      if (badguy._y < 0)              badguy.dir_y = -badguy.dir_y;      if (badguy.hitTest(beam)) {             if (beam.status == "fired!") {                    player.score += 10;                    beam.status = "passive";                    badguy.status = "dead";                    badguy._alpha = 30;             }           }    } else if (++unDieCount > 12) {          unDieCount = 0;          badguy.status = "alive";          badguy._alpha = 100;    } }; 

The first thing I did in this onLoad function was create the beam instance. I also created some new properties within; they will help me track the aircraft later on. The status property will help me figure out if the beam has been fired or not.

 attachMovie("ammo", "beam", 3); beam.x = 0; beam.y = 0; beam.status = "passive"; 

The next thing I set up was our enemy, badguy . This guy has a lot of propertiestake a look:

 attachMovie("enemy", "badguy", 2); badguy.status = "alive"; badguy._y = Math.random()*(400-badguy._height); badguy._x = Math.random()*(440-badguy._width); badguy.dir_x = 10; badguy.dir_y = 10; unDieCount = 0; 

The unDieCount variable helps me freeze the enemy in a dead state long enough for the user to see that the program is reacting to a hit.

As the demo doesn't start till the second frame, I've decided to hide the ammo and the bad guy until the user presses the button.

 beam._visible = false; badguy._visible = false; 

The next snippet is from the onEnterFrame function that makes the ammo follow the ship if it's not being fired.

 if (beam.status == "passive") {         beam.x = player._x-9;         beam.y = player._y-20; } 

And if the ammo has been fired, go ahead and move it up.

 if (beam.status == "fired!") {         beam.y -= beam._height; 

When the missile hits the end of the screen, it is reset. Once I set the missile to passive, the code I went over previously will make the ammo follow the aircraft again.

 if (beam.y < -beam._height) {         beam.status = "passive";         beam.gotoAndPlay("fadein"); } 

Right after the properties are updated in the ammo Movie Clip, I start to check what's up with the enemy. If he's not alive, we move him.

 if (badguy.status == "alive") {        badguy._x += badguy.dir_x;        badguy._y += badguy.dir_y; 

To make the enemy bounce off the sides of the walls, I had to reverse the velocities once I detected a hit.

 if (badguy._x > (439-badguy._width))         badguy.dir_x = -badguy.dir_x; if (badguy._x < 0)         badguy.dir_x = -badguy.dir_x; 

I also had to test the top and bottom walls.

 if (badguy._y > (399-badguy._height))         badguy.dir_y = -badguy.dir_y; if (badguy._y < 0)         badguy.dir_y = -badguy.dir_y; 

If the ammo is fired and it collides with the enemy, then I add to the score and reset everything.

 if (badguy.hitTest(beam)) {       if (beam.status == "fired!") {               player.score += 10;               beam.status = "passive";               badguy.status = "dead";               badguy._alpha = 30;       } } 

The reason I'm testing to see if the beam status is fired is because I don't want the beam to hit the enemy when it's still on the ship. If all these tests result to true, everything is reset and the bad guy dies. Cool, eh?

So what happens when the enemy is dead? Take a look at the code:

 } else if (++unDieCount > 12) {         unDieCount = 0;         badguy.status = "alive";         badguy._alpha = 100; } 

When the bad guy status is dead , the bad guy is dimmed. It will stay dimmed for at least 12 frames until this last condition is true. Once unDieCount is over 12, it resets itself and the bad guy is brought back to life.

Now that we know how the other stuff is controlled, let's see how the bad guy and the beam become visible once you go to the next frame. The following is the code found in the button:

 on (release) {   beam._visible = true;   badguy._visible = true;   nextFrame(); } 

Let's jump into the code that I stored within the aircraft's Movie Clip.

 // Game Development with ActionScript // By Lewis Moronta (c) 2003 // This demo demonstrates how to // incorporate physics within your game. onClipEvent(load) {          // Setup some properties         score = 0;         vel_x = 0;         vel_y = 0         acel_x = 4;         acel_y = 4; } onClipEvent(enterFrame) {         // Move the ship         _x += vel_x;         _y += vel_y;         // Check boundaries         if (_x < 0)                 _x = 0;         if (_x > (440-_width))                 _x = 440-_width;         if (_y < 0)                 _y = 0;         if (_y > (400-_height))                 _y = 400-_height;         // Slow down the ship         // by simulating friction         if (vel_x > 0)                 vel_x--;         if (vel_x < 0)                 vel_x++;         if (vel_y > 0)                 vel_y--;         if (vel_y < 0)                 vel_y++;         // CONTROLS //////////         if (Key.isDown(Key.LEFT)) {                 vel_x -= acel_x;                 if (acel_x < -16)                         acel_x = -16;          }         if (Key.isDown(Key.RIGHT)) {                vel_x += acel_x;                if (acel_x > 16)                        acel_x = 16;         }         if (Key.isDown(Key.UP)) {                vel_y -= acel_y;                if (acel_y < -16)                        acel_y = -16;         }         if (Key.isDown(Key.DOWN)) {               vel_y += acel_y;               if (acel_y > 16)                       acel_y = 16;         }         if (Key.isDown(Key.SPACE)) {               _root.beem.status = "fired!";         }         _parent.scoreDisplay = "SCORE: "+score; } onClipEvent(mouseDown) {         if (this.hitTest(_root._xmouse, _root._ymouse)) {                this.startDrag();                Mouse.hide();         } } onClipEvent(mouseUp) {         this.stopDrag();         Mouse.show(); } 

In the beginning, there was velocity and acceleration. There was also another property named score . These are the variables initialized when the clip is loaded.

In the onEnterFrame handler, I wrote code to add velocity to the aircraft's current position even if it's stationary.

 _x += vel_x; _y += vel_y; 

One of the first things I did after this was check to make sure that our player doesn't move out of the stage's viewable area.

 if (_x < 0)         _x = 0; if (_x > (440-_width))         _x = 440-_width; if (_y < 0)         _y = 0; if (_y > (400-_height))         _y = 400-_height; 

Here are the most important lines in this sectionthe friction code. How does friction behave? It basically slows down motion in most cases. How did I achieve this in this demo? I went against my velocities until it reached 0check it out:

 if (vel_x > 0)         vel_x--; if (vel_x < 0)         vel_x++; 

The friction code tries to subtract 1 from the velocity in the x-axis until the aircraft comes to a complete haltthis is exactly what I do to the y-axis velocities:

 if (vel_y > 0)         vel_y--; if (vel_y < 0)         vel_y++; 

When the user presses the Left arrow key, the aircraft accelerates in a west direction. The acceleration is capped at -16 pixels per frame. If the user were to just release the key, you'd see friction take over.

 if (Key.isDown(Key.LEFT)) {         vel_x -= acel_x;         if (acel_x < -16)     acel_x = -16; } 

I did something similar to the right motion but this time I add the acceleration and capped it at 16 ppf (pixels per frame):

 if (Key.isDown(Key.RIGHT)) {         vel_x += acel_x;         if (acel_x > 16)                 acel_x = 16; } 

The Up and Down arrow key responses and code are very similar so I'll be brief in my explanation:

 if (Key.isDown(Key.UP)) {         vel_y -= acel_y;         if (acel_y < -16)                  acel_y = -16; } if (Key.isDown(Key.DOWN)) {         vel_y += acel_y;         if (acel_y > 16)                 acel_y = 16; } 

When the Up key is pressed, the aircraft is moved up and is capped at 16 ppf. When the Down key is pressed, the airplane is moved down and it's capped at 16 ppf.

In order to trigger the conditional structures that fire the projectile on the main Timeline, we must flag them that the user wants to fire (the spacebar is pressed).

 if (Key.isDown(Key.SPACE)) {         _root.beem.status = "fired!"; } 

As the last thing in this handler, I wrote up this line to update the display:

 _parent.scoreDisplay = "SCORE: "+score; 

That concludes the friction code.

The following two functions allow the user to drag and drop the aircraft:

 onClipEvent(mouseDown) {         if (this.hitTest(_root._xmouse, _root._ymouse)) {                 this.startDrag();                 Mouse.hide();         } } 

The mouseDown function checks to see if the mouse is being pressedif it is, it starts to drag while hiding the mouse.

 onClipEvent(mouseUp) {         this.stopDrag();         Mouse.show(); } 

The mouseUp handler detects to see when the user stops dragging the aircraft, thus stopping the drag and showing the cursor.

All it required to create a semi-realistic game engine was a little physics!

[ LiB ]


Game Development with ActionScript
Game Development with ActionScript
ISBN: 1592001106
EAN: 2147483647
Year: 2004
Pages: 162
Authors: Lewis Moronta

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net