龟兔赛跑(基于GUI与多线程实现)

直击龟兔赛跑现场

下面这张图是我们设计龟兔赛跑界面的初始效果与基本组成结构:

接下来是我仅代表我个人提出的一些疑问与解答:

1、俩动物以图片的形式显示?

其实在这里两个动物类就像标签一样

标签组件是什么?用于短文本字符串或图片显示固定提示信息。

下面给出这个初始界面的代码与效果图:

java 复制代码
class Race extends JFrame{
    JPanel p;
    private JButton b=new JButton("开始");//开始按钮
    private JLabel stateOfRabbit=new JLabel("乌龟和兔子的比赛现场");//显示比赛/兔子状态
    private JLabel rabbit =new JLabel(new ImageIcon("images/rabbit.jpg"));//兔子
    private JLabel tortoise =new JLabel(new ImageIcon("images/tortoise.jpg"));//乌龟

    public Race(){
        super("龟兔赛跑");//标题
        p=new JPanel(null);
        b.setBounds(20, 10, 70, 30);
        rabbit.setBounds(20, 100, 150, 166);
        tortoise.setBounds(20, 390, 150, 136);
        stateOfRabbit.setBounds(300, 20, 260, 50);
        stateOfRabbit.setFont(new Font("", Font.BOLD, 22));

        p.add(b);
        p.add(stateOfRabbit);
        p.add(rabbit);
        p.add(tortoise);
        this.add(p);


        this.setBounds(200,150,1000,650);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
}

2、多线程实现俩小动物比赛

在上面的代码中,我们把兔子乌龟都定为标签类,但是俩东西参加比赛,是要同时参与比赛过程的,这里要利用多线程实现,也就是兔子、乌龟这俩标签要在比赛过程中(进程)移动,他俩的行为都属于这个进程(比赛)中的俩线程。

我们知道线程的创建方式有很多种:

  • 继承Thread,重写run()(创建单独的类/匿名内部类)
  • 实现Runnable,重写run()(创建单独的类/匿名内部类)
  • 实现Callable,重写call()(创建单独的类/匿名内部类)
  • 使用lambda表达式
  • 线程工厂 ThreadFactory
  • 线程池 ThreadPoolEcecutor

在GUI的学习中我们知道可以把Rabblt定位一个类,继承JFrame类再改写可以实现我们想要的窗口效果。同样标签类也是这样,可以把Rabbit类继承Jlabel类实现想要的兔子标签。

一个类可以实现多个接口,但只能继承一个父类。这里很明显要么实现Runnable,要么实现Callable接口,那就拿实现Runnable来举例

java 复制代码
class Race extends JFrame{
    ......
    private Rabbit rabbit =new Rabbit(new ImageIcon("images/rabbit.jpg"));//兔子
    private Tortoise tortoise =new Tortoise(new ImageIcon("images/tortoise.jpg"));//乌龟
    .......
    class Rabbit extends JLabel implements Runnable{
        public Rabbit(Icon image) {
            super(image);
        }
        @Override
        public void run() {}
    }

    class Tortoise extends JLabel implements Runnable{
        public Tortoise(Icon image) {
            super(image);
        }
        @Override
        public void run() {}
    }

}

3、兔子和乌龟跑起来?

这里就表示一下俩东西的x方向的位移就行了,窗口里的效果相当于是50米跑一样的。

俩东西一起出发,兔子领先过不了一会就闭了(不动-位移不变),乌龟此时依旧锲而不舍!˃̣̣̥᷄⌓˂̣̣̥᷅ 但是很可惜!兔子居然就睡了4000ms就醒了!难道兔子是外星兔嘛!不过好在我龟也不是太慢!老天不负有心龟,🐢胜利!

利用组件可以在窗口里访问更新位置来实现兔子乌龟的移动效果

java 复制代码
public abstract class Component
    public Point getLocation() {
            return location();
    }
    public void setLocation(int x, int y) {
            move(x, y);
    }
    public void move(int x, int y) {
            synchronized(getTreeLock()) {
                setBoundsOp(ComponentPeer.SET_LOCATION);
                setBounds(x, y, width, height);
            }
    }
}

实现代码如下:

乌龟状态:(一直低俗慢跑)

java 复制代码
 class Tortoise extends JLabel implements Runnable{
        public Tortoise(Icon image) {
            super(image);
        }
        boolean stop;//默认false
        int speed=4;
        int x,y;

        @Override
        public void run() {
            //easy一直低速跑(未停时-未到终点前)
            while (!stop){
                //获取起始坐标
                x=getLocation().x;
                y=getLocation().y;

                //移动-更新坐标
                x+=speed;
                setLocation(x,y);

                //循环一次太快了不符合乌龟龟设,慢点慢点...同时也把cpu给人兔子让一让
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

                if(x>=MAX_LENGTH)
                    stop=true;
            }
        }
    }

兔子状态:(快速跑-睡大觉-快速跑)

java 复制代码
 class Rabbit extends JLabel implements Runnable{
        public Rabbit(Icon image) {
            super(image);
        }

        boolean stop;
        int speed=10;
        int x,y;

        @Override
        public void run() {
            x=getLocation().x;
            y=getLocation().y;

            while (!stop){
                x+=speed;
                setLocation(x,y);

                try {
                    Thread.sleep(500);//彼此彼此你也用您也用用cpu
                    if(x<300)//小白兔全力冲刺!
                        stateOfRabbit.setText("无敌飞毛腿!");
                    //因为等下要大睡4000毫秒,所以直接在这里面写了,就不用在解决一边异常了
                    if(x==300){//兔子此时跑到300px树下->睡大觉->又冲刺!
                        stateOfRabbit.setText("兔子睡大觉!");
                        Thread.sleep(4000);
                        /*
                         * ->(x=300)时更改为 speed=0
                         * ->x+=0(x=300)->slepp(50)->speed=10;setText(兔子惊讶..)
                        */
                        if(speed==0){
                            speed=10;
                            stateOfRabbit.setText("兔子惊讶!全力冲刺吧!");
                        }else {
                            speed=0;
                        }
                    }

                    if (x>=MAX_LENGTH){
                        stateOfRabbit.setText("啊?乌龟赢了?哈哈哈哈啊哈哈哈");
                        stop=true;
                    }
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

            }

        }
    }

4、开始按钮-处理事件

java 复制代码
 b.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                new Thread(rabbit).start();
                new Thread(tortoise).start();
                b.setVisible(false);
            }
        });

完整代码见这里这里请点击吧!

文本形式的龟兔赛跑代码请点击

相关推荐
正小安21 分钟前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
2402_8575893622 分钟前
“衣依”服装销售平台:Spring Boot框架的设计与实现
java·spring boot·后端
吾爱星辰1 小时前
Kotlin 处理字符串和正则表达式(二十一)
java·开发语言·jvm·正则表达式·kotlin
哎呦没1 小时前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端
_.Switch2 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光2 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   2 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   2 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
编程、小哥哥2 小时前
netty之Netty与SpringBoot整合
java·spring boot·spring
Fan_web2 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery