当前位置: 首页 > 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.lryc.cn/news/623603.html

相关文章:

  • macos 安装nodepad++ (教程+安装包+报错后的解决方法)
  • Sentinel和12.5米高程的QGIS 3D效果
  • scikit-learn/sklearn学习|套索回归Lasso解读
  • scikit-learn RandomizedSearchCV 使用方法详解
  • scikit-learn 中的均方误差 (MSE) 和 R² 评分指标
  • .NET 中的延迟初始化:Lazy<T> 与LazyInitializer
  • 『搞笑名称生成器』c++小游戏
  • Spring Cloud整合Eureka、ZooKeeper、原理分析
  • 云计算-k8s实战指南:从 ServiceMesh 服务网格、流量管理、limitrange管理、亲和性、环境变量到RBAC管理全流程
  • 【Kubernetes系列】Kubernetes中的resources
  • 脉冲计数实现
  • vue3 ref和reactive的区别和使用场景
  • Nightingale源码Linux进行跨平台编译
  • 数学建模 15 逻辑回归与随机森林
  • 大模型微调【2】之使用AutoDL进行模型微调入门
  • 工具测试 - marker (Convert PDF to markdown + JSON quickly with high accuracy)
  • 深入理解 uni-app 页面导航:switchTab、navigateTo、redirectTo、reLaunch 与 navigateBack
  • 回溯剪枝的 “减法艺术”:化解超时危机的 “救命稻草”(一)
  • 基于径向基函数神经网络的数据回归预测 RBF
  • 【Jenkins】02 - 自动化部署配置
  • Matlab数字图像处理——梯度稀疏性和泊松方程求解的反光/倒影去除系统
  • C#中List、Path、字符串操作等常用方法总结
  • Git登录配置的详细方法
  • Python入门第7课:异常处理机制:让你的程序更健壮(try-except详解)
  • uniapp中uni.showToast和 uni.showLoading同时使用时出现提示中断冲突问题。
  • 《告别 if-else 迷宫:Python 策略模式 (Strategy Pattern) 的优雅之道》
  • 【Tech Arch】Hive技术解析:大数据仓库的SQL桥梁
  • 在 Element UI 的 el-table 中实现某行标红并显示删除线
  • Java 大视界 -- 基于 Java 的大数据分布式计算在气象灾害预警与应急响应中的应用
  • 图论水题4