⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch13.htm

📁 Java游戏开发
💻 HTM
📖 第 1 页 / 共 3 页
字号:
+ i + j + &quot;.gif&quot;);<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tracker.addImage(image[i][j],
id);<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>
&nbsp;&nbsp;}<BR>
<BR>
&nbsp;&nbsp;protected void setCollision() {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;collision = new Rectangle(position.x +
3, position.y + 3,<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;position.width - 6, position.height
- 6);<BR>
&nbsp;&nbsp;}<BR>
<BR>
&nbsp;&nbsp;public BitSet update() {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;// See if the scorpion escaped<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BitSet action = super.update();<BR>
&nbsp;&nbsp;&nbsp;&nbsp;if (action.get(Sprite.SA_KILL))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ScorpionRoundup.lost++;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;return action;<BR>
&nbsp;&nbsp;}<BR>
}</TT>
</BLOCKQUOTE>
<HR>
<P>
The <TT>Scorpion</TT> class uses a
two-dimensional array of images to show the animations of the
scorpion kicking its legs and wagging its tail in each direction.
Figure 13.3 shows the images used by the <TT>Scorpion</TT>
class.
<P>
<A HREF="f13-3.gif" ><B>Figure 13.3 : </B><I>The images used by the Scorpion class.</I></A>
<P>
The constructor for <TT>Scorpion</TT>
takes parameters specifying the direction and speed increment
for the scorpion, <TT>dir</TT> and
<TT>speedInc</TT>. The <TT>dir</TT>
parameter determines in which direction the scorpion travels,
as well as which side of the screen it starts from, and the parameter
can be set to either <TT>0</TT> (left)
or <TT>1</TT> (right). The <TT>speedInc</TT>
parameter specifies how much to increase the scorpion's speed
beyond its default speed. This parameter is how new scorpions
become faster as the difficulty level of the game increases.
<P>
The <TT>update</TT> method in <TT>Scorpion</TT>
is overridden to track when the scorpion makes it across the screen.
This works rather indirectly, so bear with me. Notice in the constructor
for <TT>Scorpion</TT> that the bounds
action is set to <TT>BA_DIE</TT>.
If you recall, the bounds actions determine what a sprite does
when it reaches a boundary (the other side of the applet window,
in this case). The <TT>BA_DIE</TT>
bounds action causes the <TT>SA_KILL</TT>
flag to be returned by the default sprite <TT>update</TT>
method, eventually resulting in the sprite being removed from
the sprite list. By looking for this flag in <TT>Scorpion</TT>'s
overridden <TT>update</TT> method,
you can tell when the scorpion makes it across the screen unscathed.
Pretty tricky, huh?
<P>
If the scorpion has made it across safely, the <TT>ScorpionRoundup.lost</TT>
variable is incremented. This variable is a public static member
of the <TT>ScorpionRoundup</TT> applet
class that can be accessed by other classes, such as <TT>Scorpion</TT>.
You'll learn more about it later in this lesson when you get into
the <TT>ScorpionRoundup</TT> class.
<P>
Scorpion Roundup uses a derived version of the <TT>SpriteVector</TT>
class called <TT>SRVector</TT>. Listing
13.2 contains the source code for the <TT>SRVector</TT>
class.
<HR>
<BLOCKQUOTE>
<B>Listing 13.2. The </B><TT><B><FONT FACE="Courier">SRVector</FONT></B></TT><B>
class.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT>public class SRVector extends SpriteVector
{<BR>
&nbsp;&nbsp;public SRVector(Background back) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;super(back);<BR>
&nbsp;&nbsp;}<BR>
<BR>
&nbsp;&nbsp;Sprite isPointInside(Point pt) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;// Iterate backward through the sprites,
testing each<BR>
&nbsp;&nbsp;&nbsp;&nbsp;for (int i = (size() - 1); i &gt;= 0;
i--) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sprite s = (Sprite)elementAt(i);
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ((s.getClass().getName().equals(&quot;Scorpion&quot;))
&amp;&amp;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.isPointInside(pt))
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return s;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;}<BR>
&nbsp;&nbsp;&nbsp;&nbsp;return null;<BR>
&nbsp;&nbsp;}<BR>
<BR>
&nbsp;&nbsp;protected boolean collision(int i, int iHit) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;// Do nothing!<BR>
&nbsp;&nbsp;&nbsp;&nbsp;return false;<BR>
&nbsp;&nbsp;}<BR>
}</TT>
</BLOCKQUOTE>
<HR>
<P>
The <TT>SRVector</TT> class overrides
two methods in <TT>SpriteVector</TT>:
<TT>isPointInside</TT> and <TT>collision</TT>.
The overridden <TT>isPointInside</TT>
method is necessary to distinguish between the user clicking a
scorpion sprite and clicking the net sprite. Without overriding
this method, you would never be able to detect when a scorpion
is clicked, because the net sprite would always be in the way.
This is a result of the fact that the net sprite follows the mouse
around and has a higher Z-order than the scorpions (so it can
always be seen). The simple solution is to look only for sprites
of type <TT>Scorpion</TT> in the <TT>isPointInside</TT>
method.
<P>
Because the scorpions don't need to be able to collide with each
other or the net sprite, it makes sense to do nothing when a collision
occurs. This is carried out by simply returning <TT>false</TT>
from the <TT>collision</TT> method.
<P>
You've now seen the sprite classes used by <TT>ScorpionRoundup</TT>.
It's time to check out the applet class.
<H3><A NAME="TheScorpionRoundupClass"><B>The </B><TT><B><FONT SIZE=4 FACE="Courier">ScorpionRoundup</FONT></B></TT><B><FONT SIZE=4>
Class</FONT></B></A></H3>
<P>
The <TT>ScorpionRoundup</TT> class
takes care of all the high-level animation and sound issues, as
well as handling user input. First take a look at the member variables
defined in the <TT>ScorpionRoundup</TT>
class:
<BLOCKQUOTE>
<TT>private Image&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offImage,
back, netImage;<BR>
private AudioClip&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;music, netHit,
netMiss, applause;<BR>
private Graphics&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offGrfx;<BR>
private Thread&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;animate;
<BR>
private MediaTracker&nbsp;&nbsp;tracker;<BR>
private SRVector&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;srv;<BR>
private Sprite&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net;
<BR>
private int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delay
= 83; // 12 fps<BR>
private Font&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;infoFont
= new Font(&quot;Helvetica&quot;,<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Font.PLAIN,
14);<BR>
private FontMetrics&nbsp;&nbsp;&nbsp;infoMetrics;<BR>
private Random&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rand
= new<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Random(System.currentTimeMillis());
<BR>
private boolean&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;musicOn
= true;<BR>
private static int&nbsp;&nbsp;&nbsp;&nbsp;level, caught;<BR>
public static int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lost;</TT>
</BLOCKQUOTE>
<P>
You might be curious about a few of these member variables. The
four <TT>AudioClip</TT> member variables
hold audio clips for the music and sound effects used in the game.
The <TT>musicOn</TT> member variable
is a boolean variable that determines whether the music is on
or off. The <TT>level</TT>, <TT>caught</TT>,
and <TT>lost</TT> member variables
are used to store the state of the game: <TT>level</TT>
is the current difficulty level, <TT>caught</TT>
is how many scorpions have been caught, and <TT>lost</TT>
is how many scorpions have escaped.
<P>
The <TT>init</TT> method in <TT>ScorpionRoundup</TT>
is pretty straightforward-it loads and initializes all the images
and sounds used by the game:
<BLOCKQUOTE>
<TT>public void init() {<BR>
&nbsp;&nbsp;// Load and track the images<BR>
&nbsp;&nbsp;tracker = new MediaTracker(this);<BR>
&nbsp;&nbsp;back = getImage(getCodeBase(), &quot;Res/Back.gif&quot;);
<BR>
&nbsp;&nbsp;tracker.addImage(back, 0);<BR>
&nbsp;&nbsp;netImage = getImage(getCodeBase(), &quot;Res/Net.gif&quot;);
<BR>
&nbsp;&nbsp;tracker.addImage(netImage, 0);<BR>
&nbsp;&nbsp;Scorpion.initResources(this, tracker, 0);<BR>
<BR>
&nbsp;&nbsp;// Load the audio clips<BR>
&nbsp;&nbsp;music = getAudioClip(getCodeBase(), &quot;Res/Music.au&quot;);
<BR>
&nbsp;&nbsp;netHit = getAudioClip(getCodeBase(), &quot;Res/NetHit.au&quot;);
<BR>
&nbsp;&nbsp;netMiss = getAudioClip(getCodeBase(), &quot;Res/NetMiss.au&quot;);
<BR>
&nbsp;&nbsp;applause = getAudioClip(getCodeBase(), &quot;Res/Applause.au&quot;);
<BR>
}</TT>
</BLOCKQUOTE>
<P>
The <TT>stop</TT> method has been
pretty standard in all the applets you've seen thus far. However,
in <TT>ScorpionRoundup</TT> it has
an extra line of code that stops looping the music audio clip:
<BLOCKQUOTE>
<TT>public void stop() {<BR>
&nbsp;&nbsp;if (animate != null) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;animate.stop();<BR>
&nbsp;&nbsp;&nbsp;&nbsp;animate = null;<BR>
&nbsp;&nbsp;}<BR>
&nbsp;&nbsp;music.stop();<BR>
}</TT>
</BLOCKQUOTE>
<P>
The extra line of code, <TT>music.stop()</TT>,
is important because it ensures that the music is stopped when
the thread is stopped. Without this simple method call, the music
would continue to play even after a user has left the Web page
containing the game.
<P>
<CENTER><TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><B>Warning</B></TD></TR>
<TR><TD>
<BLOCKQUOTE>
Be sure to always stop all looped sounds when the applet thread is stopped. You do this simply by calling the <TT>stop</TT> method on the <TT>AudioClip</TT> object from within the applet's <TT>stop</TT> method, as you just saw in <TT>ScorpionRoundup</TT>.
</BLOCKQUOTE>

</TD></TR>
</TABLE></CENTER>
<P>
<P>
The <TT>run</TT> method in <TT>ScorpionRoundup</TT>
calls the <TT>newGame</TT> method,
which you'll learn about in a moment. Listing 13.3 contains the
source code for the <TT>run</TT> method.
<HR>
<BLOCKQUOTE>
<B>Listing 13.3. The </B><TT><B><FONT FACE="Courier">ScorpionRoundup</FONT></B></TT><B>
class's </B><TT><B><FONT FACE="Courier">run</FONT></B></TT><B>
method.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT>public void run() {<BR>
&nbsp;&nbsp;try {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;tracker.waitForID(0);<BR>
&nbsp;&nbsp;}<BR>
&nbsp;&nbsp;catch (InterruptedException e) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;return;<BR>
&nbsp;&nbsp;}<BR>
<BR>
&nbsp;&nbsp;// Set up a new game<BR>
&nbsp;&nbsp;newGame();<BR>
<BR>
&nbsp;&nbsp;// Update everything<BR>
&nbsp;&nbsp;long t = System.currentTimeMillis();<BR>
&nbsp;&nbsp;while (Thread.currentThread() == animate) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;srv.update();<BR>
&nbsp;&nbsp;&nbsp;&nbsp;repaint();<BR>
&nbsp;&nbsp;&nbsp;&nbsp;try {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t += delay;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(Math.max(0, t
- System.currentTimeMillis()));<BR>
&nbsp;&nbsp;&nbsp;&nbsp;}<BR>
&nbsp;&nbsp;&nbsp;&nbsp;catch (InterruptedException e) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;}<BR>
&nbsp;&nbsp;}<BR>
}</TT>
</BLOCKQUOTE>
<HR>
<P>
After setting up a new game, the <TT>run</TT>
method enters the main update loop where it updates the sprite
list and forces a repaint. Speaking of updating, the <TT>update</TT>
method does a few new things in <TT>ScorpionRoundup</TT>;
check out Listing 13.4.
<HR>
<BLOCKQUOTE>
<B>Listing 13.4. The </B><TT><B><FONT FACE="Courier">ScorpionRoundup</FONT></B></TT><B>
class's </B><TT><B><FONT FACE="Courier">update</FONT></B></TT><B>
method.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT>public void update(Graphics g) {<BR>
&nbsp;&nbsp;// Create the offscreen graphics context<BR>
&nbsp;&nbsp;if (offGrfx == null) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;offImage = createImage(size().width, size().height);
<BR>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -