用J2se做游戏音乐时的问题

hnd201031000407 2012-04-20 03:17:29
我做一个坦克大战小游戏,用javax.sound.sampled.Clip 类来播放音乐。背景音乐用Clip.loop()来播放。而坦克那些需要重复播放的炮声用Clip.start()来播放。这些都放在一个自己做的audio类里。坦克每产生一个开炮的信号,我就new一个audio类的对象,并放在一个容器里面,然后游戏重画方法里面不停地检测是否容器里面有音乐,有的话就播放出来。这样子效果很好,但是问题是每播放一个音乐就要new一个audio的对象,这会产生很多很多的对象。要是音乐一播放完就Clip.close()的话内存基本不会有太大的提升,但是我的问题是,如果一播放完就Clip.close()的话游戏就会间歇地卡顿,我猜想应该是一次性释放太多的对象,触发jvm的主垃圾收集器,而主垃圾收集会让其他进程暂停,因此出现了卡顿。而如果我不一播放完就Clip.close()的话,我会新建一个线程来专门做Clip.close()这个动作,每close完一次就sleep一段时间。这样子不让一次性有过多的对象被废弃。解决了卡顿的问题,但是内存却会一直增加,因为同一时间新建的audio类对象比释放的audio类对象多。以上便是问题所在,恳请各位出手相助!万分感谢!

下面是audio类的代码

public class Audio {
MyPanel panel;
javax.sound.sampled.Clip clip1;
java.io.File f;
boolean life = true;
//取得播放时的系统时间,以便达到预定播放时间之后采取其他操作
long start = System.currentTimeMillis();
Clip clip;
AudioInputStream inputStream;

Audio(String file, MyPanel panel) {
this.f = new java.io.File(file);
this.panel = panel;
try {
inputStream = javax.sound.sampled.AudioSystem
.getAudioInputStream(this.f);
clip = javax.sound.sampled.AudioSystem.getClip();
} catch (UnsupportedAudioFileException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (LineUnavailableException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

public void play() {

try {

clip.open(inputStream);
clip.start();

inputStream.close();
inputStream = null;

} catch (Exception e) {
e.printStackTrace();
}

}

public void loop(String file) {// 循环播放

try {
javax.sound.sampled.AudioInputStream inputStream = javax.sound.sampled.AudioSystem
.getAudioInputStream(new java.io.File(file));
clip1 = javax.sound.sampled.AudioSystem.getClip();
clip1.open(inputStream);
clip1.loop(Clip.LOOP_CONTINUOUSLY);
} catch (Exception e) {
e.printStackTrace();
}

}
...全文
199 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
lqjack 2012-04-24
  • 打赏
  • 举报
回复
组件一个资源池,在资源池中调用
cseu 2012-04-23
  • 打赏
  • 举报
回复
start只会播放一次,可以用loop(1)替换播放多次。不过由于你开炮密集的原因,为了达到并发播放,可以先把声音file读入byte[]中缓存起来,然后每次开炮时去重新播放。

//sample code for file to byte[]
InputStream input = null;
try {
input = new FileInputStream("C:\\Windows\\Media\\tada.wav");
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int n = 0;
while ((n = input.read(buffer)) != -1) {
output.write(buffer, 0, n);
}
wavBytes = output.toByteArray();//wavBytes is a cached byte[]
} catch (IOException e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//code for fire
AudioInputStream in = AudioSystem.getAudioInputStream(new ByteArrayInputStream(wavBytes));
Clip clip = AudioSystem.getClip();
clip.open(in);
clip.start();
hnd201031000407 2012-04-23
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 的回复:]

把不同的音乐做成不同的clip对象,缓存在Audio中,播放方法做成静态方法.
放背景音乐就直接调用Audio.playBG(),里面调用bgClip.loop(-1)循环播放
开炮就调用Audio.playFire(),里面调用fireClip.start(),播放一次.
[/Quote]
你这个方法我试过,行不通。因为clip如果只new过一次那么就只能播放一次,播完再start是没声音的。
除非再setFramePosition设置回到一开始的位置。但是这样子的话就有一个问题,因为开炮很密集,所以上一个声音还没播放完,这边又调用他了,那边没播完这里再setFramePosition回到起点肯定行不通。
cseu 2012-04-20
  • 打赏
  • 举报
回复
把不同的音乐做成不同的clip对象,缓存在Audio中,播放方法做成静态方法.
放背景音乐就直接调用Audio.playBG(),里面调用bgClip.loop(-1)循环播放
开炮就调用Audio.playFire(),里面调用fireClip.start(),播放一次.

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧