英文:
Playing audio from my Loop a single time without halting the rest of loop
问题
以下是翻译好的内容:
假设我有一个主游戏循环GameLoop。
在这个循环内,我有我的游戏更新。
我正在处理精灵碰撞测试的事件,每次迭代都会进行测试。
如果碰撞为真,则播放音频文件。
问题出在这里:
音频剪辑要么会在游戏冻结时迅速播放,
要么会有延迟地播放,就像我想要的那样,但整个游戏除了音频剪辑外都会停止。
我只是想要一些关于多线程的提示。基本上,据我所知,这将是处理这个问题的最佳方式,但我似乎无法使其正确运行。
注意,我会在主类上扩展线程,但已经扩展了Canvas,这是必需的。
public Main() {
boolean running = true;
while(running) {
// 检查碰撞(返回布尔值)
// 如果为真,则继续执行Entity.doLogic()
// 然后激活AudioClip类的.playAudioClip(this, path)
// 然后播放音频剪辑,一旦播放完毕,它将返回
// 返回并立即再次开始播放
// 同时,循环在我这里冻结了。
}
}
这是实际的Sounds类:
public class Sounds {
public void startSound() {
String path = "path";
playAudioClip(game, path);
}
public void playAudioClip(String path) {
try {
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(new File(path)));
clip.start();
} catch(Exception e) {
System.out.println("加载音频文件时出现问题");
}
try {
Thread.sleep(500);
} catch(Exception ex) {
System.out.println("休眠出现问题");
}
}
}
我已经尝试过下面的方法,情况相同(通过s.start()和s.run()调用它没有区别),使用.start()会在线程中引发错误,我会快速重现并分享:
public class Sounds extends Thread {
@Override
public void run() {
String path = "path";
playAudioClip(game, path);
}
public void playAudioClip(String path) {
try {
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(new File(path)));
clip.start();
} catch(Exception e) {
System.out.println("加载音频文件时出现问题");
}
try {
Thread.sleep(500);
} catch(Exception ex) {
System.out.println("休眠出现问题");
}
}
}
使用.start()只在内部定义run()时抛出“java.lang.IllegalThreadStateException”异常。
自我备注。不要这样做。
错误地使用多线程的典型例子是在任何时候都有243个最大线程同时运行。
英文:
Let's say I've a main GameLoop
Inside this loop I have my Game Updates
I'm handling my Events for Sprite collision testing with each Iteration
If collision is true, play audio file
Here's where the problem occurs
The Audio clip will either play Rapidly, while the game is frozen
or
It will play w/ delay like I want but the entire Game comes to a halt other than the Audio Clip.
I'm just looking for some tips on Threading Basically.
As far as i'm aware it'll be the best way to handle this problem and I can't seem to get it running correctly.
Note I would extend Thread on main class but already extends Canvas, needed.
public Main()
{
boolean running = true;
while(running)
{
// check for collision (returns boolean)
// if true proceed to execute Entity.doLogic()
// this then activates the AudioClip class' .playAudioClip(this, path)
// the audio Clip is then played and once it's done it'll return
// returns and instantly goes back to playing again
// meanwhile the loop Freezes up on me.
}
}
And This is the actual Sound.class
public class Sounds
{
public void startSound()
{
String path = "path";
playAudioClip(game, path);
}
public void playAudioClip(String path)
{
try
{
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(new File(path)));
clip.start();
}
catch(Exception e)
{
System.out.println("Problem loading audio file");
}
try{Thread.sleep(500);}catch(Exception ex){System.out.println("Problem with Sleep");};
}
}
I've tried the below and same situation (Calling it by s.start() and s.run() no difference) using .start() would throw err in thread, will recreate real quick and share)
public class Sounds extends Thread
{
@Override
public void run()
{
String path = "path";
playAudioClip(game, path);
}
public void playAudioClip(String path)
{
try
{
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(new File(path)));
clip.start();
}
catch(Exception e)
{
System.out.println("Problem loading audio file");
}
try{Thread.sleep(500);}catch(Exception ex){System.out.println("Problem with Sleep");};
}
}
throws to console "java.lang.IllegalThreadStateException" invoking with start() only defining run() inside of this object
Multithreading in the wrong way prime example 243 max threads going at any point there
答案1
得分: 0
当Clip
的start()
方法执行时,声音会通过专门为此目的创建的守护线程播放。您无需创建Thread
,也不需要包含Thread.sleep()
命令。只要您的程序在运行,声音就会执行。如果程序在声音仍在播放时停止运行,因为它是守护线程,声音不会完成,而是会随着程序一起停止。
我猜测您的代码可能来自一个唯一任务是播放声音的示例程序。一个更好的示范示例会展示如何在更大的程序环境中管理Clip
。
这里有一个可以尝试的类。我省略了Exception
处理。我使用URL
是因为它允许在程序已编译成jar的情况下获取资源。在文件结构方面,代码假定声音文件位于与您的Sounds
类的位置相对应的子文件夹中。
public class Sounds
{
private Clip clip;
public Sounds(String soundFileName)
{
URL url = this.class.getResource("audio/" + soundFileName);
AudioInputStream ais = AudioSystem.getAudioInputStream(url);
DataLine.Info info = new DataLine.Info(Clip.class, ais.getFormat());
clip = (Clip) AudioSystem.getLine(info);
clip.open(ais);
}
public void playAudioClip()
{
clip.setFramePosition(0);
clip.start();
}
}
Clip
类是为保存在内存中的声音而设计的。如果您不想将声音文件保存在内存中,应该使用SourceDataLine
,因为它启动更快,而且一次只在内存中保存一个缓冲区的数据,而不是整个文件。
因此,我们将Clip
作为实例变量,并在实例化过程中加载和打开它。
命令clip.setFramePosition(0)
的存在是为了每次调用Clip
时,它都会从文件的开头开始播放。有了这个设置,您可以随时调用和播放Clip
。最坏的情况是,如果在调用时正在播放中间,声音会跳回开头重新开始播放。
英文:
When the start()
method of a Clip
executes, the sound is played via a daemon thread created just for that purpose. There is no need for you to create a Thread
and no need to include the Thread.sleep()
command. As long as your program is running, the sound will execute. If your program stops while the sound is still playing, because it's on a daemon, the sound will not finish, but will stop along with the program.
My guess is that your code came from an example program who's only task is to play a sound. A better demo example would have shown how to manage a Clip
in the context of a larger program.
Here is a class to try. I've omitted the Exception
handling. I use URL
because that allows one to get resources even if the program has been compiled into a jar. In terms of file structure, the code assumes that the sound files are in a subfolder relative to the location of your Sounds
class.
public class Sounds
{
private Clip clip;
public Sounds(String soundFileName)
{
URL url = this.class.getResource("audio/" + soundFileName);
AudioInputStream ais = AudioSystem.getAudioInputStream(url);
DataLine.Info info = new DataLine.Info(Clip.class, ais.getFormat());
clip = (Clip) AudioSystem.getLine(info);
clip.open(ais);
}
public void playAudioClip()
{
clip.setFramePosition(0);
clip.start();
}
}
The Clip
class was designed for sounds that are held in memory. If you don't want to hold you sound file in memory, you should use SourceDataLine
, as it will launch more quickly and only holds a buffer's worth of data at a time in memory instead of the entire file.
Thus, we make the Clip
an instance variable, and load and open it as part of the instantiation process.
The command clip.setFramePosition(0)
is there so that any time you call the Clip
, it will start playing from the beginning of the file. With this, you can call and play the Clip
at any time. Worst case scenario, if it is in the middle of playing when you call it, the sound will jump back to the beginning and start anew.
专注分享java语言的经验与见解,让所有开发者获益!
评论