当前位置: 首页 > news >正文

多线程—飞机大战(加入播放音乐功能版本)

读者须知:

飞机大战基本功能代码在项目历程专栏中,这里仅展示播放音乐功能如何添加

实现效果:

代码实现:

(一)导入第三方包/库:

在这里插入图片描述

这里面具有Player类播放器,可以播放mp3文件,解决了java默认仅支持wav格式文件的问题。

当然如果想要获取wav格式文件也可以,那就下载一个Adobe Audiority软件,在里面转换MP3文件,就可以获得wav格式。

(二)创建FileMusic类储存音乐文件(MP3格式)

package DemoProject.fjm0601;import java.io.File;public class FileMusic {static File fileBack = new File("D:\\CloudMusic\\MP3\\William Black,Linney - Higher Now.mp3");}

(三)创建音乐线程类

3.1 获取音乐线程
3.2 停止音乐线程
package DemoProject.fjm0601;import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.Player;import javax.sound.sampled.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;public class ThreadMusic {static Player playerBack ;static Thread thBack;public static SourceDataLine line;public static Thread getPlayBkTh(File fileBack){try {FileInputStream fsBack = new FileInputStream(fileBack);playerBack = new Player(fsBack);thBack = new Thread() {public void run() {try {playerBack.play();} catch (JavaLayerException e) {throw new RuntimeException(e);}}};return thBack;} catch (FileNotFoundException e) {throw new RuntimeException(e);} catch (JavaLayerException e) {throw new RuntimeException(e);}}public static void stopBk(){playerBack.close();}}

将player对象变为静态以跨类调用

(四)在GameWD类中的paint()方法中,在state == 1 的时候,获取线程并开始播放

播放状态由isPlay控制(一开始默认false),当运行到isPlay == false,则播放,并改值为true。

public void paint(Graphics g){BaseBoard=createImage(getWidth(),getHeight());//creatImage()这个方法返回的是VolatileImage对象或者是未初始化的Image,很有可能会丢失,所以这不稳定Graphics gImage=BaseBoard.getGraphics();if(state==0){gImage.drawImage(DemoProject.fjm0601.GameWDUtils.bgObj,0,0,null);paint0(gImage,this);}else if(state==1){if(isPlay == false){
*                thBack.start();System.out.println("此处可再次运行");isPlay = true;}objectList.removeAll(removeList);removeList.clear();objectList.addAll(addList);addList.clear();for(GameObj object:objectList){object.paintSelf(gImage);}gImage.setColor(Color.CYAN);gImage.setFont(new Font("幼圆",Font.BOLD,20));gImage.drawString("获得分数"+" "+Score,30,70);}g.drawImage(BaseBoard,0,0,null);}

(五)在GameWD的paint2()方法中,改isPlay为false,并销毁线程,停止播放。然后再次创建播放线程,以备“点击重新开始游戏”后能再度播放。

public static void paint2(GameWD gm){isPlay = false;//线程在这里死亡,无法重生(start)thBack.interrupt();//仅仅使用interrupted是无法使用阻断player的play方法的,因为play听不见interrupted方法。ThreadMusic.stopBk();thBack = new Thread() {public void run() {try {ThreadMusic.playerBack = new Player(new FileInputStream(FileMusic.fileBack));ThreadMusic.playerBack.play();//player关闭后不可重置和线程一样都只有一次生命} catch (JavaLayerException e) {throw new RuntimeException(e);} catch (FileNotFoundException e) {throw new RuntimeException(e);}}};Graphics gImage = gm.getGraphics();gImage.setColor(Color.BLACK);gImage.fillRect(0,0,gm.getWidth(),gm.getHeight());gImage.setColor(Color.RED);gImage.setFont(new Font("幼圆",Font.BOLD,40));gImage.drawString("Game Over",200,200);gImage.setColor(Color.CYAN);gImage.drawString("查看排行榜",200,580);//创建文本输入框和确定按钮JTextField jtf = new JTextField();gImage.setFont(new Font("幼圆",Font.BOLD,40));gImage.setColor(Color.WHITE);//drawString的y是字符的底部y坐标gImage.drawString("请点击下方,输入您的姓名",50,400);//JTextField的y是文本输入框顶部的y坐标jtf.setBounds(150,400,300,25);JButton confirmBtn = new JButton("确定");confirmBtn.setBounds(240,435,100,40);confirmBtn.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {String name = jtf.getText();try {writeFile(name,Score);} catch (IOException ex) {throw new RuntimeException(ex);}}});gm.add(jtf);gm.add(confirmBtn);JFrame[] jFrame = new JFrame[1];int[] currentTimes = {0};int[] previousTimes = {0};gm.addMouseListener(new MouseAdapter() {@Overridepublic void mouseClicked(MouseEvent e) {super.mouseClicked(e);int x = e.getX();int y = e.getY();createRankJf(x,y,currentTimes,previousTimes, jFrame);}});//创建查看排行榜图片://gImage.drawImage(GameWDUtils.RankObj,200,480, null);}

问:为什么不将创建线程这个行为封装成一个方法?
答:因为创建方法后,将旧的变量名传入,并且赋入新值,原先的引用并不会修改为指向新的内存地址。因为引用传参是修改不了原先的引用的。
解决方法:将void方法修改为具有返回值的方法,在方法里修改引用后返回,就可以获得新的且与原来变量名一致的线程了

至此,可以实现音乐的适时播放

http://www.dtcms.com/a/336487.html

相关文章:

  • 【Virtual Globe 渲染技术笔记】6 着色
  • C语言---第一个C语言程序
  • Tomcat下载、安装及配置详细教程
  • Hybrid Beamforming Design for OFDM Dual-Function Radar-Communication System
  • LaTeX中表示实数集R的方法
  • 零基础搭建公网 Nginx:通过 cpolar 内网穿透服务实现远程访问
  • 朝花夕拾(四) --------python中的os库全指南
  • 【计算机数学】关于全概率和贝叶斯公式的使用场景说明
  • Linux目录相关的命令
  • 排列组合+数量+资料
  • 聊聊Vuex vs Pinia
  • MySQL执行计划解读
  • 人脸AI半球梯控/门禁读头的功能参数与技术实现方案
  • 网络常识-DNS如何解析
  • 集成运算放大器(反向加法,减法)
  • Linux Shell定时检查日期执行Python脚本
  • 【AIGC】DDPM scheduler解析:扩散模型里的“调度器”到底在调什么?
  • 线程的同步
  • 魔改chromium源码——解除 iframe 的同源策略
  • Go语言实战案例-使用ORM框架 GORM 入门
  • 0️⃣基础 认识Python操作文件夹(初学者)
  • E2B是一个开源基础设施,允许您在云中安全隔离的沙盒中运行AI生成的代码和e2b.dev网站
  • 基因编辑预测工具:inDelphi与Pythia
  • Linux学习记录
  • 图解简单选择排序C语言实现
  • 01数据结构-插入排序
  • 一文读懂[特殊字符] LlamaFactory 中 Loss 曲线图
  • 防火墙带宽管理
  • 使用 Python 的 `cProfile` 分析函数执行时间
  • AUTOSAR进阶图解==>AUTOSAR_SWS_EthernetStateManager