📄 ch10.htm
字号:
// Create the UI<BR>
if (ngButton == null) {<BR>
ngButton = new Button("New Game");
<BR>
add(ngButton);<BR>
}<BR>
<BR>
// Load and track the images<BR>
tracker = new MediaTracker(this);<BR>
back = getImage(getCodeBase(), "Res/Back.gif");
<BR>
tracker.addImage(back, 0);<BR>
smGecko = getImage(getCodeBase(), "Res/SmGecko.gif");
<BR>
tracker.addImage(smGecko, 0);<BR>
Gecko.initResources(this, tracker, 0);<BR>
Geckocide.initResources(this, tracker, 0);<BR>
Rock.initResources(this, tracker, 0);<BR>
GilaMonster.initResources(this, tracker, 0);<BR>
Scorpion.initResources(this, tracker, 0);<BR>
Rattler.initResources(this, tracker, 0);<BR>
Tarantula.initResources(this, tracker, 0);<BR>
}</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
The <TT><FONT FACE="Courier">update</FONT></TT> method is where
a lot of interesting things take place in <TT><FONT FACE="Courier">TravelingGecko</FONT></TT>.
Listing 10.7 shows the source code for the <TT><FONT FACE="Courier">update</FONT></TT>
method.
<HR>
<BLOCKQUOTE>
<B>Listing 10.7. The </B><TT><B><FONT FACE="Courier">TravelingGecko</FONT></B></TT><B>
class's </B><TT><B><FONT FACE="Courier">update</FONT></B></TT><B>
method.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier">public void update(Graphics g) {<BR>
// Create the offscreen graphics context<BR>
if (offGrfx == null) {<BR>
offImage = createImage(size().width, size().height);
<BR>
offGrfx = offImage.getGraphics();<BR>
scoreMetrics = offGrfx.getFontMetrics(scoreFont);
<BR>
}<BR>
<BR>
// Draw the sprites<BR>
tgv.draw(offGrfx);<BR>
<BR>
// Draw the score<BR>
offGrfx.setFont(scoreFont);<BR>
offGrfx.drawString(String.valueOf(score), 10, 5 +
<BR>
scoreMetrics.getAscent());<BR>
<BR>
// Draw the number of lives<BR>
for (int i = 0; i < (lives - 1); i++)<BR>
offGrfx.drawImage(smGecko, 65 + i *<BR>
(smGecko.getWidth(this) +
1), 10, this);<BR>
<BR>
// Draw the game over message<BR>
if (lives <= 0) {<BR>
Font f
= new Font("Helvetica", Font.BOLD, 36);<BR>
FontMetrics fm = offGrfx.getFontMetrics(f);
<BR>
String s
= new String("Game Over");<BR>
offGrfx.setFont(f);<BR>
offGrfx.drawString(s, (size().width -
fm.stringWidth(s)) / 2,<BR>
((size().height - fm.getHeight())
/ 2) + fm.getAscent());<BR>
}<BR>
<BR>
// Draw the image onto the screen<BR>
g.drawImage(offImage, 0, 0, null);<BR>
}</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
After drawing the sprites, the <TT><FONT FACE="Courier">update</FONT></TT>
method draws the score using the <TT><FONT FACE="Courier">drawString</FONT></TT>
method. The small gecko images are then drawn to represent the
number of remaining lives. If the number of lives is less than
or equal to zero, the <TT><FONT FACE="Courier">Game Over</FONT></TT>
message is drawn. Finally, the offscreen buffer image is drawn
to the screen.
<P>
Traveling Gecko only supports keyboard input, primarily because
there isn't a good way to use the mouse in a game like this. The
keyboard input in the <TT><FONT FACE="Courier">TravelingGecko</FONT></TT>
class is handled in the <TT><FONT FACE="Courier">keyDown</FONT></TT>
method, which follows:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">public boolean keyDown(Event evt, int
key) {<BR>
// Change the gecko velocity based on the key pressed
<BR>
switch (key) {<BR>
case Event.LEFT:<BR>
gecko.setVelocity(new Point(-8, 0));<BR>
break;<BR>
case Event.RIGHT:<BR>
gecko.setVelocity(new Point(8, 0));<BR>
break;<BR>
case Event.UP:<BR>
gecko.setVelocity(new Point(0, -8));<BR>
break;<BR>
case Event.DOWN:<BR>
gecko.setVelocity(new Point(0, 8));<BR>
break;<BR>
}<BR>
return true;<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
The <TT><FONT FACE="Courier">keyDown</FONT></TT> method simply
sets the velocity of the gecko sprite based on which one of the
arrow keys is being pressed. Notice that the magnitude of the
velocity is set to <TT><FONT FACE="Courier">8</FONT></TT>, which
means that the gecko moves eight pixels on the screen for each
key press.
<P>
The <TT><FONT FACE="Courier">action</FONT></TT> method is used
to handle the user clicking the New Game button:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">public boolean action(Event evt, Object
arg) {<BR>
if (evt.target instanceof Button)<BR>
if (((String)arg).equals("New Game"))
<BR>
newGame();<BR>
return true;<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
If the <TT><FONT FACE="Courier">action</FONT></TT> method detects
that a button has been clicked, the <TT><FONT FACE="Courier">newGame</FONT></TT>
method is called to start a new game. Speaking of the <TT><FONT FACE="Courier">newGame</FONT></TT>
method, here it is:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">void newGame() {<BR>
// Set up a new game<BR>
lives = 4;<BR>
score = 0;<BR>
tgv = new TGVector(new ImageBackground(this, back),
this);<BR>
gecko = new Gecko(this);<BR>
tgv.add(gecko);<BR>
for (int i = 0; i < 4; i++)<BR>
tgv.add(new Rock(this, i));<BR>
tgv.add(new GilaMonster(this));<BR>
tgv.add(new Scorpion(this));<BR>
tgv.add(new Rattler(this));<BR>
tgv.add(new Tarantula(this));<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
The <TT><FONT FACE="Courier">newGame</FONT></TT> method does everything
necessary to set up a new game; the <TT><FONT FACE="Courier">lives</FONT></TT>
and <TT><FONT FACE="Courier">score</FONT></TT> member variables
are initialized, the sprite list is re-created, and all the sprites
are added back to the list. Notice that a reference to the gecko
sprite is stored away in the <TT><FONT FACE="Courier">gecko</FONT></TT>
member variable so that it can be accessed in <TT><FONT FACE="Courier">keyDown</FONT></TT>
to move the gecko.
<P>
That finishes up the details of your first Java game, Traveling
Gecko! I encourage you to study this game in detail and make sure
that you follow what is happening with the sprites. Then you can
try your hand at enhancing it and adding any new features you
can dream up.
<H2><A NAME="Summary"><B><FONT SIZE=5 COLOR=#FF0000>Summary</FONT></B></A>
</H2>
<P>
Congratulations, you made it through your first complete Java
game! In this lesson, you made the journey from concept to reality
on a pretty neat game that uses just about everything you've learned
in the book thus far. Once again, you saw the power of the sprite
classes because the majority of the game takes place within them.
You also saw how easy it is to provide keyboard support within
the context of a real game.
<P>
Even though you finished your first Java game in this lesson,
you still have a way to go on your path toward becoming a Java
game programming whiz. The good news is that you're in a nice
position, having a complete game under your belt. Your next challenge
is how to incorporate sound into Java games, which is covered
in the next section of the book. You'll learn that sound adds
a much needed dimension to games in Java.
<H2><A NAME="QA"><B><FONT SIZE=5 COLOR=#FF0000>Q&A</FONT></B></A>
<BR>
</H2>
<TABLE>
<TR VALIGN=TOP><TD WIDTH=50><B>Q</B></TD><TD><B>Why model the rocks as sprites? Aren't they really just part of the background?</B>
</TD></TR>
<TR VALIGN=TOP><TD WIDTH=50><B>A</B></TD><TD>Logically, you could think of the rocks as part of the background, in that they don't do much beyond limiting the gecko's movement. But that one action, limiting the gecko's movement, is the whole reason that
the rocks have to be implemented as sprites. If the rocks were just drawn on the background, there would be no straightforward way to detect collisions between them and the gecko.
</TD></TR>
<TR VALIGN=TOP><TD WIDTH=50><B>Q</B></TD><TD><B>Why derive different classes for all the predators?</B>
</TD></TR>
<TR VALIGN=TOP><TD WIDTH=50><B>A</B></TD><TD>Although it isn't strictly necessary to derive different classes for the predators, it is very convenient and makes for good organization because the images used by each predator are linked to the predator
class. It is also nice to have constructors with fewer parameters for each predator.
</TD></TR>
<TR VALIGN=TOP><TD WIDTH=50><B>Q</B></TD><TD><B>How does the <TT><B><FONT FACE="Courier">collision</FONT></B></TT> method in <TT><B><FONT FACE="Courier">TGVector</FONT></B></TT> know which types of sprites have collided with each other?</B>
</TD></TR>
<TR VALIGN=TOP><TD WIDTH=50><B>A</B></TD><TD>The <TT><FONT FACE="Courier">collision</FONT></TT> method uses the name of the sprite class to determine what type of sprite it is. This is accomplished by using the <TT><FONT FACE="Courier">getClass</FONT></TT>
method to get a <TT><FONT FACE="Courier">Class</FONT></TT> object for the sprite, and then the <TT><FONT FACE="Courier">getName</FONT></TT> method to get the class name as a <TT><FONT FACE="Courier">String</FONT></TT> object. When you have the string name
of a sprite class (<TT><FONT FACE="Courier">"Gecko"</FONT></TT>, for example), it's easy to take different actions based on the types of sprites that are colliding.
</TD></TR>
<TR VALIGN=TOP><TD WIDTH=50><B>Q</B></TD><TD><B>Why are the score and number of lives member variables declared as public static in the <TT><B><FONT FACE="Courier">TravelingGecko</FONT></B></TT> class?</B>
</TD></TR>
<TR VALIGN=TOP><TD WIDTH=50><B>A</B></TD><TD>Because they must be modifiable from outside the <TT><FONT FACE="Courier">TravelingGecko</FONT></TT> class. More specifically, the <TT><FONT FACE="Courier">Gecko</FONT></TT> class needs to be able to increment
the score when the gecko makes it across the screen, and the <TT><FONT FACE="Courier">TGVector</FONT></TT> class needs to be able to decrement the number of lives when the gecko collides with a predator and dies.
</TD></TR>
</TABLE>
<P>
<H2><A NAME="Workshop"><B><FONT SIZE=5 COLOR=#FF0000>Workshop</FONT></B></A>
</H2>
<P>
The Workshop section provides questions and exercises to help
you get a better feel for the material you learned today. Try
to answer the questions and at least ponder the exercises before
moving on to tomorrow's lesson. You'll find the answers to the
questions in appendix A, "Quiz Answers."
<H3><A NAME="Quiz"><B>Quiz</B></A></H3>
<OL>
<LI>What classic arcade game is Traveling Gecko based on?
<LI>How is the player rewarded for his kind help in guiding the
gecko safely across the hazardous desert?
<LI>How are the keyboard controls for the gecko implemented?
<LI>How well would a real gecko fare in the same situation?
<LI>How do you know when the New Game button has been pressed?
</OL>
<H3><A NAME="Exercises"><B>Exercises</B></A></H3>
<OL>
<LI>Change the <TT><FONT FACE="Courier">Gecko</FONT></TT> class
so that the gecko faces in the direction in which he's traveling.
<LI>Make the destination opening in the rocks vary in position.
Hint: Use smaller images for the rocks and more rock sprite objects
that can be tiled and rearranged on the screen.
<LI>Vary the speeds of the predators based on the difficulty level
(score).
<LI>Extend the predator classes to allow them to travel in either
horizontal direction. This could vary with each new game.
<LI>Do some research on geckos and see whether I'm right about
them faring pretty well in this situation.
</OL>
<P>
<HR WIDTH="100%"></P>
<CENTER><P><A HREF="ch9.htm"><IMG SRC="pc.gif" BORDER=0 HEIGHT=88 WIDTH=140></A><A HREF="index.htm"><IMG SRC="hb.gif" BORDER=0 HEIGHT=88 WIDTH=140></A><A HREF="#CONTENTS"><IMG SRC="cc.gif" BORDER=0 HEIGHT=88 WIDTH=140></A><A HREF="ch11.htm"><IMG
SRC="nc.gif" BORDER=0 HEIGHT=88 WIDTH=140></A></P></CENTER>
<P>
<HR WIDTH="100%"></P>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -