Java多线程初使用3——飞机大战V0版本——ArrayList

Java多线程初使用3——飞机大战V0版本——ArrayList

上篇文章我们使用了双缓冲技术进行了画笔优化,今天我们仍然使用双缓冲,但是对线程部分进行优化——使用ArrayList实现线程的存放。

一、GameUI界面

二、创建飞机类

三、本次监听器画图思路——ArrayList

四、DrawThread画buffimg

五、DrawImageThread死循环线程

六、效果展示

一、GameUI界面

public class GameUI extends JFrame {

    public void initUI(){

        setTitle("飞机大战V0");
        setSize(800,600);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setResizable(false);
        setVisible(true);

        // 流式布局
        setLayout(new FlowLayout());
        // 添加按钮
        Button btn = new Button("start");
        add(btn);

        Graphics g = getGraphics();
        // 按钮监听器
        GameListener gl = new GameListener(g);
        btn.addActionListener(gl);
    }

    public static void main(String[] args) {
        new GameUI().initUI();
    }
}

二、创建飞机类

先不急着创建按钮监听器,毕竟我们很熟悉流程了。

public class Fly {
    protected int x,y; // 出现位置
    protected int speedx,speedy;// 速度
    protected int type; // 判断是敌机还是我机
    protected ImageIcon imageIcon; // 图标
    protected Image image;// 图标转成图片
}

创建我方飞机和敌方飞机类,很明显可以继承Fly(继承也能很好解决ArrayList的冲突问题,继承后无论是Enemy还是Our均不会冲突)。

public class Our extends Fly{
    public Our(int x,int y) {
        this.x = x;
        this.y = y;
        this.type = 0;
        this.imageIcon = new ImageIcon("src\\xw_Class\\xw_18Class_Thread_PlainV0\\Our.png");
        this.image = imageIcon.getImage();
    }
}
public class Enemy extends Fly{
    Random random = new Random();

    public Enemy(int x,int y) {
        this.x = x;
        this.y = y;
        this.type = 1;
        this.imageIcon = new ImageIcon("src\\xw_Class\\xw_18Class_Thread_PlainV0\\Enemy.png");
        this.image = imageIcon.getImage();
        this.speedx = random.nextInt(40)-20;
        this.speedy = random.nextInt(40)-20;
    }
}

ImageIconImage类的使用大家要注意,用getImage()即可获取ImageIcon。

这里两种飞机的图片大家可以自行上网查找,博主的图片是这样子的。

我方飞机:
在这里插入图片描述

敌方飞机:
在这里插入图片描述

三、本次监听器画图思路——ArrayList

这次我们不再像之前那样一次性创建多个线程,而是先把对象存放到ArrayList中,让线程类每隔固定时间取出一个对象进行画图,这样可以优化线程。

public class GameListener implements ActionListener {
    Graphics g;
    BufferedImage buffimg;
    Graphics bg;
    DrawImageThread dit;// 后续实现,为之前的while(true)死循环线程类,用于画buffimg
    DrawThread dt;// 后续实现,为向buffimg画图的线程类,将向buffimg画图与飞机类分离开来。
    // 使用ArrayList存放对象,后续让线程每隔一定时间取出对象,达到线程优化的目的
    ArrayList<Fly> array = new ArrayList<>();
    Random random = new Random();

    public GameListener(Graphics g) {
        this.g = g;
        array.add(new Our(350,400));// 初识添加一个我方飞机
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (buffimg == null){
            buffimg = new BufferedImage(800,600,2);
        }
        if(bg == null){
            bg = buffimg.getGraphics();
        }
        int x = random.nextInt(800);
        int y = random.nextInt(200);
        Enemy enemy = new Enemy(x,y); // 点击添加一个敌方飞机入队列
        this.array.add(enemy);

        if (dt == null){
            dt = new DrawThread(bg,array); // 画进buffimg
            dt.start();
        }

        if(dit == null){
            dit = new DrawImageThread(g,buffimg);// 将buffimg画出
            dit.start();
        }

    }
}

四、DrawThread画buffimg

public class DrawThread extends Thread{
    Graphics g;
    ArrayList<Fly> array = new ArrayList<>();// 所有类共享一个ArrayList

    public DrawThread(Graphics g, ArrayList<Fly> array) {
        this.g = g;// Gamelistener将buffimg的画笔传过来
        this.array = array;
    }

    @Override
    public void run() {
        for(;;){
            for (int i = 0; i < array.size(); i++) {
                Fly f = array.get(i);
                // 取出来的是敌机还是我机?
                if(f.type == 1) {// 敌机
                    f.x += f.speedx;
                    f.y += f.speedy;
                    g.drawImage(f.image, f.x, f.y,50,50, null);
                }
                if(f.type == 0){// 我机
                    g.drawImage(f.image, f.x, f.y,50,50,  null);
                }
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            g.setColor(new Color(238,238,238));
            g.fillRect(0,0,800,600);
        }
    }
}

五、DrawImageThread死循环线程

public class DrawImageThread extends Thread{
    Graphics g;
    BufferedImage buffimg;

    public DrawImageThread(Graphics g, BufferedImage buffimg) {
        this.g = g;// GameListener将窗体画笔传过来,用于将buffimg呈现
        this.buffimg = buffimg;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(30);
            } catch (InterruptedException interruptedException) {
                interruptedException.printStackTrace();
            }

            g.drawImage(buffimg,0,0,null);
        }
    }
}

六、效果展示

在这里插入图片描述

怎么样,是不是稍微有点像了,之后我们将继续完善项目。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Neko1145

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值