目录
编辑器:IDEA
语言:Java
主要技术:Socket网络通讯
效果
https://www.bilibili.com/video/BV1Um4y187FV/?spm_id_from=333.999.0.0
主要思想
①服务端与客户端通讯,互相发送各个状态,以达到相对同步;
②共3个界面:服务端、客户端、游戏界面;
③倒计时结束,根据双方的金钱进行判断输赢。
实现
1.准备图片
(里面的hook.png、stone.png和loginBackground.png没有用到,主要是钩子还得跟着线甩,后采取了使用粉色小球代替钩子,相对较容易实现;stone石头和loginBackground登录背景图未添加入程序)
(1)背景图
下面两张图为主要背景,是用ps相对画了一下。
(2)金块
共3种金块,分别为小金块、中等金块和大金块,金块是在4399上截的图。
(3)矿工
共3种状态,分别为手在上(手在上时,钩子来回摇摆,等待下钩)、手在下(手在下时,钩子释放,去抓取金块)、手上下动(表示正在往上拉,钩子回收中),这个也是在4399上截的图。
(4)钩子
即粉色小球。
2.服务端与客户端搭建
服务端:
客户端:
(1)新建Server类
继承JFrame。
public class Server extends JFrame{
public static void main(String[] args) {
//点击运行,从此处开始运行
}
}
(2)添加基本元素
①多行文本框:“textArea”,主要用来显示一些重要信息,比如“开启服务”、“输赢情况”等等;
②滚动条:“scrollPane”,多行文本框的上下滚动条;
③文本:“labelPort ”→“端口号:”;
④文本输入框:“textPort ”→输入开启的端口号;
⑤按钮:“btOpen”→“开启服务”,确定好端口号,点击此按钮,代表服务端开启服务,等待来自客户端的连接;
⑥按钮:“btBegin”→“开始游戏”,客户端连接成功后,点击此按钮,可进入游戏界面。
public static JTextArea textArea = new JTextArea(5,10);//多行文本框,可以显示信息
private static JScrollPane scrollPane;//这个是给textArea添加滚动条
private static JLabel labelPort = new JLabel("端口号:");
private static JTextField textPort = new JTextField("8088",10);
private static JButton btOpen = new JButton("开启服务");
public static JButton btBegin = new JButton("开始游戏");
(3)新建launch方法
主要写入各个元素的属性(文本格式、按钮点击事件等等)。
点击查看代码
void launch(){
this.setVisible(true);//设置窗口可见
this.setSize(500,500);//窗口的大小,宽500*高500像素
this.setLocationRelativeTo(null);//窗口位置:屏幕居中
this.setTitle("黄金矿工联机版(server)");//窗口的标题
this.setResizable(false);//设置窗口不可以更改大小
setDefaultCloseOperation(EXIT_ON_CLOSE);//设置窗口的关闭事件,即点击窗口右上角的×,就可以关闭程序
setLayout(null);//设置窗口的布局
//textArea.setOpaque(false);//透明
textArea.setForeground(Color.black);//设置textArea的前景色,即里面字体的颜色
textArea.setFont(new Font("幼圆",Font.BOLD,15));//设置textArea的字体
textArea.setEnabled(false);//只读,不可以更改textArea里面的内容
textArea.setBounds(0,0,500,200);//textArea的坐标和大小
scrollPane = new JScrollPane(textArea);
scrollPane.createHorizontalScrollBar();//竖的滚动条
scrollPane.setBounds(0,0,500,200);
labelPort.setFont(new Font("幼圆",Font.PLAIN,18));
labelPort.setBounds(145,250,100,20);//500/2=250 250-(100+100+10)/2)=145
textPort.setFont(new Font("幼圆",Font.PLAIN,18));
textPort.setBounds(238,250,100,20);//162+66+10=238
//开启服务按钮
btOpen.setFont(new Font("幼圆",Font.PLAIN,15));
btOpen.setBounds(200,300,100,30);//500/2=250 250-100/2=200
btOpen.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//TODO:点击“btOpen”按钮后运行这里
}
});
//开始游戏按钮
btBegin.setFont(new Font("幼圆",Font.PLAIN,15));
btBegin.setBounds(200,350,100,30);//按钮的位置和大小
btBegin.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//TODO:点击“btBegin”按钮后运行这里
}
});
this.add(scrollPane);//把textArea添加到窗口中
this.add(labelPort);
this.add(textPort);
this.add(btOpen);
this.add(btBegin);
}
(4)新建公共类publicMeans
里面主要放置一些公共变量。
public class publicMeans {
public static String ip = null;
public static int port = 0;
public static boolean isServer = false;//记录此程序是服务端还是客户端,服务端:true;客户端:false
public static boolean isConn = false;//记录是否连接成功
public static boolean isEnd = false;//表示游戏是否结束
}
(5)创建线程类ServerThread
主要用来新建接收和发送信息的相关变量(is,isr,br,info,os,pw),然后接收并解析来自客户端的信息。
点击查看代码
public class ServerThread extends Thread{//extends Thread创建服务端线程
private Socket socket = null;
//接收来自客户端信息的相关变量
public InputStream is = null;
public InputStreamReader isr = null;
public static BufferedReader br = null;
public static String info = null;
//向客户端发送信息的相关变量
public OutputStream os = null;
public PrintWriter pw = null;
@Override
public void run() {//线程开启后,自动执行run
try{
socket = Server.serverSocket.accept();//等待客户端连接,若没有连接,就会一直在这一行代码等着,若连接了,就会下一步
publicMeans.isServer = true;//表示这个窗口是服务端
publicMeans.isConn = true;//这里表示客户端连接了,所以把isConn置为true
Server.textArea.append("连接成功。\r\n");//把这句话添加到textArea中
os = socket.getOutputStream();
pw = new PrintWriter(os);//这两个是向客户端发送信息的相关变量
is = socket.getInputStream();
isr = new InputStreamReader(is);
br = new BufferedReader(isr);//这三个事接收客户端信息的变量
while(true){//这里使用死循环,是因为要一直监视客户端有没有发过来信息
while((info = br.readLine()) != null){
//br.readLine()就是读取客户端发过来的信息,br.readLine()读取一行,然后使用while((info = br.readLine()) != null)读取发过来的所有信息
//TODO:解析客户端发过来的信息
}
}
}catch (Exception e){}
}
(6)在Server类中建立服务端
private static Socket socket;
public static ServerSocket serverSocket;
private static ServerThread thread;
public static void BuildServer(){//建立服务端
try{
serverSocket = new ServerSocket(8088);//创建服务端,8088是端口号,可以更改,这里的端口号要跟客户端的端口号一致
textArea.append("服务端开启成功,等待客户端连接......\r\n");//把这句话添加到textArea中
btOpen.setEnabled(false);//设置开启服务按钮为不可以点击的状态,因为已经开启服务了
thread = new ServerThread();//创建一个线程→第(4)步
thread.start();//线程开启,会自动执行ServerThread中的run方法
}catch (Exception e){e.printStackTrace();}
}
(7)调用建立服务端方法
在launch方法中的btOpen按钮的点击事件中引用建立服务端的方法(BuildServer)。
btOpen.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (!textPort.getText().isEmpty()){//如果textPort不为空,才可以去建立
publicMeans.port = Integer.parseInt(textPort.getText().trim());
BuildServer();//把建立服务端移到了这里
//只有点击开启服务按钮,才会去建立服务端
}
}
});
(8)在Server类中建立发送信息的方法
//服务端发送信息时引用
public static void Send(String message){
thread.pw.write(message + "\r\n");//这句就是把message发送给客户端
thread.pw.flush();
}
(9)在main方法中调用launch方法
第(1)步的main。
public static void main(String[] args){//这个main是程序入口,就是点击运行,程序从这里开始跑
Server server = new Server();
server.launch();//调用launch方法
}
(10)新建Client类
继承JFrame(创建客户端的方法与创建服务端大体相似)。
public class Client extends JFrame {
public static void main(String[] args) {
//点击运行,从此处开始运行
}
}
(11)添加基本元素
①多行文本框:“textArea”,主要用来显示一些重要信息,比如“连接成功”、“输赢情况”等等;
②滚动条:“scrollPane”,多行文本框的上下滚动条;
③文本:“labelIP”→“IP:”;
④文本输入框:“textIP”→输入服务端IP;
⑤文本:“labelPort ”→“端口号:”;
⑥文本输入框:“textPort ”→输入开启的端口号;
⑦按钮:“btConn”→“连接”,客户端连接服务端。
public static JTextArea textArea = new JTextArea(5,10);
private static JScrollPane scrollPane;
private static JLabel labelIP = new JLabel("IP:");
private static JTextField textIP = new JTextField("127.0.0.1",10);
private static JLabel labelPort = new JLabel("端口号:");
private static JTextField textPort = new JTextField("8088",10);
public static JButton btConn = new JButton("连接");
(12)新建launch方法
主要写入各个元素的属性(文本格式、按钮点击事件等等)。
点击查看代码
void launch(){
this.setVisible(true);
this.setSize(500,500);
this.setLocationRelativeTo(null);//窗口位置:居中
this.setTitle("黄金矿工联机版(client)");
this.setResizable(false);
setLayout(null);//设置布局
setDefaultCloseOperation(EXIT_ON_CLOSE);
//textArea.setOpaque(false);//透明
textArea.setForeground(Color.black);
textArea.setBackground(Color.white);
textArea.setFont(new Font("幼圆",Font.BOLD,15));
textArea.setEnabled(false);//只读
textArea.setBounds(0,0,500,200);
scrollPane = new JScrollPane(textArea);
scrollPane.setBounds(0,0,500,200);
//"IP:"
labelIP.setFont(new Font("幼圆",Font.PLAIN,15));
labelIP.setBounds(145,250,100,20);
//输入IP地址的文本框
textIP.setFont(new Font("幼圆",Font.PLAIN,15));
textIP.setBounds(238,250,100,20);
//“端口:”
labelPort.setFont(new Font("幼圆",Font.PLAIN,15));
labelPort.setBounds(145,300,100,20);
//输入端口号的文本框
textPort.setFont(new Font("幼圆",Font.PLAIN,15));
textPort.setBounds(238,300,100,20);
//连接按钮
btConn.setFont(new Font("幼圆",Font.PLAIN,15));
btConn.setBounds(200,350,100,30);
btConn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//TODO:点击“btOpen”按钮后运行这里
//比如“ 123 ”,加了.trim就会得到“123”
publicMeans.ip = textIP.getText().trim();//获取输入的IP,就是textIP里面的 .trim()的意思是删除文本框里面内容前后的空格
publicMeans.port = Integer.parseInt(textPort.getText().trim());//因为port是int类型,所以要使用Integer.parseInt把string转为int
}
});
this.add(scrollPane);
this.add(labelIP);
this.add(textIP);
this.add(labelPort);
this.add(textPort);
this.add(btConn);
}
(13)创建线程类ClientThread
主要用来新建接收和发送信息的相关变量(is,isr,br,info,os,pw),然后接收并解析来自服务端的信息。
点击查看代码
public class ClientThread extends Thread{//创建客户端线程
private Socket socket;
public ClientThread(Socket socket){this.socket = socket;}
//接收来自服务端信息的相关变量
public InputStream is = null;
public InputStreamReader isr = null;
public BufferedReader br = null;
private static String info = null, infoAll = null;
//向服务端发送信息的相关变量
public OutputStream os = null;
public PrintWriter pw = null;
@Override
public void run() {//线程开始,自动运行
try{
socket = new Socket(publicMeans.ip,publicMeans.port);//服务端的ip地址和端口号 这里的ip和port也就是刚才文本框里输入的
publicMeans.isServer = false;//如果成功进入到这一步,则代表此窗口是客户端窗口
publicMeans.isConn = true;//连接成功
Client.textArea.append("连接成功。\r\n");//"\r\n"的意思是换行
Client.btConn.setEnabled(false);//禁用客户端的连接按钮
os = socket.getOutputStream();
pw = new PrintWriter(os);
is = socket.getInputStream();
isr = new InputStreamReader(is);
br = new BufferedReader(isr);//这里就是客户端接收的地方
while(true){//这里使用死循环,是因为要一直监视服务端有没有发过来信息
//刚才在服务端里面,开始游戏的时候服务端向客户端发送了“开始游戏”,这里解析
while((info = br.readLine()) != null){
//TODO:解析服务端发过来的内容
}
}//跟服务端一个意思
}catch (Exception e){
e.printStackTrace();
}
}
(14)在Client类中建立客户端
private static Socket socket;
private static ClientThread thread;
public static void BuildClient(){//创建客户端
try{
thread = new ClientThread(socket);//跟刚才一样,创建一个客户端线程
thread.start();
}catch (Exception e){}
}
(15)调用建立客户端的方法
在launch方法中的btConn按钮的点击事件中引用建立客户端的方法(BuildClient)。
btConn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//比如“ 123 ”,加了.trim就会得到“123”
publicMeans.ip = textIP.getText().trim();//获取输入的IP,就是textIP里面的 .trim()的意思是删除文本框里面内容前后的空格
publicMeans.port = Integer.parseInt(textPort.getText().trim());//因为port是int类型,所以要使用Integer.parseInt把string转为int
BuildClient();//点击连接按钮后,去创建客户端
}
});
(16)在Client类中建立发送信息的方法
//客户发送信息时引用
public static void Send(String message){
thread.pw.write(message + "\r\n");
thread.pw.flush();
}
(17)在main方法中调用launch方法
第(10)步的main。
public static void main(String[] args){//这个main是程序入口,就是点击运行,程序从这里开始跑
Client client = new Client();
client.launch();
}
3.游戏界面实现
//TODO:
标签:Java,textArea,static,new,黄金矿工,public,服务端,客户端 From: https://www.cnblogs.com/xbxxx/p/18207095