Java课程实践飞机大战swing GUI利用多线程实现背景音乐播放暂停(个人学习记录留档)

Java课程实践飞机大战swing GUI利用多线程实现背景音乐播放暂停(个人学习记录留档),第1张

目标

(1)使用 Java Swing 类库完成飞机大战游戏中的难度选择、音效开关界面。
(2)使用 Java Swing 类库完成得分排行榜界面,显示该难度的玩家得分排名。 并可与玩家进行交互,输入玩家姓名后可记录该局得分,并可删除任一玩家的历史得分。
(3)使用 Runnable 接口实现多线程,完善火力道具功能。
(4)继承 Thread 类实现多线程,完成游戏背景音乐、子d击中敌机、炸d爆炸、 道具生效、Boss 机出场、游戏结束时的音效控制。

原理 Swing GUI

用ide的自带的图形界面编程:
例如:
新建窗口

其中form是一个基于XML的文件,这么设计的目的是为了摆脱复杂的Swing代码,intelliJ编译器会透明地自动生成必要的代码来创建和布局所有的控件。

给按钮或其他什么组件添加监听器:

图例中添加的是ActionListener,用于接收 *** 作事件的侦听器接口。对处理 *** 作事件感兴趣的类可以实现此接口,而使用该类创建的对象可使用组件的 addActionListener 方法向该组件注册。在发生 *** 作事件时,调用该对象的 actionPerformed 方法。

多线程

业务逻辑:

实现 实现图形窗口

以第一个窗口为例:

对应类:

public class AircraftWarStartFrame {
    private JFrame frame;
    private JPanel StartPanel;
    private JButton easyButton;
    private JButton hardButton;
    private JButton normalButton;
    private JComboBox musicComboBox;
    private JLabel musicLabel;
    private static Object locker = Main.locker;
    private String gameDegree;
    private boolean isStop = false;

    public AircraftWarStartFrame() {

        frame = new JFrame("AircraftWar");
        frame.setSize(400,600);
        frame.setLocationRelativeTo(null);
        frame.setContentPane(this.StartPanel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);

        easyButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                synchronized (locker){
                    try{
                        gameDegree = "Easy";
                        locker.notify();

                        frame.dispose();
                    }catch (Exception e1){
                        e1.printStackTrace();
                    }
                }
            }
        });
        normalButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                synchronized (locker){
                    try{
                        gameDegree = "Normal";
                        locker.notify();

                        frame.dispose();
                    }catch (Exception e1){
                        e1.printStackTrace();
                    }
                }
            }
        });
        hardButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                synchronized (locker){
                    try{
                        gameDegree = "Hard";
                        locker.notify();

                        frame.dispose();
                    }catch (Exception e1){
                        e1.printStackTrace();
                    }
                }
            }
        });
        musicComboBox.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if(musicComboBox.getSelectedItem().equals("关")){
                    Main.bgmMusicThread.setStop(true);
                    isStop = true;
                }
                else{
                    Main.bgmMusicThread.setStop(false);
                    isStop = false;
                }
            }
        });
    }

    /**
     * 选择游戏难度
     * @return 游戏实例
     */
    public Game startGame(){
        Game game;
        switch (gameDegree){
            case "Easy":
                game=new EasyGame();
                break;
            case "Normal":
                game=new NormalGame();
                break;
            case "Hard":
                game=new HardGame();
                break;
            default:
                game=new EasyGame();
        }
        game.isStop=isStop;
        return game;
    }

}
实现背景音乐的暂停播放

播放音频线程:

public class MusicThread extends Thread {
    
    //音频文件名
    private String videos;
    private AudioFormat audioFormat;
    private byte[] samples;

    //播放/停止标志
    private boolean isStop = false;
    //循环播放标志
    private boolean inLoop = false;
    //借宿播放标志
    private boolean toEnd = false;


    public MusicThread(String filename,boolean isStop,boolean inLoop) {
        //初始化filename
        this.videos = filename;
        this.isStop = isStop;
        this.inLoop = inLoop;
        reverseMusic();
    }

    public void reverseMusic() {
        try {
            //定义一个AudioInputStream用于接收输入的音频数据,使用AudioSystem来获取音频的音频输入流
            AudioInputStream stream = AudioSystem.getAudioInputStream(new File(videos));
            //用AudioFormat来获取AudioInputStream的格式
            audioFormat = stream.getFormat();
            samples = getSamples(stream);
        } catch (UnsupportedAudioFileException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public byte[] getSamples(AudioInputStream stream) {
        int size = (int) (stream.getFrameLength() * audioFormat.getFrameSize());
        byte[] samples = new byte[size];
        DataInputStream dataInputStream = new DataInputStream(stream);
        try {
            dataInputStream.readFully(samples);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return samples;
    }

    public void play(InputStream source) {
        int size = (int) (audioFormat.getFrameSize() * audioFormat.getSampleRate());
        byte[] buffer = new byte[size];
        //源数据行SoureDataLine是可以写入数据的数据行
        SourceDataLine dataLine = null;
        //获取受数据行支持的音频格式DataLine.info
        DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
        try {
            dataLine = (SourceDataLine) AudioSystem.getLine(info);
            dataLine.open(audioFormat, size);
        } catch (LineUnavailableException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        dataLine.start();
        try {
            int numBytesRead = 0;
            while (numBytesRead != -1) {
                //结束
                if(toEnd){
                    break;
                }
                //暂停
                if(isStop){
                    while (isStop){
                        try {
                            Thread.sleep(1000);
                        }catch (InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                }
				//从音频流读取指定的最大数量的数据字节,并将其放入缓冲区中
                numBytesRead =
                        source.read(buffer, 0, buffer.length);
				//通过此源数据行将数据写入混频器
                if (numBytesRead != -1) {
                    dataLine.write(buffer, 0, numBytesRead);
                }
            }

        } catch (IOException ex) {
            ex.printStackTrace();
        }

        dataLine.drain();
        dataLine.close();

    }


    /**
     * 设置音效打开/关闭
     */
    public void setStop(boolean isStop){this.isStop=isStop;}

    /**
     * 设置循环播放
     */
    public void setInLoop(boolean inLoop){this.inLoop = inLoop;}

    /**
     * 结束播放
     */
    public void setToEnd(boolean toEnd){this.toEnd = toEnd;}

    /**
     * 控制音频循环播放
     */
    @Override
    public void run() {
        if(inLoop){
            while (inLoop){
                InputStream stream = new ByteArrayInputStream(samples);
                play(stream);
            }
        }
        InputStream stream = new ByteArrayInputStream(samples);
        play(stream);
    }

}
新建音效线程

以子d击中音效为例

new MusicThread("src/videos/bullet_hit.wav",isStop,false).start();
其他

JTable 的设置:
利用model来导入数据

	/**
     * 设置表格
     */
    public void setTable(){
        //显示难度
        degreeLabel.setText("难度:"+userDao.degree);

        DefaultTableModel model = new DefaultTableModel();
        String[] columnName = {"排 名","名 称","分 数","达成时间"};
        model.setColumnIdentifiers(columnName);
        List<User> users = userDao.getAllUsers();
        int index = 1;
        for(User user : users){
            Vector row = new Vector(4);
            row.add(0,Integer.toString(index));
            row.add(1,user.getUserName());
            row.add(2,Integer.toString(user.getScore()));
            row.add(3,user.getTime());
            index++;
            model.addRow(row);
        }

        scoreTable.setModel(model);
        tableScrollPane.setViewportView(scoreTable);
    }

线程相关方法总结

总结

重点是理清业务逻辑,实际实现代码没有用到多少技术

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/786162.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-05
下一篇 2022-05-05

发表评论

登录后才能评论

评论列表(0条)

保存