📄 ch10.htm
字号:
The <TT><FONT FACE="Courier">Gecko</FONT></TT> class contains
the following custom sprite actions that are used to add the predators:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">public static final int SA_ADDGILAMONSTER
= 3,<BR>
SA_ADDSCORPION
= 4,<BR>
SA_ADDRATTLER
= 5,<BR>
SA_ADDTARANTULA
= 6;</FONT></TT>
</BLOCKQUOTE>
<P>
Looking at these sprite actions, it might seem a little strange
to allow the gecko to add predators. However, you'll see in a
moment that adding new predators is based on the gecko making
it safely across the desert, which can only be detected from within
the <TT><FONT FACE="Courier">Gecko</FONT></TT> class.
<P>
The constructor for <TT><FONT FACE="Courier">Gecko</FONT></TT>
is pretty simple:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">public Gecko(Component comp) {<BR>
super(comp, image, 0, 1, 0, new Point(42, 232), new
<BR>
Point(0, 0), 20, Sprite.BA_STOP);<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
Notice in the constructor that the <TT><FONT FACE="Courier">BA_STOP</FONT></TT>
bounds action is specified, which keeps the gecko from being able
to wrap around the sides of the game window.
<P>
The <TT><FONT FACE="Courier">setCollision</FONT></TT> method is
used to shrink the gecko's collision rectangle so that collision
detection isn't quite so sensitive:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">protected void setCollision() {<BR>
collision = new Rectangle(position.x + 3, position.y
+ 3,<BR>
position.width - 6, position.height -
6);<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
Shrinking the gecko's collision rectangle is important because
having one of the legs of the gecko collide with a predator shouldn't
be enough to get him into trouble. By shrinking the collision
rectangle, you require more contact for the gecko to qualify as
a free lunch.
<P>
The <TT><FONT FACE="Courier">update</FONT></TT> method in <TT><FONT FACE="Courier">Gecko</FONT></TT>
does most of the work. Listing 10.1 contains the source code for
the <TT><FONT FACE="Courier">update</FONT></TT> method.
<HR>
<BLOCKQUOTE>
<B>Listing 10.1. The </B><TT><B><FONT FACE="Courier">Gecko</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 BitSet update() {<BR>
BitSet action = super.update();<BR>
<BR>
// Toggle the frame and clear the velocity<BR>
if (velocity.x != 0 || velocity.y != 0) {<BR>
frame = 1 - frame;<BR>
setVelocity(new Point(0, 0));<BR>
}<BR>
<BR>
// Has he made it?<BR>
if (position.y < 8) {<BR>
// Update the score and reposition the
gecko<BR>
TravelingGecko.score += 25;<BR>
position.x = 42;<BR>
position.y = 232;<BR>
<BR>
// See if we should add another bad guy
<BR>
if (TravelingGecko.score % 100 == 0) {
<BR>
Random rand = new Random(System.currentTimeMillis());
<BR>
switch(rand.nextInt() % 4)
{<BR>
case 0:<BR>
// Set flag to
add a Gila monster<BR>
action.set(Sprite.SA_ADDSPRITE);
<BR>
action.set(Gecko.SA_ADDGILAMONSTER);
<BR>
break;<BR>
case 1:<BR>
// Set flag to
add a scorpion<BR>
action.set(Sprite.SA_ADDSPRITE);
<BR>
action.set(Gecko.SA_ADDSCORPION);
<BR>
break;<BR>
case 2:<BR>
// Set flag to
add a rattler<BR>
action.set(Sprite.SA_ADDSPRITE);
<BR>
action.set(Gecko.SA_ADDRATTLER);
<BR>
break;<BR>
case 3:<BR>
// Set flag to
add a tarantula<BR>
action.set(Sprite.SA_ADDSPRITE);
<BR>
action.set(Gecko.SA_ADDTARANTULA);
<BR>
break;<BR>
}<BR>
}<BR>
}<BR>
<BR>
return action;<BR>
}</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
The <TT><FONT FACE="Courier">update</FONT></TT> method first calls
the superclass <TT><FONT FACE="Courier">update</FONT></TT> method
to handle all the standard sprite updating. It then toggles the
gecko's animation frame and clears the velocity. The animation
frame is toggled because there are only two frames, <TT><FONT FACE="Courier">0</FONT></TT>
and <TT><FONT FACE="Courier">1</FONT></TT>. Because there are
only two frames, you can just toggle them rather than increment
the current frame. The velocity has to be cleared because of the
way you're handling user input. When the user presses an arrow
key to move the gecko, the gecko's velocity is set accordingly.
But you only want the gecko to move once for each key press. The
solution is to update the gecko, allowing his position to be altered
based on the velocity, and then clear the velocity.
<P>
A check is then performed to see whether the gecko made it across
the desert. Because the rocks block him from getting to the top
of the screen in all places except the opening, you simply check
his vertical position to see whether he made it. If so, the score
is updated and he is repositioned back at the start. Notice that
the score is referenced from the <TT><FONT FACE="Courier">TravelingGecko</FONT></TT>
class. It is declared as public static in <TT><FONT FACE="Courier">TravelingGecko</FONT></TT>
so that other objects can get to it without having access to a
<TT><FONT FACE="Courier">TravelingGecko</FONT></TT> object. Technically,
this goes against standard object-oriented design practice, but
the reality is that it would be very difficult to give access
to the <TT><FONT FACE="Courier">score</FONT></TT> variable using
only access methods. You learn about the <TT><FONT FACE="Courier">TravelingGecko</FONT></TT>
class a little later in this section.
<P>
The <TT><FONT FACE="Courier">update</FONT></TT> method then decides
whether or not to add a new predator. This determination is based
on the score: For every 100 points, a new predator is added. A
predator is randomly chosen and the appropriate sprite action
flags are set to trigger the creation.
<P>
The last method in <TT><FONT FACE="Courier">Gecko</FONT></TT>
is <TT><FONT FACE="Courier">addSprite</FONT></TT>, which handles
creating the predator sprite objects:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">protected Sprite addSprite(BitSet action)
{<BR>
// Add new bad guys?<BR>
if (action.get(Gecko.SA_ADDGILAMONSTER))<BR>
return new GilaMonster(component);<BR>
else if (action.get(Gecko.SA_ADDSCORPION))<BR>
return new Scorpion(component);<BR>
else if (action.get(Gecko.SA_ADDRATTLER))<BR>
return new Rattler(component);<BR>
else if (action.get(Gecko.SA_ADDTARANTULA))<BR>
return new Tarantula(component);<BR>
<BR>
return null;<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
The <TT><FONT FACE="Courier">addSprite</FONT></TT> method checks
the sprite action flags and creates the appropriate predator.
<TT><FONT FACE="Courier">addSprite</FONT></TT> then makes sure
to return the newly created sprite so that it can be added to
the sprite list.
<P>
Before getting to the predator classes, let's look at the <TT><FONT FACE="Courier">Geckocide</FONT></TT>
class. Listing 10.2 contains the complete source code for the
<TT><FONT FACE="Courier">Geckocide</FONT></TT> class.
<HR>
<BLOCKQUOTE>
<B>Listing 10.2. The </B><TT><B><FONT FACE="Courier">Geckocide</FONT></B></TT><B>
class.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier">public class Geckocide extends Sprite
{<BR>
protected static Image[] image = new Image[4];<BR>
<BR>
public Geckocide(Component comp, Point pos) {<BR>
super(comp, image, 0, 1, 5, pos, new Point(0,
0), 10,<BR>
Sprite.BA_DIE);<BR>
}<BR>
<BR>
public static void initResources(Applet app, MediaTracker
tracker,<BR>
int id) {<BR>
for (int i = 0; i < 4; i++) {<BR>
image[i] = app.getImage(app.getCodeBase(),
"Res/Gekcide" +<BR>
i + ".gif");
<BR>
tracker.addImage(image[i],
id);<BR>
}<BR>
}<BR>
<BR>
public BitSet update() {<BR>
BitSet action = new BitSet();<BR>
<BR>
// Die?<BR>
if (frame >= 3) {<BR>
action.set(Sprite.SA_KILL);
<BR>
return action;<BR>
}<BR>
<BR>
// Increment the frame<BR>
incFrame();<BR>
<BR>
return action;<BR>
}<BR>
}</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
The <TT><FONT FACE="Courier">Geckocide</FONT></TT> class is very
similar to the <TT><FONT FACE="Courier">Spidercide</FONT></TT>
class developed in <A HREF="ch7.htm" >Day 7</A>, except that it
displays graphics for a dying gecko. It provides a simple frame-animated
sprite that kills itself after one iteration. This functionality
is implemented in the <TT><FONT FACE="Courier">update</FONT></TT>
method, which checks the <TT><FONT FACE="Courier">frame</FONT></TT>
member variable to see whether the animation is finished.
<P>
The predator classes (<TT><FONT FACE="Courier">GilaMonster</FONT></TT>,
<TT><FONT FACE="Courier">Scorpion</FONT></TT>, <TT><FONT FACE="Courier">Rattler</FONT></TT>,
and <TT><FONT FACE="Courier">Tarantula</FONT></TT>) are all very
similar to each other and contain relatively little code. Listing
10.3 shows the source code for the <TT><FONT FACE="Courier">GilaMonster</FONT></TT>
class.
<HR>
<BLOCKQUOTE>
<B>Listing 10.3. The </B><TT><B><FONT FACE="Courier">GilaMonster</FONT></B></TT><B>
class.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier">public class GilaMonster extends Sprite
{<BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -