在Java游戏中实现声音

Posted

技术标签:

【中文标题】在Java游戏中实现声音【英文标题】:implementing sound into a java game 【发布时间】:2013-07-18 18:29:46 【问题描述】:

我一直关注 Buckys java 游戏开发,并使用 slick 进行游戏的基本设置,从那时起我就将其掌握在自己手中。目前我只是在构建菜单,它几乎完成了,除了我想给它添加声音。我已经坚持了一个星期,所以它不像我没有为此做过任何研究,我只是无法让它发挥作用。现在我找到了一些代码来执行此操作,这似乎很有意义,我该如何实现它,或者如果您对如何添加一些声音有更好的想法,不胜感激。

import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.Audiosystem;
import javax.sound.sampled.Clip;

static String soundtrack = "res/doxx.wav";

public void sound(String path)

    try
        AudioInputStream audio = AudioSystem.getAudioInputStream(Menu.class.getResource(path));
        Clip clip = AudioSystem.getClip();
        clip.open(audio);
        clip.start();
     catch (Exception e)
        System.out.println("check "+path+"\n");
        e.printStackTrace();
    

编辑:此代码现已从程序中删除,但请随时根据它发布答案

到目前为止,这是与添加声音相关的代码,这是我的菜单类的全部内容,它不是很大。老实说,您可能不需要详细查看它,它目前完全基于图形和两个正在旋转的按钮(开始和退出)。

package javagame;

import org.lwjgl.input.Mouse;
import org.newdawn.slick.*;
import org.newdawn.slick.state.*;


public class Menu extends BasicGameState 

double pi=3.14159265359;
float beanPosY = 330;
float beanPosX = 70;
double gravity = 0.01;
double angleStart=1.5*pi;
double angleQuit=0.5*pi;
int radius=120;
int centerX=300;
int centerY=160;
float startPosX = (float) (centerX + Math.sin(angleStart)*radius);
float startPosY = (float) (centerY + Math.cos(angleStart)*radius);
float quitPosX = (float) (centerX + Math.sin(angleQuit)*radius);
float quitPosY = (float) (centerY + Math.cos(angleQuit)*radius);
double force = 0;
public Menu(int state)


public void init(GameContainer gc, StateBasedGame sbg) throws SlickException
    Sound music = new Sound();
    music.playBackGround("res/doxx.wav");


public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException     
    Image background = new Image("res/background640x480.fw.png");
    g.drawImage(background, 0, 0);

    Image start = new Image("res/Start100x100.fw.png");
    Image quit = new Image("res/quit100x100.fw.png");
    start.draw(startPosX,startPosY);
    quit.draw(quitPosX,quitPosY);

    Image grass = new Image("res/grass640x150.fw.png");
    g.drawImage(grass,0,340);

    Image bean = new Image("res/bean.jpg");
    bean.draw(beanPosX, beanPosY);


public void update(GameContainer gc, StateBasedGame sbg, int delta) throws SlickException
    int posX = Mouse.getX();
    int posY = Mouse.getY();
    double constant=0.002*pi;

    startPosX = (float) (centerX + Math.sin(angleStart)*radius);
    startPosY = (float) (centerY + Math.cos(angleStart)*radius);
    quitPosX = (float) (centerX + Math.sin(angleQuit)*radius);
    quitPosY = (float) (centerY + Math.cos(angleQuit)*radius);

    angleStart+=constant;
    angleQuit+=constant;
    if (angleStart>=2*pi)
        angleStart-=2*pi;
    
    if (angleQuit>=2*pi)
        angleQuit-=2*pi;
    
    //button interactions
    menuInteraction(posX,posY,sbg);


    if (beanPosY>=330)
        force=1;
    
    beanPosY-=force;
    force-=gravity;


public int getID()
    return 0;


private void menuInteraction(int posX, int posY, StateBasedGame sbg)
    //play button
    float startXDist=posX-(startPosX+50);
    float startYDist=(480-posY)-(startPosY+50);
    float startDist=(float) Math.sqrt((startXDist*startXDist)+(startYDist*startYDist));
    if(startDist<=50)
        if(Mouse.isButtonDown(0))
            sbg.enterState(1);
        
    

    //quit button
    float quitXDist=posX-(quitPosX+50);
    float quitYDist=(480-posY)-(quitPosY+50);
    float quitDist=(float) Math.sqrt((quitXDist*quitXDist)+(quitYDist*quitYDist));
    if(quitDist<=50)
        if(Mouse.isButtonDown(0))
            System.exit(0);
        
    

edit:上面的代码现在在“init()”方法中创建了一个对象,该方法调用“Sound”类及其方法“playBackGround()”。 Sound 类的代码在下面来自 JavaNewb 的答案中给出。

edit:这段代码产生的错误如下:

java.lang.NullPointerException
at com.sun.media.sound.StandardMidiFileReader.getSequence(Unknown Source)
at javax.sound.midi.MidiSystem.getSequence(Unknown Source)
at com.sun.media.sound.SoftMidiAudioFileReader.getAudioInputStream(Unknown Source)
at javax.sound.sampled.AudioSystem.getAudioInputStream(Unknown Source)
at javagame.Sound.run(Sound.java:45)
at java.lang.Thread.run(Unknown Source)

最后一点,我已经尝试过诸如 LWJGL 库之类的东西,但我无法理解它们。我也意识到我要问多少,因为我基本上是在要求有人将其编码到我的游戏中,我希望我不必这样做,但我不知道如何解决我的问题而不将其发布在这里.

PS。这不是我自己没有尝试过,所以不要痛苦,说我没有努力

【问题讨论】:

是否有任何错误异常或声音不播放? 如果您认真对待游戏开发,那么您应该寻找合适的框架/库来为您处理低级内容(例如播放声音)。一旦找到适合您需求的框架,您就可以专注于实际创建游戏,而不是重新发明***。 这真的取决于你想要做什么以及你所针对的平台。我将libgdx 用于android 游戏(尽管它 跨平台的)。以libgdx为例,框架不需要我put much effort into playing sounds。 我不是想成为一个“痛苦的人”,我当然不会指责你“不努力”,但我强烈建议你从一些介绍性的 Java 开始材料,例如 Deitel 的 Java How to Program,这样您就可以更好地理解您正在查看的代码,以及一般的面向对象编程的基础知识。要真正回答您的问题,您已经创建了一个将播放声音剪辑的方法,但您实际上并没有在初始化或呈现菜单期间的任何地方调用该方法。您需要调用它才能真正执行。 除了@LJ2 的好建议之外,当您遇到问题时,创建最简单的案例来测试您的代码也是一种好习惯。在这种情况下,您可以创建一个仅在运行时播放声音的简单程序,这样您就可以在尝试找出问题所在之前进行测试以确保它在简单的情况下工作。更大的情况。 (不过,LJ2 已经发现了你的问题——你永远不会调用 sound 方法。) 【参考方案1】:
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;

public class Sound implements Runnable

    private boolean running = false;
    private Thread thread;

    public Sound()
    
        this.start();
    

    public void start()
    
        if(running)
            return;
        this.thread = new Thread(this);
        this.running = true;
        this.thread.start();
    

    //
    private boolean playSong = false;
    private AudioInputStream inputStream;
    private String url;
    private Clip clip;

    @Override
    public void run()
    
        while(running)
        
            if(inputStream == null && playSong)
            
                this.playSong = false;
                try
                
                    this.inputStream = AudioSystem.getAudioInputStream(Sound.class.getResource(url));
                    this.clip.open(inputStream);
                    this.clip.loop(10);
                
                catch(Exception e)
                
                    e.printStackTrace();
                
            
        
    

    public void playBackGround(String string) // call to play .wav file
    
        if(this.clip != null)
        
            this.clip.stop();
            this.clip.close();
        
        try
        
            this.clip = AudioSystem.getClip();
        
        catch(LineUnavailableException e)
        
            e.printStackTrace();
        
        url = string + ".wav";
        this.playSong = true;
        this.inputStream = null;
    

    public void disposeSound()
    
        if(this.clip != null)
        
            this.clip.stop();
            this.clip.close();
        
        this.clip = null;
        this.playSong = false;
        this.inputStream = null;
    

【讨论】:

感谢您的回复,我已经编辑了我的代码以实现您给我的内容并将其放入原始问题中。恐怕不会产生声音,运行时不会产生错误,但是 IDE 在检查我的代码的 cmets 中引用的错误时会发现一些事情 对的问题是你的类需要实现 Runnable... public class Sound 实现 Runnable 上面的代码是一个独立于你的类的类。只需在 main 中创建此类的一个实例并调用“playBackGround”方法 为了清楚起见,您需要创建一个新的 java 类文件并将上面的代码复制到其中。 我明白了,谢谢 :) 不过我还是有一些问题,请编辑我的问题【参考方案2】:

当您尝试从空 URL 创建 AudioInputStream 时会发生此错误。确保 url 不为空,确保引用正确的文件。

【讨论】:

以上是关于在Java游戏中实现声音的主要内容,如果未能解决你的问题,请参考以下文章

Java中的声音问题

教你在“狼人杀”中实现变声效果

教你在“狼人杀”中实现变声效果

教你在“狼人杀”中实现变声效果

在 Java 中实现 BFS

java中的声音 - 播放声音时游戏冻结