Integrating Artwork with Programming


Sometimes it's quicker to copy your code onto new artwork, and sometimes it's quicker to import symbols and change the symbol instances to point to the new symbols.

In this case, the relative positioning of so many movie clips was difficult to preserve, so it was quicker to copy the code into the artist's movie. It quickly became obvious that the relative positioning of the artist's symbols, especially the trees, would make this very time-consuming . I copied the code into the artist's movie and then labeled the layers and symbol instances.

The Turret

I hadn't realized that the tank turret and body would need to rotate independently in time to tell the artist, so I had to embed these layers as separate symbols within both of the tank symbols and give them instance names of turret and body. Another result of the tank turret and body rotating independently is that I had to remove the turret part of the tank blast skin, which is an overlay that makes the tank appear to have exploded. Because the actual turret could be pointing in any direction or angle, it had to be omitted from the blast skin symbol.

The Bomb's Scale

I also hadn't realized that to control the scale of the bomb animation programmatically, each of the frames would have to display the bomb at the same scale. (See Figure 25.9.) I had to standardize the size of all the frames in the animation.

Figure 25.9. Each frame of the bomb, shown with onion skinning turned on, shows the bomb at the same scale because its scale is controlled programmatically rather than with a shape tween.

graphics/25fig09.gif

To move the playhead in the bomb movie clip to the right frame based on the upward or downward speed, I added the following code on the bomb movie clip, inside the if (z>=0) statement at the end:

 if (zSpeed>15) {     gotoAndStop(2);  } else if (zSpeed > 5) {     gotoAndStop(3);  } else if (zSpeed > 2) {     gotoAndStop(4);  } else if (zSpeed > -5) {     gotoAndStop(5);  } else if (zSpeed > -10) {     gotoAndStop(6);  } else if (zSpeed > -20) {     gotoAndStop(7);  } 

If the bomb is shot mostly horizontally, the first and last frames of the animation will never get played because the speed is never high enough as it goes up and then back down.

Making the Controls Draggable

We decided to allow players to set the controls by dragging the end of the indicator rather than by pressing arrow keys. To do this, I placed an extra-large invisible button over the handle at the end of the indicator line in the indicator-long and indicator-short movie clips. (See Figure 25.10.)

Figure 25.10. The light-gray area is the invisible button that activates the dragging.

graphics/25fig10.gif

Then I placed the following code on the invisible button in both movie clips:

 on (press) {     _parent.dragging = true;      }  }  on (release, releaseOutside) {     _parent.dragging = false;  } 

When the invisible button was pressed, it set a variable on the control called dragging to true. Then I added the following at the end of the code inside the onClipEvent (enterFrame) on the player1tank symbol to make the angle control's indicator draggable:

 // When angle control is modified, calculate change  else if (_root.player1controls.angle.dragging) {     // Calculate distance between mouse and indicator nexus      deltaX=_root.player1controls.angle._xmouse;      deltaY=_root.player1controls.angle._ymouse;      // Calculate the control setting      radians = Math.atan2(deltaY, deltaX);      degrees = _root.fixAngle(Math.round(((180*radians)/Math.PI))+90);      // Keep the angle control within bounds      if (degrees > 80 && degrees < 270) {         degrees=80;      } else if (degrees > 270) {         degrees=0;      }      // Update the angle control      _root.player1controls.angle.indicator._rotation=degrees;  } 

When the dragging variable for the angle control became true, the deltaX and deltaY variables are set to the _xmouse and _ymouse properties of the angle indicator. Because the center point of the indicator (the end of the line) is also the center point of the angle control, the _xmouse and _ymouse properties of the angle symbol are always equal to the distances between the mouse pointer and the beginning of the indicator. The built-in arctangent function, Math.atan2(), calculates the angle in radians between the two points based on the X and Y distances. This number is converted to degrees, rounded to the nearest integer, and 90 is added because the indicator's _rotation property equals 0 when the indicator is pointing straight up.

Finally, the angle is shifted to the 0 “360 range. The degrees variable is evaluated several times to keep the indicator within the range of 0 “80 degrees. When the indicator's _rotation property equals 0 °, it is pointing vertically; when it is 80 °, it is pointing near horizontal. I didn't want it to be any closer to horizontal because the bomb would never gain any height and would explode immediately. If degrees is between 80 ° and 270 °, it is snapped to 80. If it is between 270 and 360 it is snapped to zero. The _rotation property of the indicator is updated based on the final value of the degrees variable. All this happened continuously until the player stopped pressing the invisible button over the indicator and dragging became false.

Then I added the following at the end of the code inside the onClipEvent(enterFrame) on the player1tank symbol to make the direction control's indicator draggable:

 // When direction control is modified, calculate change  else if (_root.player1controls.direction.dragging) {     // Calculate distance between mouse and indicator nexus      deltaX=_root.player1controls.direction._xmouse;      deltaY=_root.player1controls.direction._ymouse;      // Calculate the control setting      radians = Math.atan2(deltaY, deltaX);      degrees = _root.fixAngle(Math.round(((180*radians)/Math.PI))+90);      // Keep the direction control within bounds      if ((degrees > 270) && (degrees < 360)) {         degrees=360;      } else if ((degrees > 180) && (degrees <= 270)){         degrees=180;      }      // Update the direction control      _root.player1controls.direction.indicator._rotation=degrees;  } 

The direction control operates the same as the angle control, described previously, except that the indicator's range is 0 “180 ° rather than 0 “90 °. When the indicator's _rotation property equals 0 °, it is pointing straight up; when it is 180 °, it is pointing straight down. If degrees is between 270 and 360, it is snapped to 360. If it is between 180 and 270, it is snapped to 270. Finally, the _rotation property of the indicator is updated based on the final value of the degrees variable. All this happened continuously until the player stopped pressing the invisible button over the indicator and dragging became false.

Then I added the following at the end of the code inside the onClipEvent(enterFrame) on the player1tank symbol to make the power control's indicator draggable:

 // When power control is modified, calculate change  } else if (_root.player1controls.power.dragging) {     // Calculate distance between mouse and indicator nexus      deltaX=_root.player1controls.power._xmouse;      deltaY=_root.player1controls.power._ymouse;      // Calculate the control setting      radians = Math.atan2(deltaY, deltaX);      degrees = Math.round(((180*radians)/Math.PI))+90;      degrees = _root.fixAngle(degrees);      // Keep the power control within bounds      if ((degrees > 270) && (degrees < 360)) {         degrees=360;      } else if ((degrees > 180) && (degrees <= 270)){         degrees=180;      }      // Update the power control      _root.player1controls.power.indicator._rotation = degrees;  } 

The power control operates the same as the direction control. The _rotation property of the indicator is updated based on the final value of the degrees variable. All this happened continuously until the player stopped pressing the invisible button over the indicator and dragging became false.

Updating the Turret Based on Controls

To make the turret appear to angle upward when the angle control is set, I used the gotoAndStop() function to position the playhead in the turret movie clip appropriately. I added the following code on the player1tank movie clip inside the if statement that checks to see whether the _root.controls.angle.dragging variable is true:

 // Angle the turret upwards  this.turret.gotoAndStop(Math.abs(Math.round((90-degrees)/15))); 

First the degrees variable is subtracted from 90 because the indicator's value goes up when the _rotation property of the indicator decreases. This number is divided by 15 because there are six frames to display the 90 ° range. This number is rounded and the absolute value determines to what frame of the turret animation the playhead should move.

To make the turret rotate when the direction control is set, I set the _rotation property of the turret movie clip. To do so, I added the following code on the player1tank movie clip inside the if statement that checks to see whether the _root.controls.direction. dragging variable is true:

 // Rotate the turret  this.turret._rotation = degrees-90; 

The _rotation property of any movie clip equals 0 when the movie starts. If the number is increased, it rotates to the left. If it is decreased, it rotates to the right.

Bomb Controller

At first I attached the artist's shell blast, sand blast, or water splash movie clip with attachMovieClip(), depending where the bomb landed. But I eliminated the need to position those movie clips by placing all of them on separate frames in a new bombcontroller movie clip. (See Figure 25.11.)

Figure 25.11. Nothing is in the first frame of the bomb animation because the playhead is moved inside the bomb movie clip programmatically.

graphics/25fig11.gif

The code on the bomb movie clip in frame 1 would determine to which frame to move the playhead, so I put a stop() action in frame 1. I first put each one at the center point on a separate frame. The bomb, now on frame 1 of the bombcontroller movie clip, already had an onClipEvent(enterFrame) event on it to update the location and scale of the bomb. So, I decided to also use it to then move the playhead to the frames that contain the shell blast, sand blast, or water splash movie clips, depending on the bomb's location when it reaches the ground again. I labeled frames 2 “4 as shellblast, sandblast, and watersplash so that code on the bomb movie clip could move the playhead to the appropriate frame based on the bomb movie clip's location when it reaches the ground. On the bomb movie clip (in frame 1), I changed the first two lines, which set the bomb movie clip's X and Y coordinates so that it moved the entire bombcontroller movie clip instead of just the bomb movie clip by changing this to _parent:

 _parent._x=x;  _parent._y=y; 

The code inside the else statement is executed when the z variable is less than 0, indicating that the bomb is below the ground. To first evaluate whether the bomb has hit the player1tank movie clip, I added the following code inside the else statement on the bomb:

 // Detect what was hit  if (_root.player1tank.hitTest(_root._x, _root._y, true)) {     // Rotate blast skin to match body and make it visible      _root.player1tank.blast._rotation=_root.player1tank.body._rotation;      _root.player1tank.blast._visible=true;      _parent.gotoAndStop("shellblast");  } 

The hitTest() function in the if statement evaluates whether the mouse's X and Y positions intersect with the player1tank movie clip. If they do, the blast skin is rotated to match the tank body, it is made visible, and the playhead is moved to the frame within the bombcontroller movie clip that contains the shell blast movie clip.

To then evaluate whether the bomb has hit the player2tank movie clip, I added the following code inside the else statement on the bomb:

 else if (_root.player2tank.hitTest(_root._x, _root._y, true)) {     // Rotate blast skin to match body and make it visible      _root.player2tank.blast._rotation=_root.player2tank.body._rotation;      _root.player2tank.blast._visible=true;      _parent.gotoAndStop("shellblast");  } 

The hitTest() function in the first if statement evaluates whether the mouse's X and Y positions intersect with the player2tank movie clip.

If the bomb didn't hit one of the tanks or islands, it must have landed in the water. So, I added the following else statement inside the existing else statement on the bomb:

 else {     // Otherwise, the water was hit, display water splash      _parent.gotoAndStop("watersplash");  } 

If none of the previous if statements evaluates as true, inside the else statement, the gotoAndStop() function advances the playhead to the frame that contains the water splash movie clip.

Because the bomb movie clip was now inside the bombcontroller movie clip, I had to update code on the fire button. In the Library, I removed the bomb movie clip's bomb linkage and created a new linkage for the new bombcontroller movie clip called bombcontroller. On the fire button, I replaced all instances of bomb with bombcontroller:

 _root.attachMovie("bombcontroller", "thebombcontroller", 10);  // Rotate the bomb to match the turret direction  _root.thebombcontroller._rotation=_root.player1controls.direction.  indicator._rotation-90;  // Send variables to the bomb controller  _root.thebombcontroller.bombclip.x = point.x;  _root.thebombcontroller.bombclip.y = point.y;  _root.thebombcontroller.bombclip.xSpeed = xSpeed;  _root.thebombcontroller.bombclip.ySpeed = ySpeed;  _root.thebombcontroller.bombclip.zSpeed = zSpeed;  _root.thebombcontroller.bombclip.xWind = xWind;  _root.thebombcontroller.bombclip.yWind = yWind; 

Until now, the bomb was attached at the center point of the turret. To attach the bomb to the end of the turret, regardless of the turret's angle or direction, I placed an instance of an invisible button on each frame in the turret animation, giving all of them the same instance name of end. Because the _x and _y properties of the end instances would return values relative to the center point of the turret, I had to create a function to convert local coordinates to global coordinates. To call this function, I placed the following code on Player 1's fire button, just before the variables are sent to the bombcontroller:

 // Locate the end of the turret in global coordinates  point = new object();  _root.player1tank.turret.locate(point); 

Then I placed the following code on frame 1 of player1tank's turret movie clip:

 function locate(point) {     point.x = end._x;      point.y = end._y;      localToGlobal(point);      return point;  } 

First I assigned the _x and _y properties of the end movie clip instance to the X and Y variables within the point object. Then I used the built-in localToGlobal() function to convert the location of the end of the turret from coordinates that are relative to the turret movie clip to global coordinates.

To remove the bombcontroller, I placed the following in the last frame of the sand blast, water splash, and shell blast movie clips:

 // Remove the bomb controller, which removes this MC as well  removeMovieClip("_root.thebombcontroller"); 


Inside Flash
Inside Flash MX (2nd Edition) (Inside (New Riders))
ISBN: 0735712549
EAN: 2147483647
Year: 2005
Pages: 257
Authors: Jody Keating

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