首页 > 编程语言 >Java-黄金矿工(一)

Java-黄金矿工(一)

时间:2024-05-22 21:20:21浏览次数:23  
标签:Java textArea static new 黄金矿工 public 服务端 客户端

目录

编辑器: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登录背景图未添加入程序)
imgs

(1)背景图

下面两张图为主要背景,是用ps相对画了一下。
up
down

(2)金块

共3种金块,分别为小金块、中等金块和大金块,金块是在4399上截的图。
smallGold
middleGold
bigGold

(3)矿工

共3种状态,分别为手在上(手在上时,钩子来回摇摆,等待下钩)、手在下(手在下时,钩子释放,去抓取金块)、手上下动(表示正在往上拉,钩子回收中),这个也是在4399上截的图。
minerState1
minerState2
minerState3

(4)钩子

即粉色小球。
hookBall

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

相关文章

  • 2024年最新java(高级)面试题
    1.创建对象的几种方式使用new关键字:使用new关键字可以在堆内存中创建一个新的对象。通过反射机制:通过Java反射机制,可以在运行时动态地获取类的信息并创建对象。这种方式可以通过Class类的newInstance()方法或Constructor类的newInstance()方法来创建对象。Clas......
  • 2024最新Java面试题——java基础
    1.如何理解OOP面向对象编程       在面向对象编程中,程序被组织成一系列互相关联和相互作用的对象,每个对象都有自己的属性和方法。对象之间通过消息传递的方式进行交互,通过定义类和实例化对象来创建具体的对象。       面向对象是一种编程思想,也是一种编程模式,将......
  • 揭秘Java反射:如何轻松获取类的属性及父类属性
    哈喽,大家好,我是木头左!相信很多小伙伴在学习Java的过程中,都曾经遇到过需要动态地获取类的属性和方法的场景。而Java反射正是解决这个问题的利器。那么,如何使用Java反射来获取类的属性及父类的属性呢?一、Java反射简介要了解一下Java反射是什么。简单来说,Java反射就是运行时能够......
  • Java:如何轻松获取当前执行的方法名
    哈喽,大家好,我是木头左!在编程的世界里,经常会遇到各种各样的问题。有时候,需要了解当前执行的方法名,以便更好地调试代码或者记录日志。那么,如何在Java中轻松获取当前执行的方法名呢?本文将为您揭示这个神秘的技巧!一、Java方法的执行上下文在Java中,每个方法都有一个与之关联的执行......
  • Docker openjdk java AES 解密报错
    javaAES解密报错java.security.InvalidKeyException:Illegalkeysizeordefaultparametersatjavax.crypto.Cipher.checkCryptoPerm(Cipher.java:1026)atjavax.crypto.Cipher.implInit(Cipher.java:801)atjavax.crypto.Cipher.chooseProvider(Cipher.java:864)atjavax.c......
  • Java RMI遇到的Connection refused to Host: 127.x.x.x/192.x.x.x/10.x.x.x问题解决方
    问题故障解决记录--JavaRMIConnectionrefusedtohost:x.x.x.x....在学习JavaRMI时,我遇到了以下情况问题原因:可能大家的host是10或者192的私有地址,我估计都是和我一样的一个原因:/etc/hosts文件的配置问题(我是ubuntu系统下的实验环境),也就是主机名称和IP地址的映射关系......
  • 04 Java8新特性
    一函数式编程函数式编程是把动作作为参数对象传给调用的方法。@TestpublicvoidtestAddThen(){List<Integer>list=Arrays.asList(3,1);List<Integer>collect=list.stream()//map的入参是Function类型对象......
  • [ES2024] Improve Application-wide Error Handling rethrowing JavaScript Error wit
    Thenew cause datapropertythatyoucanaddtoathrown Error canbeusedtoretainaccesstotheoriginalerrorcaughtinapromiserejection. constsendLog=(...args)=>console.log(...args);asyncfunctionfetchStuff(){awaitfetch('h......
  • Java实验五: Java多线程程序设计(头歌)
    一、线程接力编写一个应用程序,除了主线程外,还有三个线程:first、second和third。first负责模拟一个红色的按钮从坐标(10,60)运动到(100,60);second负责模拟一个绿色的按钮从坐标(100,60)运动到(200,60)。third线程负责模拟一个蓝色的按钮从坐标(200,60)运动到(300,60)。第一步以下是ideajdk1.8的教......
  • 面向孩子们的-JavaScript-项目-全-
    面向孩子们的JavaScript项目(全)原文:zh.annas-archive.org/md5/9C2A1F6AA0F3566A2BF5430895525455译者:飞龙协议:CCBY-NC-SA4.0前言从书名中您可以猜到,这本书是为孩子们设计和设置的,以便他们可以自学JavaScript,并使用JavaScript创建一些项目。通过以一种无与伦比的方式......