📄 056-060.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:Using Objects for Animations</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=2//-->
<!--PAGES=056-060//-->
<!--UNASSIGNED1//-->
<!--UNASSIGNED2//-->
<CENTER>
<TABLE BORDER>
<TR>
<TD><A HREF="052-056.html">Previous</A></TD>
<TD><A HREF="../ewtoc.html">Table of Contents</A></TD>
<TD><A HREF="060-064.html">Next</A></TD>
</TR>
</TABLE>
</CENTER>
<P><BR></P>
<P>The net result of a repaint() call is that the screen is filled with the background color before the foreground is painted. When repaint() is called quickly, the rapid alternation between background and foreground colors causes the flickering effect. Figure 2-5 clarifies the relationship between repaint(), update(), and paint(), which you should understand.
</P>
<P><A NAME="Fig5"></A><A HREF="javascript:displayWindow('images/02-05.jpg',314,247 )"><IMG SRC="images/02-05t.jpg"></A>
<BR><A HREF="javascript:displayWindow('images/02-05.jpg',314,247)"><FONT COLOR="#000077"><B>Figure 2-5</B></FONT></A> Relationship between repaint(), update(), and paint()</P>
<P>An obvious way of curing flicker is by overriding update() so it no longer clears the screen:
</P>
<!-- CODE SNIP //-->
<PRE>
public void update(Graphics g) {
paint(g)
}
</PRE>
<!-- END CODE SNIP //-->
<P>The problem with this cure is that there will be a “trail” behind any animated object (or <I>sprite</I>) that moves, since the previous frame is no longer erased. You can use this trail to make some cool effects, but there’s a more general solution to flickering, called <I>double-buffering.</I></P>
<H4 ALIGN="LEFT"><A NAME="Heading8"></A><FONT COLOR="#000077">Using Double-Buffering to Eliminate Flicker</FONT></H4>
<P>Double-buffering, as the name implies, makes use of two buffers: the original graphics context and an <I>offscreen</I> graphics context. Each frame of the animation is rendered on the offscreen buffer, starting with the splash of background color. When the offscreen buffer is ready, its contents are drawn to the original graphics context. The net result: There isn’t any flicker, because all of the elements of each frame of the animation are drawn to the screen at once, instead of one by one. Figure 2-6 illustrates the action of double-buffering.</P>
<P><A NAME="Fig6"></A><A HREF="javascript:displayWindow('images/02-06.jpg',463,400 )"><IMG SRC="images/02-06t.jpg"></A>
<BR><A HREF="javascript:displayWindow('images/02-06.jpg',463,400)"><FONT COLOR="#000077"><B>Figure 2-6</B></FONT></A> Double-buffering in action</P>
<P>Let’s translate this into Java. First, you must declare an offscreen buffer, using the following syntax:
</P>
<!-- CODE SNIP //-->
<PRE>
Graphics offscreen; // Declaration of offscreen buffer
Image image;
</PRE>
<!-- END CODE SNIP //-->
<P>Think of an Image as a complete picture that can be blasted to the screen. (You’ll learn more about images in Chapter 3, Animating Sprites.)
</P>
<P>The actual allocation of the offscreen buffer should take place in the init() method of the applet:</P>
<!-- CODE SNIP //-->
<PRE>
public void init() {
... other initializations ...
image = createImage(width,height); // allocation of offscreen
offscreen = image.getGraphics(); // buffer
}
</PRE>
<!-- END CODE SNIP //-->
<P>The Image method getGraphics() returns the graphics context associated with the image.
</P>
<P>Now modify paint() so that it draws to the offscreen buffer, instead of to the original graphics context. You must clear the offscreen buffer now to prevent getting trails. When the offscreen buffer is ready, dump it to the screen by using drawImage(). For example, here’s how Broadway’s paint() would be changed to implement double-buffering. Note that the Graphics method drawImage() paints <I>image</I> to the screen at coordinates (0,0) of the applet’s graphics context.</P>
<!-- CODE //-->
<PRE>
public void paint(Graphics g) {
offscreen.setColor(Color.black);
offscreen.fillRect(0,0,300,300); // clear buffer
offscreen.setColor(Color.yellow);
offscreen.fillRect(0,0,90,90);
offscreen.fillRect(250,0,40,190);
...
offscreen.setColor(Color.magenta);
offscreen.fillRect(200,55,60,135);
g.drawImage(image,0,0,this); // draw offscreen buffer
// to screen
}
</PRE>
<!-- END CODE //-->
<P>To use double-buffering in your own applets, paste in the declarations of the image and offscreen buffer, and modify init() and paint() as has just been discussed. You’ll also need to override update() so it doesn’t clear the screen:
</P>
<!-- CODE SNIP //-->
<PRE>
public void update(Graphics g) {
paint(g)
}
</PRE>
<!-- END CODE SNIP //-->
<P>Voilà—flicker-free animation! Next, let’s discuss a simple way of improving the performance of the animation.
</P>
<H4 ALIGN="LEFT"><A NAME="Heading9"></A><FONT COLOR="#000077">Using Clipping to Improve Performance</FONT></H4>
<P>If you look carefully at the Broadway applet again, you’ll notice that the animation takes place in the center of the screen, and the surrounding portions remain unchanged. As a result, dumping the entire offscreen buffer to the screen seems to be a waste. Ideally, only the part of the offscreen buffer that changed should be copied. Java makes it easy to specify the portion of the graphics buffer that needs to be modified by subsequent graphics operations. Defining a <I>clipping rectangle</I> for a graphics context limits future changes to the interior and edges of that rectangle. In the case of Broadway, the clipping rectangle might be the maximum region that the moving rectangle traverses, as shown in Figure 2-7.</P>
<P><A NAME="Fig7"></A><A HREF="javascript:displayWindow('images/02-07.jpg',466,399 )"><IMG SRC="images/02-07t.jpg"></A>
<BR><A HREF="javascript:displayWindow('images/02-07.jpg',466,399)"><FONT COLOR="#000077"><B>Figure 2-7</B></FONT></A> Clipping rectangle for Broadway</P>
<P>To define a clipping region, use the Graphics method clipRect():
</P>
<!-- CODE SNIP //-->
<PRE>
// sets clipRect to rectangle at (x,y) with the
// specified width and height
g.clipRect(int x, int y, int width,int height);
</PRE>
<!-- END CODE SNIP //-->
<P>Now Broadway’s update() can be modified in the following way:
</P>
<!-- CODE SNIP //-->
<PRE>
public void update(Graphics g) {
g.clipRect(70,90,130,110);
paint(g);
}
</PRE>
<!-- END CODE SNIP //-->
<P>You might be wondering why the call to g.clipRect() occurs in update(), instead of in the paint() method. Remember that paint() is called to draw the applet when it first appears on the screen. By clipping in the paint() method, you’ve restricted painting to the clipping rectangle, and the region outside the clipping rectangle will always stay blank. The proper moment to clip in our applet is when a repaint() takes place, and the call to clipRect() fits nicely in update().
</P>
<P>Another way to restrict painting to a given rectangle is by using the following form of the repaint() method in the run() method of the applet:</P>
<!-- CODE SNIP //-->
<PRE>
repaint(70,90,130,110);
</PRE>
<!-- END CODE SNIP //-->
<P>This version of the repaint() method paints the area bounded by the arguments.
</P>
<P>Compile and run the double-buffered, clipped version of Broadway, and you’ll see the difference immediately.</P>
<P>Now, the next step is turning this solo boogie into a group dance!</P><P><BR></P>
<CENTER>
<TABLE BORDER>
<TR>
<TD><A HREF="052-056.html">Previous</A></TD>
<TD><A HREF="../ewtoc.html">Table of Contents</A></TD>
<TD><A HREF="060-064.html">Next</A></TD>
</TR>
</TABLE>
</CENTER>
</BODY>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -