?? ch6.htm
字號:
The <TT><FONT FACE="Courier">frameInc</FONT></TT> member variable
is used to provide a means to change the way that the animation
frames are updated. For example, in some cases you might want
the frames to be displayed in the reverse order. You can easily
do this by setting <TT><FONT FACE="Courier">frameInc</FONT></TT>
to <TT><FONT FACE="Courier">-1</FONT></TT> (its typical value
is <TT><FONT FACE="Courier">1</FONT></TT>). The <TT><FONT FACE="Courier">frameDelay</FONT></TT>
and <TT><FONT FACE="Courier">frameTrigger</FONT></TT> member variables
are used to provide a means of varying the speed of the frame
animation. You'll see how the speed of animation is controlled
when you learn about the <TT><FONT FACE="Courier">incFrame</FONT></TT>
method later today.
<P>
Another member variable that you might be curious about is <TT><FONT FACE="Courier">collision</FONT></TT>,
which is a <TT><FONT FACE="Courier">Rectangle</FONT></TT> object.
This member variable is used to support rectangle collision detection,
in which a rectangle is used in collision detection tests. You'll
see how <TT><FONT FACE="Courier">collision</FONT></TT> is used
later in today's lesson when you learn about the <TT><FONT FACE="Courier">setCollision</FONT></TT>
and <TT><FONT FACE="Courier">testCollision</FONT></TT> methods.
<P>
The last member variable, <TT><FONT FACE="Courier">hidden</FONT></TT>,
is a boolean flag that determines whether or not the sprite is
hidden. When you set this variable to true, the sprite is hidden
from view. Its default setting is true, meaning that the sprite
is visible.
<P>
The <TT><FONT FACE="Courier">Sprite</FONT></TT> class has two
constructors. The first constructor creates a <TT><FONT FACE="Courier">Sprite</FONT></TT>
without frame animations, meaning that it uses a single image
to represent the sprite. The code for this constructor is as follows:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">public Sprite(Component comp, Image img,
Point pos, Point vel, int z,<BR>
int ba) {<BR>
component = comp;<BR>
image = new Image[1];<BR>
image[0] = img;<BR>
setPosition(new Rectangle(pos.x, pos.y, img.getWidth(comp),
<BR>
img.getHeight(comp)));<BR>
setVelocity(vel);<BR>
frame = 0;<BR>
frameInc = 0;<BR>
frameDelay = frameTrigger = 0;<BR>
zOrder = z;<BR>
bounds = new Rectangle(0, 0, comp.size().width, comp.size().height);
<BR>
boundsAction = ba;<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
This constructor takes an image, position, velocity, Z-order,
and boundary action as parameters. The second constructor takes
an array of images and some additional information about the frame
animations. The code for the second constructor is as follows:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">public Sprite(Component comp, Image[]
img, int f, int fi, int fd,<BR>
Point pos, Point vel, int z, int ba) {<BR>
component = comp;<BR>
image = img;<BR>
setPosition(new Rectangle(pos.x, pos.y, img[f].getWidth(comp),
<BR>
img[f].getHeight(comp)));<BR>
setVelocity(vel);<BR>
frame = f;<BR>
frameInc = fi;<BR>
frameDelay = frameTrigger = fd;<BR>
zOrder = z;<BR>
bounds = new Rectangle(0, 0, comp.size().width, comp.size().height);
<BR>
boundsAction = ba;<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
The additional information required of this constructor includes
the current frame, frame increment, and frame delay.
<P>
The <TT><FONT FACE="Courier">Sprite</FONT></TT> class contains
a number of access methods, which are simply interfaces to get
and set certain member variables. These methods consist of one
or two lines of code and are pretty self-explanatory. Check out
the code for the <TT><FONT FACE="Courier">getVelocity</FONT></TT>
and <TT><FONT FACE="Courier">setVelocity</FONT></TT> access methods
to see what I mean about the access methods being self-explanatory:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">public Point getVelocity() {<BR>
return velocity;<BR>
}<BR>
<BR>
public void setVelocity(Point vel)<BR>
{ <BR>
velocity = vel;<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
More access methods exist for getting and setting other member
variables in <TT><FONT FACE="Courier">Sprite</FONT></TT>, but
they are just as straightforward as <TT><FONT FACE="Courier">getVelocity</FONT></TT>
and <TT><FONT FACE="Courier">setVelocity</FONT></TT>. Rather than
spending time on those, let's move on to some more interesting
methods!
<P>
The <TT><FONT FACE="Courier">incFrame</FONT></TT> method is the
first <TT><FONT FACE="Courier">Sprite</FONT></TT> method with
any real substance:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">protected void incFrame() {<BR>
if ((frameDelay > 0) && (--frameTrigger
<= 0)) {<BR>
// Reset the frame trigger<BR>
frameTrigger = frameDelay;<BR>
<BR>
// Increment the frame<BR>
frame += frameInc;<BR>
if (frame >= image.length)<BR>
frame = 0;<BR>
else if (frame < 0)<BR>
frame = image.length - 1;
<BR>
}<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
<TT><FONT FACE="Courier">incFrame</FONT></TT> is used to increment
the current animation frame. It first checks the <TT><FONT FACE="Courier">frameDelay</FONT></TT>
and <TT><FONT FACE="Courier">frameTrigger</FONT></TT> member variables
to see whether the frame should actually be incremented. This
check is what allows you to vary the frame animation speed for
a sprite, which is done by changing the value of <TT><FONT FACE="Courier">frameDelay</FONT></TT>.
Larger values for <TT><FONT FACE="Courier">frameDelay</FONT></TT>
result in a slower animation speed. The current frame is incremented
by adding <TT><FONT FACE="Courier">frameInc</FONT></TT> to <TT><FONT FACE="Courier">frame</FONT></TT>.
<TT><FONT FACE="Courier">frame</FONT></TT> is then checked to
make sure that its value is within the bounds of the image array,
because it is used later to index into the array when the frame
image is drawn.
<P>
The <TT><FONT FACE="Courier">setPosition</FONT></TT> methods set
the position of the sprite. The following is their source code:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">void setPosition(Rectangle pos) {<BR>
position = pos;<BR>
setCollision();<BR>
}<BR>
<BR>
public void setPosition(Point pos) {<BR>
position.move(pos.x, pos.y);<BR>
setCollision();<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
Even though the sprite position is stored as a rectangle, the
<TT><FONT FACE="Courier">setPosition</FONT></TT> methods allow
you to specify the sprite position as either a rectangle or a
point. In the latter version, the position rectangle is simply
moved to the specified point. After the position rectangle is
moved, the collision rectangle is set with a call to <TT><FONT FACE="Courier">setCollision</FONT></TT>.
<TT><FONT FACE="Courier">setCollision</FONT></TT> is the method
that sets the collision rectangle for the sprite. The source code
for <TT><FONT FACE="Courier">setCollision</FONT></TT> is as follows:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">protected void setCollision() {<BR>
collision = position;<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
Notice that <TT><FONT FACE="Courier">setCollision</FONT></TT>
sets the collision rectangle equal to the position rectangle,
which results in simple rectangle collision detection. Because
there is no way to know what sprites will be shaped like, you
leave it up to derived sprite classes to implement versions of
<TT><FONT FACE="Courier">setCollision</FONT></TT> with specific
shrunken rectangle calculations. Therefore, to implement shrunken
rectangle collision, you just calculate a smaller collision rectangle
in <TT><FONT FACE="Courier">setCollision</FONT></TT>.
<P>
This <TT><FONT FACE="Courier">isPointInside</FONT></TT> method
is used to test whether a point lies inside the sprite. The source
code for <TT><FONT FACE="Courier">isPointInside</FONT></TT> is
as follows:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">boolean isPointInside(Point pt) {<BR>
return position.inside(pt.x, pt.y);<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
This method is very handy for determining whether the user has
clicked on a certain sprite. A good example of this is a board
game in which the user drags pieces around with the mouse. You
could implement the pieces as sprites and use the <TT><FONT FACE="Courier">isPointInside</FONT></TT>
method to see whether the mouse has clicked on one of the pieces.
<P>
The method that does most of the work in <TT><FONT FACE="Courier">Sprite</FONT></TT>
is the <TT><FONT FACE="Courier">update</FONT></TT> method, which
is shown in Listing 6.1.
<HR>
<BLOCKQUOTE>
<B>Listing 6.1. The </B><TT><B><FONT FACE="Courier">Sprite</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 = new BitSet();<BR>
<BR>
// Increment the frame<BR>
incFrame();<BR>
<BR>
// Update the position<BR>
Point pos = new Point(position.x, position.y);<BR>
pos.translate(velocity.x, velocity.y);<BR>
<BR>
// Check the bounds<BR>
// Wrap?<BR>
if (boundsAction == Sprite.BA_WRAP) {<BR>
if ((pos.x + position.width) < bounds.x)
<BR>
pos.x = bounds.x + bounds.width;
<BR>
else if (pos.x > (bounds.x + bounds.width))
<BR>
pos.x = bounds.x - position.width;
<BR>
if ((pos.y + position.height) < bounds.y)
<BR>
pos.y = bounds.y + bounds.height;
<BR>
else if (pos.y > (bounds.y + bounds.height))
<BR>
pos.y = bounds.y - position.height;
<BR>
}<BR>
// Bounce?<BR>
else if (boundsAction == Sprite.BA_BOUncE) {<BR>
boolean bounce = false;<BR>
Point vel = new Point(velocity.x,
velocity.y);<BR>
if (pos.x < bounds.x) {<BR>
bounce = true;<BR>
pos.x = bounds.x;<BR>
vel.x = -vel.x;<BR>
}<BR>
else if ((pos.x + position.width) >
<BR>
(bounds.x + bounds.width))
{<BR>
bounce = true;<BR>
pos.x = bounds.x + bounds.width
- position.width;<BR>
vel.x = -vel.x;<BR>
}<BR>
if (pos.y < bounds.y) {<BR>
bounce = true;<BR>
pos.y = bounds.y;<BR>
vel.y = -vel.y;<BR>
}<BR>
else if ((pos.y + position.height) >
<BR>
(bounds.y + bounds.height))
{<BR>
bounce = true;<BR>
pos.y = bounds.y + bounds.height
- position.height;<BR>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -