• 沒有找到結果。

系統平台

在文檔中 網路象棋遊戲 (頁 5-0)

第二章 系統環境介紹

2.1 系統平台

作業系統 : Window 2000 專業版 程式語言 : Java 1.4

網頁伺服器: BRS Web Weaver

2.2 設定 BRS Web Weaver

1. 安裝 BRS Web Weaver 軟体 2. 設定 Sever IP 及 虛擬目錄

圖一 web Sever IP 設定

圖二 Virtual Root 及預設文件之設定

2.3 Java I/O 概論:

JAVA 把 I/O 動作(包含讀寫檔、存取記憶体、網路資源或是將 資料顯示在燭幕上都算是 I/O 串流)視為串流。JAVA 裡面的串流是位 元或字元的組合。程式編撰人員可以透過串流來讀取或寫入資料。甚 至可以透過串流連到資料來源並將資料以位元或字元陣列的形式儲 存起來。

Stream, Reader 與 Writer 元件

透過串流的作法可以使得撰寫資料來源的程式更為一致,我們 只需要利用 JAVA 中的 java.io 的類別庫就可以將各種檔案處理、記憶 体處理或是網路處理都視為串流來做處理即可。

在 JAVA 裡面我譬可以透過他的 InputStream,OutputStream,

Reader , 和 Writer 類 別 來 處 理 串 流 I/O 。 其 中 InputStream 和 OutputStream 主要用在以位元為主的串流中,而 Reader 和 Writer 類 別則用來處理以字元為主的串流。有的串流元件可以做記憶体的緩衝 處理,有的則沒有這樣的功能。

一般都透過串流類別的建構來建立串流位元,但串流類別區分為 輸入串流和輸出串流,因此程式撰寫人員需選用適合的串流類別加以 使用才行。建好串流物件之後,皆下來則是用到他裡面的 read 和 write 方法來讀取或傳輸資料。而使用完一個串流物件之後,還需透過它的

close 方法來關閉串流,並結束對資料來源的處理。

2.4 Java Applet 概論:

Applet 能動態的將 web sever 中的資料下載到瀏覽器之中。接著 在瀏覽器所在的環境下去執行 Applet。然而從網路上下載程式並於用 戶端電腦中執行事件頗具危險。因此,Applet 並沒有和其他具潛在它 危險的應用程式一樣,它們被限制在某個範圍內運作。換句話來說,

它們不可以在超出範圍處執行程式碼。

舉例來說,Applet 通常是不被允許做執行讀取或寫入的動作。因 為此行為存在著摧毀磁碟中所有資料的危險性。Applet 也不可以執行 電腦中原有的程式碼,因此被限制無法啟動用戶端應用程式。

或許對於許多使用者照成莫大的不方便,然而這些預設的限制乃 在於保護使用者避免掉不必要的損失。不過,JAVA 的安全架構正逐 漸成形,而有另一種機制,它允許使用者釋放對 Applet 的限制,使 得 Applet 可以執行可信賴的程式碼,而被用來區分可信賴與不可信 賴的程式碼為一數字符號,每個 Applet 會有一個數字符號,如果當 使用者相信此程式是沒有問題時,那他便可以選擇釋放 Applet 的限 制。

2.4.1 Applet 的生命週期

在我們一般所撰寫的 JAVA 應用程式當中我們是透過 main()開 始執行。但 Applet 則 必 需 透 過 web 瀏覽器或其他工具,例如 Appletviewer 來執行,因為 Applet 中沒有 main()方法。

Applet 的生命週期由四個方法所組成,分別為 init()、start()、stop() 及 destroy()。這些方法都可以在 java.applet.Applet 類別中定義。而每 個 Applet 都有此特性。

在 Applet 開始執行時會先呼叫 init()方法。在 init()方法中程式碼 僅會執行一次。例如:讀取 HTML 檔案中所定義的參數。

在 init()方法完成執行後,start()方法開始執行。透過 Appletviewer 或 Web 瀏覽器最小化時,會去呼叫 stop 方法。而在 Applet 瀏覽器最 大化時,則會呼叫 start 方法。

若使用者正在瀏覽一個含有 Applet 的網頁。接著跳到另一個網 頁,則會呼叫 stop 方法。但若使用者再度返回原網頁時,則瀏覽器 會呼叫 start()方法。最後,在 applet 執行結束之前,appletviewer 或 web 瀏覽器會去呼叫 destroy()方法。不過,在呼叫 destroy()方法之前,

還會先去呼叫 stop()方法。

2.5 JAVA Socket 簡介

Socket 是網路應用程式的核心,不論 Sever 端或 Client 端網路應 用程式 Socket 皆為不可或缺之要素,二台電腦若要相連,首先 server 端及 Client 端都要建立一個 socket,當 server 端偵測到來自 client 端的連結請求時,則接受此請求並藉此建立 client 端之 socket,此 socket 將做為此 client 端連線及後續處理傳送及接收資 料的依據,至此則完成 server 端與 client 端的 socket 通訊連結。

以下為大致上的流程圖:

ServerSocket

Connection Client

Accept Request

read

write Close

Server

圖三 socket 流程圖

第三章 Client 端遊戲程式

3.2 棋盤與棋子的建立

public Chess_tab(int x,int y,int n,int sta,int kind,int my_cr) {

初始值為:

tab[0][0] = new Chess_tab( 0, 0, 5,1,5,0);

tab[0][1] = new Chess_tab( 40, 0, 4,1,4,0);

tab[0][2] = new Chess_tab( 80, 0, 3,1,3,0);

tab[0][3] = new Chess_tab(120, 0, 2,1,2,0);

tab[0][4] = new Chess_tab(160, 0, 1,1,1,0);

tab[0][5] = new Chess_tab(200, 0, 2,1,2,0);

tab[0][6] = new Chess_tab(240, 0, 3,1,3,0);

tab[0][7] = new Chess_tab(280, 0, 4,1,4,0);

tab[0][8] = new Chess_tab(320, 0, 5,1,5,0);

tab[1][0] = new Chess_tab( 0, 40, 0,0,0,0);

… … .

… … … .

tab[8][8] = new Chess_tab(320,320, 0,0,0,0);

tab[9][0] = new Chess_tab( 0,360,15,1,5,1);

tab[9][1] = new Chess_tab( 40,360,14,1,4,1);

tab[9][2] = new Chess_tab( 80,360,13,1,3,1);

tab[9][3] = new Chess_tab(120,360,12,1,2,1);

tab[9][4] = new Chess_tab(160,360,11,1,1,1);

tab[9][5] = new Chess_tab(200,360,12,1,2,1);

tab[9][6] = new Chess_tab(240,360,13,1,3,1);

tab[9][7] = new Chess_tab(280,360,14,1,4,1);

tab[9][8] = new Chess_tab(320,360,15,1,5,1);

記錄著一開始棋盤的貼圖狀況,之後每移動一步這個 tab 將會跟著 改變,直到遊戲結束。

3.3 移動棋子

在 mouseDown 函式中,先檢查了 lock 和 gameover 這二個變 數,lock 是用來檢查是否是自已可以移動的回合,而 gameover 則是 檢查是否遊戲是否已經結束了。mouseDown 函式中會取得按下左鍵 時的座標位置,然後透過 find_witch 函式

public void find_which(int x,int y) {

int cx,cy;

for(int i=0;i<10;i++) {

for(int j=0;j<9;j++) {

cx = tab[i][j].pt.x + 20; cy = tab[i][j].pt.y + 20;

if(Math.abs(x - cx)<20 && Math.abs(y - cy)<20) {

row = i; col = j;

} } } }

找出其對應在棋盤上 90 個點中的哪一個,再把其值傳回去 mouseDown 然後檢查是否是自已方的棋子、和傳出是哪一顆棋子以 便移動動作完成後去作棋步是否合法的檢查。

在 mouseDrag 中,邊拖曳時必需 repaint ,這邊我們只重貼以 棋子為中心長寬個 90,就是下面的程式:

repaint(x-30,y-30,90,90);

這樣可以避免整個畫面因為 repaint 過於頻煩而產生閃爍的感覺。

最後,在 mouseUp 中,同樣的經過 find_which 函式找出棋盤上 的點,然後去檢查是否按下和放開的點是同樣一個點,也就是原地不 動這項,原地不動代表著玩家放棄了移動這顆棋子的想法,而去移動 別顆棋。如果兩個點不同,則將 棋子的種類、移動前的點、移動後 的點送出檢查,如檢查合法,則完成移動並檢查是否有 將軍對將軍 的情況產生,如果有,則遊戲結束,如果沒有則將移動的訊息送給對 方,並將畫可重新貼過。

3.4 走法檢查

象棋中,包函了:將、士、象、車、馬、包和卒等七種不同類形 的棋子,每種的走法都不盡相同,所以我們利用 switch(k) 也就是先 檢查 kind 這一項,將、士、象、車、馬、包、卒 分別是 kind 的 1、

2、3、4、5、6、7,然後再去檢查棋步是否合法。

將、士、象,都屬於不能過河的棋子,所以並沒有去檢查是否有 吃掉對方的將,檢查步驟較其他的棋子少了一步,車、馬、包和卒再 檢查移動是否合法時,也必需同時檢查是否吃掉了對方的將。

將:可上下左右移動一步,但只能在九宮中移動。

if(Math.abs(f_x - to_x) + Math.abs(f_y - to_y) == 1) {

if(to_y < 6 && to_y > 2 && to_x > 6) {

if(tab[to_x][to_y].my_color == 0) {

clip0.play();

return true;

}

clip7.play();

return false;

}

clip7.play();

return false;

}

先檢查是否是往橫或直的方向移動一格,再去檢查移動完是否還在九 宮格內,最後去檢查要目地的點是否有自已方的棋子,如果都合法則 傳回移動完成,並送出移動音效。

士:只能在九宮格中的斜線中往斜向移動一格。

if(Math.abs(f_x - to_x) == 1 && Math.abs(f_y - to_y) == 1) {

if(to_y < 6 && to_y > 2 && to_x > 6) {

if(tab[to_x][to_y].my_color == 0) {

clip1.play();

return true;

}

clip7.play();

return false;

}

clip7.play();

return false;

}

先檢查是否是往斜向的方向移動一格,再檢查移動完後是否還在九宮 格內,最後去檢查要目地的點是否有自已方的棋子,如果都合法則傳 回移動完成,並送出移動音效。

象:只能移動田字形,並且不能過河,且不能憋象眼。

if(Math.abs(f_x - to_x) == 2 && Math.abs(f_y - to_y) == 2) {

if(( (to_x > f_x) && (to_y > f_y) && tab[f_x+1][f_ y+1].state == 0 ) ||

( (to_x > f_x) && (to_y < f_y) && tab[f_x+1][f_y-1].state == 0 ) ||

( (to_x < f_x) && (to_y > f_y) && tab[f_x-1][f_y+1].state == 0 ) ||

( (to_x < f_x) && (to_y < f_y) && tab[f_x-1][f_y-1].state == 0 ) ) {

if(tab[to_x][to_y].my_color == 0) {

馬:走日字形,但不能拐馬腳。

if(tab[to_x][to_y].my_color == 0) {

if (tab[row][col].kind == 1 && tab[row][col].my_color == 0) {

車:能往直或橫的移動,沒有限定移動的格數。

if(f_x - to_x == 0 && to_y > f_y + 1) {

for(int i = to_y - 1;i > f_y ;i--) {

if (tab[f_x][i].state != 0) retur n false;

}

if(tab[to_x][to_y].my_color == 0) {

if (tab[row][col].kind == 1 && tab[row][col].my_color == 0) {

包:能往直或橫移動,沒有限定格數,但在要吃掉對方棋子時,中間

if (tab[f_x][i].state != 0) count++;

}

if (count == 1) {

if(tab[to_x][to_y].state == 1 && tab[to_x][to_y].my_color == 0) {

if (tab[row][col].kind == 1 && tab[row][col].my_color == 0) {

if(tab[to_x][to_y].state == 0) {

行。假如棋子數為 0 的話,那就是普通移動的狀態,那目地點就不 能有任何的棋子才行。

如果只是往直或橫的方向移動一格,則檢查方法和將類似。

卒:在自已的領地中,只能往前不能後退;在對方的領地中,可以往 前、右或左,也不能往後走。一次只能移動一格。

if((f_x == 5 || f_x ==6) && to_y - f_y ==0 && f_x - to_x == 1) {

if(tab[to_x][to_y].my_color == 0) {

if(tab[to_x][to_y].my_color == 0) {

if (tab[row][col].kind == 1 && tab[row][col].my_color == 0) {

if(tab[to_x][to_y].my_color == 0) {

if (tab[row][col].kind == 1 && tab[row][col].my_color == 0)

gameover = 1;

clip8.play();

} clip6.play();

return true;

} }

clip7.play();

return false;

}

這是在對方領地中的檢查程式,檢查是否是往前、右或左移動一格,

再來檢查目地點是否有自已方的棋子。

3.5 遊戲結束檢查

在象棋遊戲中,一場遊戲的結束有二種情況,第一就是一方吃掉另一 方的將軍,而第二種情況就是將軍對將軍(也就是雙方的將軍在同一 條直線上,且中間沒有其他的棋子),吃掉另一方的將軍的情況,我 們在棋步走法是否合法裡面就順便檢查了是否有吃掉對方的將軍這 一項了,剩下將軍對將軍的情況,我們建立了一個 class :checkKind1() 在 mouseUp 裡,檢查完棋步是否合法後去呼叫這個 class 做將軍對 將軍的檢查,檢查的方法分成二種狀況:第一種就是移動的棋子是將 軍的時後,這時必需用目地點去做檢查,先檢查目地點的直線上面是 否同時存在有二顆將軍的棋子,如果同時存在二顆將軍則去檢查將軍 和將軍中是否有其他的棋子,如果沒有則遊戲就結束了;另一種情況 就是移動的棋子並不是將軍,這時後就要用起始點去作檢查,先去檢 查起始點是不是在九宮格的直線上,也就是我們棋盤上 y = 3,4,5 這三條直線上,如果是在這三條直線上再去檢查他是否是橫向的移 動,如果是往橫的移動則去檢查起始點的直線上是否有二顆將軍,然 後再去檢查二顆將軍中間是否有其他的棋子,如果沒有則遊戲結束。

3.6 音效

關於音效部分,總共包含了七種棋子的移動音效、錯誤音效和遊戲結 束的音效,先在 index.html 裡面作讀檔的動作:

<applet code="netchess.class" height=400 width=360 clip0= "將.wav"

String fileName0 = getParameter("clip0");

clip0 = getAudioClip(getDocumentBase(),fileName0);

String fileName1 = getParameter("clip1");

clip1 = getAudioClip(getDocumentBase(),fileName1);

… ..

… … .

String fileName7 = getParameter("clip7");

clip7 = getAudioClip(getDocumentBase(),fileName7);

String fileName8 = getParameter("clip8");

clip8 = getAudioClip(getDocumentBase(),fileName8);

從 clip0 到 clip8 共九個,在棋步檢查中如果檢查移動合法,則會送 出各個棋子的移動音效,如果檢查不合法,則送出錯誤音效,遊戲結 束的音效則是在吃掉對方的將軍或將軍對將軍的情況下送出。

3.7 訊息的傳送與接收

關於棋步資訊的傳送,因為我們自訂了九十個 chess_tab 的物件,

而每個物件紀綠了目前有無棋子、棋子種類… 等,故我們傳送四個 data, 分別為移動前的座標及移動後的座標,因為要考慮到對方收到 棋子時,畫面是更新上方,也就是說 client 都是移動下方的棋子,所 以要對棋子的座標做轉換,以及棋子顏色的轉換:

傳送

public void send_state(int f_r,int f_c,int t_r,int t_c) {

lock = 1;

int from_row,from_col,to_row,to_col;

from_row = f_r; //來源座標 from_col = f_c; // 來源座標 to_row = t_r; //目的座標 to_col = t_c; //目的座標

from_row = f_r; //來源座標 from_col = f_c; // 來源座標 to_row = t_r; //目的座標 to_col = t_c; //目的座標

在文檔中 網路象棋遊戲 (頁 5-0)

相關文件