📄 547-561.html
字号:
<HTML>
<HEAD>
<META name=vsisbn content="1571690433"><META name=vstitle content="Black Art of Java Game Programming"><META name=vsauthor content="Joel Fan"><META name=vsimprint content="Sams"><META name=vspublisher content="Macmillan Computer Publishing"><META name=vspubdate content="11/01/96"><META name=vscategory content="Web and Software Development: Programming, Scripting, and Markup Languages: Java"><TITLE>Black Art of Java Game Programming:Building the JAVAroids Game</TITLE>
<!-- HEADER --><STYLE type="text/css"> <!-- A:hover { color : Red; } --></STYLE><META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW"><script><!--function displayWindow(url, width, height) { var Win = window.open(url,"displayWindow",'width=' + width +',height=' + height + ',resizable=1,scrollbars=yes'); if (Win) { Win.focus(); }}//--></script><SCRIPT><!--function popUp(url) { var Win = window.open(url,"displayWindow",'width=400,height=300,resizable=1,scrollbars=yes'); if (Win) { Win.focus(); }}//--></SCRIPT><script language="JavaScript1.2"><!--function checkForQuery(fm) { /* get the query value */ var i = escape(fm.query.value); if (i == "") { alert('Please enter a search word or phrase'); return false; } /* query is blank, dont run the .jsp file */ else return true; /* execute the .jsp file */}//--></script></HEAD><BODY>
<TABLE border=0 cellspacing=0 cellpadding=0>
<tr>
<td width=75 valign=top>
<img src="../1571690433.gif" width=60 height=73 alt="Black Art of Java Game Programming" border="1">
</td>
<td align="left">
<font face="arial, helvetica" size="-1" color="#336633"><b>Black Art of Java Game Programming</b></font>
<br>
<font face="arial, helvetica" size="-1"><i>by Joel Fan</i>
<br>
Sams, Macmillan Computer Publishing
<br>
<b>ISBN:</b> 1571690433<b> Pub Date:</b> 11/01/96</font>
</td>
</tr>
</table>
<P>
<!--ISBN=1571690433//-->
<!--TITLE=Black Art of Java Game Programming//-->
<!--AUTHOR=Joel Fan//-->
<!--AUTHOR=Eric Ries//-->
<!--AUTHOR=Calin Tenitchi//-->
<!--PUBLISHER=Macmillan Computer Publishing//-->
<!--IMPRINT=Sams//-->
<!--CHAPTER=13//-->
<!--PAGES=547-561//-->
<!--UNASSIGNED1//-->
<!--UNASSIGNED2//-->
<CENTER>
<TABLE BORDER>
<TR>
<TD><A HREF="543-547.html">Previous</A></TD>
<TD><A HREF="../ewtoc.html">Table of Contents</A></TD>
<TD><A HREF="561-570.html">Next</A></TD>
</TR>
</TABLE>
</CENTER>
<P><BR></P>
<H3><A NAME="Heading22"></A><FONT COLOR="#000077">Defining the Managers</FONT></H3>
<P>There are five manager classes in JAVAroids:
</P>
<DL>
<DD><B>•</B> AstManager
<DD><B>•</B> ShipManager
<DD><B>•</B> EnemyManager
<DD><B>•</B> EffManager
<DD><B>•</B> GameManager
</DL>
<P>Each manager class will have two methods: update(), which updates the individual sprites and handles collisions between them, and paint(), which draws the sprites. Before defining the managers, let’s see how they’ll work with each other. Figure 13-17 diagrams the interaction of the managers during the main loop of the game.
</P>
<P><A NAME="Fig17"></A><A HREF="javascript:displayWindow('images/13-17.jpg',600,747 )"><IMG SRC="images/13-17t.jpg"></A>
<BR><A HREF="javascript:displayWindow('images/13-17.jpg',600,747)"><FONT COLOR="#000077"><B>Figure 13-17</B></FONT></A> Interaction of Managers during Main Loop</P>
<P>As Figure 13-17 shows, the game manager class acts as a master clock that synchronizes the update() and paint() operations of the other four managers. Each manager in turn instructs the sprites it controls to update() and paint(). The main functionality of the game is implemented in the update() methods of the managers. For example, the asteroid manager’s update() moves the asteroids, checks for collisions with other game objects, and divides the asteroids when necessary. Another example is the update() method of the ship manager, which instructs the Ship sprite how to move, based on the keys that the player is holding down.
</P>
<P>Now let’s define the manager classes. By the time this is done, you’ll have the full game!</P>
<H4 ALIGN="LEFT"><A NAME="Heading23"></A><FONT COLOR="#000077">The Asteroid Manager</FONT></H4>
<P>The first thing the AstManager class does is create the individual asteroids used in the game. Instantiating an object is a complex and relatively slow operation, so it makes sense to allocate all the asteroids needed in the constructor. Afterward, you can control the visibility of the asteroid by suspending or restoring it.
</P>
<P>The asteroids are stored in an array <I>a[].</I> There are three sizes of asteroids: large, medium, and small. Large asteroids divide into two medium ones, and a medium asteroid splits into two small ones. As a result, we’ll use the indexing scheme shown in Figure 13-18 to implement asteroid division.</P>
<P><A NAME="Fig18"></A><A HREF="javascript:displayWindow('images/13-18.jpg',600,225 )"><IMG SRC="images/13-18t.jpg"></A>
<BR><A HREF="javascript:displayWindow('images/13-18.jpg',600,225)"><FONT COLOR="#000077"><B>Figure 13-18</B></FONT></A> Asteroid array indexing</P>
<P>More precisely, if a large asteroid <I>a[i]</I> is hit, you’ll suspend the <I>a[i]</I> sprite, and restore the two medium asteroid sprites at <I>a[2*i + NUM_LARGE]</I> and <I>a[2*i + 1 + NUM_LARGE], where NUM_LARGE is the maximum number of large asteroids.</I></P>
<P>How do we obtain the shapes for these asteroids? One way is to hardcode the polygonal coordinates. In the current implementation, asteroid shapes are created dynamically in the method MakeVectors(), by randomly perturbing the points about a polygonal template, as shown in Figure 13-19.</P>
<P><A NAME="Fig19"></A><A HREF="javascript:displayWindow('images/13-19.jpg',600,507 )"><IMG SRC="images/13-19t.jpg"></A>
<BR><A HREF="javascript:displayWindow('images/13-19.jpg',600,507)"><FONT COLOR="#000077"><B>Figure 13-19</B></FONT></A> Creating a new asteroid shape</P>
<P>Once the asteroids are constructed, the AstManager controls their interactions in its update(). Let’s take a closer look at this method.
</P>
<P>update() iterates through all sprites in the asteroid array <I>a[].</I> If no sprites are active, update() calls newBoard() to start a new rack of asteroids. If an asteroid sprite is active, it goes through a series of intersection checks. For example, here’s the code that handles a collision between an asteroid and the enemy ship objects:</P>
<!-- CODE //-->
<PRE>
///////////////////////////////////
// CHECK FOR ENEMY INTERSECTION
//
for (int j=0; j<enemy.length; j++) {
if (a[i].intersect(enemy[j])) {
Divide(i);
em.destroyEnemy(j);
}
}
</PRE>
<!-- END CODE //-->
<P>The Divide() method creates the effect of splitting asteroids by suspending the larger one, and activating the two smaller sprites using the indexing scheme we’ve described.
</P>
<P>The remainder of the update() method handles the other types of collisions similarly. A collision between the ship and a “powerup” asteroid increases the shield power of the ship.</P>
<P>Finally, the AstManager paint() method is really simple: it iterates through the array of asteroid sprites, telling each Asteroid to paint itself.</P>
<P>The source to the AstManager class is shown in Listing 13-14. The long series of constants at the beginning of the class definition is for constructing random asteroid shapes, so you can skip over it and look at the methods.</P>
<P><B>Listing 13-14</B> AstManager class</P>
<!-- CODE //-->
<PRE>
/////////////////////////////////////////////////////////////////
//
// the Asteroid Manager class -- handles all things relating
// to asteroids, as well as
// collisions with other
// game objects
//
/////////////////////////////////////////////////////////////////
public class AstManager extends Object {
/////////////////////////////////////////////////////////////////
// constants -- these control the size, basic shape, and speed
// of the asteroids
/////////////////////////////////////////////////////////////////
// max speed
static final int MAX_VX = 4;
static final int MAX_VY = 4;
// max size
static final int MAX_RADIUS = 30;
// size ratio between large:medium, and medium:small asteroids
static final int SIZE_RATIO = 2;
// constants that refer to asteroid size
static final int SMALL = 2;
static final int MEDIUM = 1;
static final int LARGE = 0;
// how much each asteroid's worth
static final int VAL_SMALL = 90;
static final int VAL_MEDIUM = 60;
static final int VAL_LARGE = 30;
// large:small asteroid size ratio
static final int SRAT = SMALL*SIZE_RATIO;
// large:medium asteroid size ratio
static final int MRAT = MEDIUM*SIZE_RATIO;
/////////////////////////////////////////////////////////////////
// templates for the asteroids
/////////////////////////////////////////////////////////////////
static final int PX0 =
(int)(Math.cos(0.0*GameMath.DEG_TO_RAD)*MAX_RADIUS);
static final int PX1 =
(int)(Math.cos(72.0*GameMath.DEG_TO_RAD)*MAX_RADIUS);
static final int PX2 =
(int)(Math.cos(144.0*GameMath.DEG_TO_RAD)*MAX_RADIUS);
static final int PX3 =
(int)(Math.cos(216.0*GameMath.DEG_TO_RAD)*MAX_RADIUS);
static final int PX4 =
(int)(Math.cos(288.0*GameMath.DEG_TO_RAD)*MAX_RADIUS);
static final int PY0 =
(int)(Math.sin(0.0*GameMath.DEG_TO_RAD)*MAX_RADIUS);
static final int PY1 =
(int)(Math.sin(72.0*GameMath.DEG_TO_RAD)*MAX_RADIUS);
static final int PY2 =
(int)(Math.sin(144.0*GameMath.DEG_TO_RAD)*MAX_RADIUS);
static final int PY3 =
(int)(Math.sin(216.0*GameMath.DEG_TO_RAD)*MAX_RADIUS);
static final int PY4 =
(int)(Math.sin(288.0*GameMath.DEG_TO_RAD)*MAX_RADIUS);
// the x-coordinates of large, medium, and small template
static final int px[][] = {
{0,MAX_RADIUS/2,MAX_RADIUS,MAX_RADIUS/2,0,-MAX_RADIUS/2,
-MAX_RADIUS,-MAX_RADIUS/2,0},
{PX0/MRAT,PX1/MRAT,PX2/MRAT,PX3/MRAT,PX4/MRAT},
{PX0/SRAT,PX1/SRAT,PX2/SRAT,PX3/SRAT,PX4/SRAT}
};
// the y-coordinates of large, medium, and small template
static final int py[][] = {
{MAX_RADIUS,MAX_RADIUS/2,0,-MAX_RADIUS/2,-MAX_RADIUS,
-MAX_RADIUS/2,0,MAX_RADIUS/2,MAX_RADIUS},
{PY0/MRAT,PY1/MRAT,PY2/MRAT,PY3/MRAT,PY4/MRAT},
{PY0/SRAT,PY1/SRAT,PY2/SRAT,PY3/SRAT,PY4/SRAT}
} ;
/////////////////////////////////////////////////////////////////
// coordinates of the powerup
/////////////////////////////////////////////////////////////////
static final int powerx[] = {
10,2,0,-2,-10,-2,0,2,10
};
static final int powery[] = {
0,2,10,2,0,-2,-10,-2,0
};
// variance in asteroid shape
static final double AVAR = 1.7;
// used for intersection calcs
static final int MAX_RAD_LARGE =
MAX_RADIUS+(int)(MAX_RADIUS/AVAR);
static final int MAX_RAD_MEDIUM =
MAX_RADIUS/MRAT+(int)(MAX_RADIUS/AVAR/MRAT);
static final int MAX_RAD_SMALL =
MAX_RADIUS/SRAT+(int)(MAX_RADIUS/AVAR/SRAT);
// num of large asteroids
static final int NUM_LARGE = 6;
// num of medium asteroids
static final int NUM_MEDIUM = 2*NUM_LARGE;
// num of small asteroids
static final int NUM_SMALL = 2*NUM_MEDIUM;
// total number of asteroids
static final int NUM_ASTS = NUM_LARGE+NUM_MEDIUM+NUM_SMALL;
// color of asteroids
static final Color LARGE_COLOR = new Color(150,150,233);
static final Color MEDIUM_COLOR = Color.cyan;
static final Color SMALL_COLOR = Color.magenta;
/////////////////////////////////////////////////////////////////
// variables
/////////////////////////////////////////////////////////////////
// level of play
static int level;
// array of asteroids
private Asteroid a[] = new Asteroid[NUM_ASTS];
// the powerup
private Asteroid powerup;
// screen bounds
static int width,height;
// references to other game objects
// the ship
ShipManager sm;
Ship ship;
Fire[] fire;
// the enemies
EnemyManager em;
Enemy[] enemy;
Fire[] enemyfire;
// the effect manager
EffManager efm;
// game manager
GameManager game;
/////////////////////////////////////////////////////////////////
// AstManager constructor:
// create all Asteroids used in game. This is done
// at beginning to improve performance
/////////////////////////////////////////////////////////////////
public AstManager(int w, int h,
ShipManager sm,EnemyManager em,
EffManager efm, GameManager g) {
ship = sm.getShip(); // get ship-- needed for
// collision detection
fire = sm.getFire(); // -- same
this.sm = sm;
enemy = em.getEnemy(); // get enemies-- needed for
// collision detection
enemyfire = em.getFire(); // -- same
this.em = em;
this.efm = efm;
game = g;
width = w;
height = h;
// create storage for actual asteroids:
// storage for large ast
int tx0[] = new int[px[LARGE].length];
int ty0[] = new int[px[LARGE].length];
// storage for medium ast
int tx1[] = new int[px[MEDIUM].length];
int ty1[] = new int[px[MEDIUM].length];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -