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

📄 ch16.htm

📁 对于程序员来说可以利用JAVA来开发网络游戏!
💻 HTM
📖 第 1 页 / 共 5 页
字号:
the parameters for the depth search algorithm. The algorithm used
by <TT><FONT FACE="Courier">evaluate</FONT></TT> determines the
best move based on the calculated &quot;goodness&quot; of each
possible move. The <TT><FONT FACE="Courier">alpha</FONT></TT>
and <TT><FONT FACE="Courier">beta</FONT></TT> parameters specify
cutoffs that enable the algorithm to eliminate some moves entirely,
thereby speeding things up. It is a little beyond today's focus
to go any further into the low-level theory behind the algorithm.
If, however, you want to learn more about how it works, look into
the Web sites mentioned at the end of yesterday's lesson.
<P>
The <TT><FONT FACE="Courier">calcScore</FONT></TT> method in <TT><FONT FACE="Courier">Connect4State</FONT></TT>
is responsible for calculating the score for a player:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">private int calcScore(int player) {<BR>
&nbsp;&nbsp;int s = 0;<BR>
&nbsp;&nbsp;for (int i = 0; i &lt; winPlaces; i++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;s += score[player][i];<BR>
&nbsp;&nbsp;return s;<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
In <TT><FONT FACE="Courier">calcScore</FONT></TT>, the score of
a player is calculated by summing each element in the <TT><FONT FACE="Courier">score</FONT></TT>
array. The <TT><FONT FACE="Courier">updateScore</FONT></TT> method
handles updating the score for a player after a move:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">private void updateScore(int player,
int x, int y) {<BR>
&nbsp;&nbsp;for (int i = 0; i &lt; winPlaces; i++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;if (map[x][y][i]) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;score[player][i] &lt;&lt;=
1;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;score[getOtherPlayer(player)][i]
= 0;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;}<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
The <TT><FONT FACE="Courier">updateScore</FONT></TT> method sets
the appropriate entries in the <TT><FONT FACE="Courier">score</FONT></TT>
array to reflect the move; the move is specified in the <TT><FONT FACE="Courier">x</FONT></TT>
and <TT><FONT FACE="Courier">y</FONT></TT> parameters. The last
method in <TT><FONT FACE="Courier">Connect4State</FONT></TT> is
<TT><FONT FACE="Courier">getOtherPlayer</FONT></TT>, which simply
returns the number of the other player:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">private int getOtherPlayer(int player)
{<BR>
&nbsp;&nbsp;return (1 - player);<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
That wraps up the game engine. You now have a complete Connect4
game engine with AI support for a computer player. Keep in mind
that although you've been thinking in terms of a human versus
the computer, the game engine is structured so that you could
have any combination of human and computer players. Yes, this
means you could set up a game so that two computer players duke
it out! Pretty neat, huh?
<H3><A NAME="TheConnect4Class"><B>The </B><TT><B><FONT SIZE=4 FACE="Courier">Connect4</FONT></B></TT><B><FONT SIZE=4>
Class</FONT></B></A></H3>
<P>
The game engine classes are cool, but they aren't all that useful
by themselves; they need an applet class with some graphics and
a user interface. The <TT><FONT FACE="Courier">Connect4</FONT></TT>
class is exactly what they need. The <TT><FONT FACE="Courier">Connect4</FONT></TT>
class takes care of all the high-level game issues such as drawing
the graphics and managing human moves through mouse event handlers.
Even though it doesn't rely on the sprite classes, the <TT><FONT FACE="Courier">Connect4</FONT></TT>
applet class is still similar to other applet classes you've developed.
Let's look at its member variables first:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">private Image&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offImage,
boardImg, handImg;<BR>
private Image[]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pieceImg
= new Image[2];<BR>
private AudioClip&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newGameSnd,
sadSnd, applauseSnd,<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;badMoveSnd,
redSnd, blueSnd;<BR>
private Graphics&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offGrfx;
<BR>
private Thread&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thread;
<BR>
private MediaTracker&nbsp;&nbsp;&nbsp;&nbsp;tracker;<BR>
private int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delay
= 83; // 12 fps<BR>
private Connect4Engine&nbsp;&nbsp;gameEngine;<BR>
private boolean&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gameOver
= true,<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myMove;
<BR>
private int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;level
= 2, curXPos;<BR>
private String&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status
= new String(&quot;Your turn.&quot;);<BR>
private Font&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;statusFont
= new Font(&quot;Helvetica&quot;, Font.PLAIN, 20);<BR>
private FontMetrics&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;statusMetrics;</FONT></TT>
</BLOCKQUOTE>
<P>
The first member variables you probably noticed are the ones for
all the graphics and sound in the game. The most important member
variable, however, is <TT><FONT FACE="Courier">gameEngine</FONT></TT>,
which is a <TT><FONT FACE="Courier">Connect4Engine</FONT></TT>
object. There are also two boolean member variables that keep
up with whether the game is over (<TT><FONT FACE="Courier">gameOver</FONT></TT>)
and whose move it is (<TT><FONT FACE="Courier">myMove</FONT></TT>).
The <TT><FONT FACE="Courier">level</FONT></TT> member variable
specifies the current level of the game, and the <TT><FONT FACE="Courier">curXPos</FONT></TT>
member keeps up with which column the hand selector is currently
over. Finally, there are a few member variables for managing the
status line text and its associated font and font metrics. Let's
move on to the methods.
<P>
The <TT><FONT FACE="Courier">init</FONT></TT> method in <TT><FONT FACE="Courier">Connect4</FONT></TT>
is pretty standard; it just loads the images and audio clips:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">public void init() {<BR>
&nbsp;&nbsp;// Load and track the images<BR>
&nbsp;&nbsp;tracker = new MediaTracker(this);<BR>
&nbsp;&nbsp;boardImg = getImage(getCodeBase(), &quot;Res/Board.gif&quot;);
<BR>
&nbsp;&nbsp;tracker.addImage(boardImg, 0);<BR>
&nbsp;&nbsp;handImg = getImage(getCodeBase(), &quot;Res/Hand.gif&quot;);
<BR>
&nbsp;&nbsp;tracker.addImage(handImg, 0);<BR>
&nbsp;&nbsp;pieceImg[0] = getImage(getCodeBase(), &quot;Res/RedPiece.gif&quot;);
<BR>
&nbsp;&nbsp;tracker.addImage(pieceImg[0], 0);<BR>
&nbsp;&nbsp;pieceImg[1] = getImage(getCodeBase(), &quot;Res/BluPiece.gif&quot;);
<BR>
&nbsp;&nbsp;tracker.addImage(pieceImg[1], 0);<BR>
<BR>
&nbsp;&nbsp;// Load the audio clips<BR>
&nbsp;&nbsp;newGameSnd = getAudioClip(getCodeBase(), &quot;Res/NewGame.au&quot;);
<BR>
&nbsp;&nbsp;sadSnd = getAudioClip(getCodeBase(), &quot;Res/Sad.au&quot;);
<BR>
&nbsp;&nbsp;applauseSnd = getAudioClip(getCodeBase(), &quot;Res/Applause.au&quot;);
<BR>
&nbsp;&nbsp;badMoveSnd = getAudioClip(getCodeBase(), &quot;Res/BadMove.au&quot;);
<BR>
&nbsp;&nbsp;redSnd = getAudioClip(getCodeBase(), &quot;Res/RedMove.au&quot;);
<BR>
&nbsp;&nbsp;blueSnd = getAudioClip(getCodeBase(), &quot;Res/BlueMove.au&quot;);
<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
Although <TT><FONT FACE="Courier">init</FONT></TT> is certainly
important, the <TT><FONT FACE="Courier">run</FONT></TT> method
is where things get interesting, because the computer player's
move is handled in the main update loop inside it. Listing 16.4
contains the source code for the <TT><FONT FACE="Courier">run</FONT></TT>
method.
<HR>
<BLOCKQUOTE>
<B>Listing 16.4. The </B><TT><B><FONT FACE="Courier">Connect4</FONT></B></TT><B>
class's </B><TT><B><FONT FACE="Courier">run</FONT></B></TT><B>
method.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier">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;// Start 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() == thread) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;// Make the computer's move<BR>
&nbsp;&nbsp;&nbsp;&nbsp;if (!gameOver &amp;&amp; !myMove) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Point pos = gameEngine.computerMove(1,
level);<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (pos.y &gt;= 0) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!gameEngine.isWinner(1))
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if
(!gameEngine.isTie()) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;blueSnd.play();
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status
= new String(&quot;Your turn.&quot;);<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myMove
= true;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else
{<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sadSnd.play();
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status
= new String(&quot;It's a tie!&quot;);<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gameOver
= true;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sadSnd.play();
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status
= new String(&quot;You lost!&quot;);<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gameOver
= true;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;repaint();<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>
&nbsp;&nbsp;&nbsp;&nbsp;}<BR>
<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>
}</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
If it is the computer player's turn, the <TT><FONT FACE="Courier">run</FONT></TT>
method attempts a move using the current level by calling <TT><FONT FACE="Courier">computerMove</FONT></TT>
on the <TT><FONT FACE="Courier">gameEngine</FONT></TT> object.
If the move is successful, <TT><FONT FACE="Courier">run</FONT></TT>
checks for a win or tie, and then it plays the appropriate sound
and updates the status text.
<P>
<CENTER><TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><B>Note</B></TD></TR>
<TR><TD>
<BLOCKQUOTE>
The <TT><FONT FACE="Courier">level</FONT></TT> member variable ultimately determines how smart the computer player is by affecting the depth of the look-ahead search. This is carried out by <TT><FONT FACE="Courier">level</FONT></TT> being passed as the 
second parameter of <TT><FONT FACE="Courier">computerMove</FONT></TT>. If you find the game too easy or too difficult, feel free to tinker with the <TT><FONT FACE="Courier">level</FONT></TT> member variable, or even supply your own calculation as the 
second parameter to <TT><FONT FACE="Courier">computerMove</FONT></TT>.
</BLOCKQUOTE>

</TD></TR>
</TABLE></CENTER>
<P>
<P>
The <TT><FONT FACE="Courier">update</FONT></TT> method handles
the details of drawing the game graphics. Listing 16.5 shows the
source code for the <TT><FONT FACE="Courier">update</FONT></TT>
method.
<HR>
<BLOCKQUOTE>
<B>Listing 16.5. The </B><TT><B><FONT FACE="Courier">Connect4</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>
&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>
&nbsp;&nbsp;&nbsp;&nbsp;offGrfx = offImage.getGraphics();<BR>
&nbsp;&nbsp;&nbsp;&nbsp;statusMetrics = offGrfx.getFontMetrics(statusFont);
<BR>
&nbsp;&nbsp;}<BR>
<BR>
&nbsp;&nbsp;// Draw the board<BR>
&nbsp;&nbsp;offGrfx.drawImage(boardImg, 0, 0, this);<BR>

⌨️ 快捷键说明

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