使用Java語言撰寫一個五子棋UI界面并實作網路對戰功能(非局域網)
一,前期準備
1,Java IDE(Eclipse)與JDK的安裝與配置
jdk-15.0.1-免配置路徑版
提取碼:earu
免安裝版Eclipse 解壓即可使用
提取碼:5iyy
網路上很多配置jdk的方法,我不再重復
這里提供一種便捷操作的方法(針對新手)
由于高版本jdk不需要手動配置路徑,將我上傳的jdk資源下載后一鍵安裝,路徑即可自動配置
2,一臺云主機
阿里云,騰訊云,華為云的云主機均可,我用的是windows系統
(window是自帶的遠程連接很方便),如果想用其他的也可,最好選擇一個有桌面的,這樣除錯起來容易些
在云主機上同樣需要安裝Eclipse與配置jdk,步驟同上
如果記憶體較大的可以安裝資料庫,這樣撰寫的程式上可以加賬號登錄注冊功能
我的云主機

3,另一臺可供測驗可以聯網的電腦或虛擬機
建議方便的同學用另一臺電腦,一臺電腦用手機熱點,另一臺用WiFi
這樣可以測驗外網的連接情況
4,轉換Java Jar為exe檔案的軟體(如exe4j)
網上很多關于轉換的教程(非必須,如果不需要可以忽略這一步)
二,功能分析與效果展示
1,這個程式主要分為三部分,UI界面,單機落子部分,聯網落子部分,而UI界面又分為登錄界面和棋盤界面,在這篇文章中UI界面與聯網落子部分為講述重點,
2,登錄界面實作的功能有以下幾點,首先當啟動程式時,應自動檢測與服務器的連接,如果連接失敗,則不出現網路登錄入口,如果連接成功,則出現網路對戰登錄入口,
連接失敗效果展示


連接成功效果展示


3,棋盤界面應滿足的功能,黑白棋的落子,判斷勝利,重新開始
棋盤效果展示

4,網路對戰應滿足的功能,由于很多電腦使用路由器與外網訪問(有的通信服務提供商會隱藏真實ip,故兩臺由不同路由器連接的電腦很難建立連接),同時增加撰寫難度,采用下棋雙方與服務器連接的方式,A->服務器<-B,A<-服務器->B,程式應做到迅速回應服務器資訊,減少延遲,雙方棋盤資訊應一致,

三,具體實作方法
1,棋盤UI的實作
JPanel jpan1 = new JPanel() { //根據新棋盤資訊作圖,覆寫原有Panel
private static final long serialVersionUID = 1L;
public void paint(Graphics graphics){ //重構paint函式
int xst=20,yst=20,add=32;
for(int t=0;t<15;t++) //畫豎線
{
graphics.drawLine(xst,yst,xst,468);
xst=xst+add;
}
xst=20;yst=20;add=32;
for(int t=0;t<15;t++) //畫橫線
{
graphics.drawLine(xst,yst,468,yst);
yst=yst+add;
}
graphics.setColor(Color.BLACK); //畫棋盤上五個黑點
graphics.fillOval(113, 113, 6, 6);
graphics.fillOval(369, 113, 6, 6);
graphics.fillOval(113, 369, 6, 6);
graphics.fillOval(369, 369, 6, 6);
graphics.fillOval(241, 241, 6, 6);
for(int t=0;t<15;t++) //根據棋盤陣列里存盤的棋子資訊畫黑白子
{
for(int t1=0;t1<15;t1++)
{
if(node[t][t1]==1)
{
graphics.setColor(Color.BLACK);
graphics.fillOval(t1*32+20-13,t*32+20-13,26,26);
}
if(node[t][t1]==-1)
{
graphics.setColor(Color.WHITE);
graphics.fillOval(t1*32+20-13,t*32+20-13,26,26);
}
}
}
}
};
由于每次落子棋盤都會發生變化,所以設定一個滑鼠觸發事件,當每次觸發都將視窗重繪,根據棋盤資訊陣列里的內容更新到當前局面,
2,網路對戰(服務器端編程)
網路對戰的實質是socket編程,即客戶端A將落子資訊傳給服務器,服務器將資訊傳給客戶端B,接著客戶端B將落子資訊傳給服務器,服務器傳給客戶端A,故在服務器端編程中應監聽兩個埠(我設定的是1075和1056)客戶端A將資訊通過1075埠傳給服務器,服務器將A傳過來的資訊通過1056傳給服務器B,默認先連接的是黑子,當黑子連接成功后,監聽白子連接,
package cilent;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class test {
public static void main(String[] args) {
ServerSocket server,server1;
try {
server = new ServerSocket(1075);
Socket socket=server.accept();
System.out.println("black is ok");
server1 = new ServerSocket(1056);
Socket socket1=server1.accept();
System.out.println("white is ok");
while(true){
System.out.println("----------");
InputStream in,in1;
try {
in = socket.getInputStream();
byte [] b=new byte[1024];
StringBuffer sb=new StringBuffer();
String s;
if(in.read(b) !=-1){
s=new String(b);
sb.append(s);
}
OutputStream out1=socket1.getOutputStream();
System.out.println("黑發給白"+sb);
out1.write(sb.toString().getBytes());
out1.flush();
in1 = socket1.getInputStream();
byte [] b1=new byte[1024];
StringBuffer sb1=new StringBuffer();
String s1;
if(in1.read(b1) !=-1){
s1=new String(b1);
sb1.append(s1);
}
OutputStream out=socket.getOutputStream();
System.out.println("白發給黑"+sb1);
out.write(sb1.toString().getBytes());
out.flush();
} catch (IOException e) {
// e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
3,網路對戰(客戶端編程)
在客戶端這邊不僅要考慮資料的發送與接收,還要考慮接識訓發送的資料在表單上如何實時的顯示,為此我自己創立了一套編碼解碼方式,為方便每次發送的資訊的格式為XX*YY,前兩位為二維陣列行數,后兩位為二維陣列列數,發送部分代碼如下
if(xrec<=9) //確認發送資料格式 XX*XX XX指二維陣列列,行
sent="0"+xrec;
else
sent=""+xrec;
sent=sent+"*";
if(yrec<=9)
sent=sent+"0"+yrec;
else
sent=sent+""+yrec;
System.out.println("==========");
try {
socket.getOutputStream().write(sent.getBytes());
System.out.println("MY sent:"+sent);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
socket.getOutputStream().flush();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} //發送完畢
由于socket的接收函式有阻塞性,當執行接收函式時,程式被阻塞,表單無法及時更新,這樣就會出現無法更新落子資訊,當接收到對方落子時一次更新兩個棋子的情況,為解決這個問題,將本機落子與接收落子分隔開,當滑鼠按下時更新本機落子,當滑鼠松開時接收服務器資訊,
void jieshou(Socket socket, JFrame jFrame)
{
//temp=1;
InputStream in = null;
try {
in = socket.getInputStream();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
JOptionPane.showMessageDialog(null,"對方未就緒!");
}
byte[] b = new byte[1024];
StringBuffer sb = new StringBuffer();
try {
if (in.read(b) != -1) {
s = new String(b);
System.out.println(s);
sb.append(s);
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
JOptionPane.showMessageDialog(null,"對方未就緒!");
}
System.out.println("來自服務器的資料:" + sb); //收到對方落子資訊
int xnew=(sb.charAt(0)-'0')*10+(sb.charAt(1)-'0');//解碼
int ynew=(sb.charAt(3)-'0')*10+(sb.charAt(4)-'0');
if(node[xnew][ynew]==0) { //更改對方落子
node[xnew][ynew]=-1;
// m=1;
}
JPanel jpan1 = new JPanel() { //根據新棋盤資訊作圖,覆寫原有Panel
private static final long serialVersionUID = 1L;
public void paint(Graphics graphics){
super.paint(graphics);
int xst=20,yst=20,add=32;
for(int t=0;t<15;t++)
{
graphics.drawLine(xst,yst,xst,468);
xst=xst+add;
}
xst=20;yst=20;add=32;
for(int t=0;t<15;t++)
{
graphics.drawLine(xst,yst,468,yst);
yst=yst+add;
}
graphics.setColor(Color.BLACK);
graphics.fillOval(113, 113, 6, 6);
graphics.fillOval(369, 113, 6, 6);
graphics.fillOval(113, 369, 6, 6);
graphics.fillOval(369, 369, 6, 6);
graphics.fillOval(241, 241, 6, 6);
for(int t=0;t<15;t++)
{
for(int t1=0;t1<15;t1++)
{
if(node[t][t1]==1)
{
graphics.setColor(Color.BLACK);
graphics.fillOval(t1*32+20-13,t*32+20-13,26,26);
}
if(node[t][t1]==-1)
{
graphics.setColor(Color.WHITE);
graphics.fillOval(t1*32+20-13,t*32+20-13,26,26);
}
}
}
}
};
jFrame.add(b1);
jFrame.add(jpan1);
jFrame.setVisible(true);
//temp=0;
}
如果有興趣的同學也可以在服務器端加一個本地服務器(推薦SQL server)搭配jdbc實作一個客戶端登錄程式(類似QQ),具體如何實作我會在下節詳細敘述,
有需要的可以給我留言,分享原始碼
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/248507.html
標籤:其他
上一篇:STM32學習筆記(五)
