时间延迟和JInput

时间:2010-01-31 00:17:13

标签: java jinput

好的,我不知道如何说出这个问题,但也许我的代码会说明问题:

public class ControllerTest
{
    public static void main(String [] args)
    {
        GamePadController rockbandDrum = new GamePadController();
        DrumMachine drum = new DrumMachine();

        while(true)
        {
            try{

            rockbandDrum.poll();

            if(rockbandDrum.isButtonPressed(1)) //BLUE PAD HhiHat)
            {
                drum.playSound("hiHat.wav");
                Thread.sleep(50);
            }

            if(rockbandDrum.isButtonPressed(2)) //GREEN PAD (Crash)
            {
                //Todo: Change to Crash
                drum.playSound("hiHat.wav");
                Thread.sleep(50);
            }
            //Etc....
         }
     }
}

public class DrumMachine
{
    InputStream soundPlayer = null;
    AudioStream audio = null;
    static boolean running = true;

    public void playSound(String soundFile)
    {
        //Tak a sound file as a paramater and then
        //play that sound file
        try{
            soundPlayer = new FileInputStream(soundFile);
            audio = new AudioStream(soundPlayer);

        }
        catch(FileNotFoundException e){
            e.printStackTrace();
        }
        catch(IOException e){
            e.printStackTrace();
        }

        AudioPlayer.player.start(audio);
    }
    //Etc... Methods for multiple audio clip playing
}

现在的问题是,如果我降低

中的延迟
Thread.sleep(50)

然后声音每秒播放多次,但如果我保持在这个级别或更高级别,我可能会错过播放的声音......

这是一个奇怪的问题,如果延迟太低,声音会循环。但是如果它太高则会错过播放声音。这只是我需要调整设置的问题,还是有其他方法来轮询控制器而没有循环声音?

编辑:如果我需要发布用于轮询控制器的代码,我会......

import java.io.*;
import net.java.games.input.*;
import net.java.games.input.Component.POV;


public class GamePadController
{
    public static final int NUM_BUTTONS = 13;

    // public stick and hat compass positions
    public static final int NUM_COMPASS_DIRS = 9;

    public static final int NW = 0;
    public static final int NORTH = 1;
    public static final int NE = 2;
    public static final int WEST = 3;
    public static final int NONE = 4;   // default value
    public static final int EAST = 5;
    public static final int SW = 6;
    public static final int SOUTH = 7;
    public static final int SE = 8;

    private Controller controller;

    private Component[] comps;  // holds the components

    // comps[] indices for specific components
    private int xAxisIdx, yAxisIdx, zAxisIdx, rzAxisIdx;
                                // indices for the analog sticks axes
    private int povIdx;         // index for the POV hat
    private int buttonsIdx[];   // indices for the buttons

    private Rumbler[] rumblers;
    private int rumblerIdx;      // index for the rumbler being used
    private boolean rumblerOn = false;   // whether rumbler is on or off

    public GamePadController()
    {
        // get the controllers
        ControllerEnvironment ce =
             ControllerEnvironment.getDefaultEnvironment();
        Controller[] cs = ce.getControllers();
        if (cs.length == 0) {
          System.out.println("No controllers found");
          System.exit(0);
        }
        else
          System.out.println("Num. controllers: " + cs.length);


        // get the game pad controller
        controller = findGamePad(cs);
        System.out.println("Game controller: " +
                           controller.getName() + ", " +
                           controller.getType());

        // collect indices for the required game pad components
        findCompIndices(controller);

        findRumblers(controller);
    } // end of GamePadController()


    private Controller findGamePad(Controller[] cs)
    /* Search the array of controllers until a suitable game pad
       controller is found (eith of type GAMEPAD or STICK).
    */
    {
        Controller.Type type;
        int i = 0;
        while(i < cs.length) {
            type = cs[i].getType();
            if ((type == Controller.Type.GAMEPAD) ||
                (type == Controller.Type.STICK))
                break;
            i++;
        }

        if (i == cs.length) {
            System.out.println("No game pad found");
            System.exit(0);
        }
        else
            System.out.println("Game pad index: " + i);

        return cs[i];
    }  // end of findGamePad()


    private void findCompIndices(Controller controller)
    /* Store the indices for the analog sticks axes
       (x,y) and (z,rz), POV hat, and
       button components of the controller.
    */
    {
        comps = controller.getComponents();
        if (comps.length == 0) {
            System.out.println("No Components found");
            System.exit(0);
        }
        else
            System.out.println("Num. Components: " + comps.length);

        // get the indices for the axes of the analog sticks: (x,y) and (z,rz)
        xAxisIdx = findCompIndex(comps, Component.Identifier.Axis.X, "x-axis");
        yAxisIdx = findCompIndex(comps, Component.Identifier.Axis.Y, "y-axis");

        zAxisIdx = findCompIndex(comps, Component.Identifier.Axis.Z, "z-axis");
        rzAxisIdx = findCompIndex(comps, Component.Identifier.Axis.RZ, "rz-axis");

        // get POV hat index
        povIdx = findCompIndex(comps, Component.Identifier.Axis.POV, "POV hat");

        findButtons(comps);
    }  // end of findCompIndices()


    private int findCompIndex(Component[] comps,
                           Component.Identifier id, String nm)
    /* Search through comps[] for id, returning the corresponding
       array index, or -1 */
    {
        Component c;
        for(int i=0; i < comps.length; i++) {
            c = comps[i];
            if ((c.getIdentifier() == id) && !c.isRelative()) {
                System.out.println("Found " + c.getName() + "; index: " + i);
                return i;
            }
        }

        System.out.println("No " + nm + " component found");
        return -1;
    }  // end of findCompIndex()


    private void findButtons(Component[] comps)
    /* Search through comps[] for NUM_BUTTONS buttons, storing
       their indices in buttonsIdx[]. Ignore excessive buttons.
       If there aren't enough buttons, then fill the empty spots in
       buttonsIdx[] with -1's. */
    {
        buttonsIdx = new int[NUM_BUTTONS];
        int numButtons = 0;
        Component c;

        for(int i=0; i < comps.length; i++) {
            c = comps[i];
            if (isButton(c)) {    // deal with a button
                if (numButtons == NUM_BUTTONS)   // already enough buttons
                    System.out.println("Found an extra button; index: " + i + ". Ignoring it");
                else {
                    buttonsIdx[numButtons] = i;  // store button index
                    System.out.println("Found " + c.getName() + "; index: " + i);
                    numButtons++;
                }
            }
        }

        // fill empty spots in buttonsIdx[] with -1's
        if (numButtons < NUM_BUTTONS) {
            System.out.println("Too few buttons (" + numButtons +
                               "); expecting " + NUM_BUTTONS);
            while (numButtons < NUM_BUTTONS) {
                buttonsIdx[numButtons] = -1;
                numButtons++;
            }
        }
    }  // end of findButtons()


    private boolean isButton(Component c)
    /* Return true if the component is a digital/absolute button, and
       its identifier name ends with "Button" (i.e. the
       identifier class is Component.Identifier.Button).
    */
    {
        if (!c.isAnalog() && !c.isRelative()) {    // digital and absolute
            String className = c.getIdentifier().getClass().getName();
            // System.out.println(c.getName() + " identifier: " + className);
            if (className.endsWith("Button"))
                return true;
        }
        return false;
    }  // end of isButton()


    private void findRumblers(Controller controller)
    /* Find the rumblers. Use the last rumbler for making vibrations,
       an arbitrary decision. */
    {
        // get the game pad's rumblers
        rumblers = controller.getRumblers();
        if (rumblers.length == 0) {
            System.out.println("No Rumblers found");
            rumblerIdx = -1;
        }
        else {
            System.out.println("Rumblers found: " + rumblers.length);
            rumblerIdx = rumblers.length-1;    // use last rumbler
        }
    }  // end of findRumblers()


    // ----------------- polling and getting data ------------------


    public void poll()
    // update the component values in the controller
    {
        controller.poll();
    }


    public int getXYStickDir()
    // return the (x,y) analog stick compass direction
    {
      if ((xAxisIdx == -1) || (yAxisIdx == -1)) {
          System.out.println("(x,y) axis data unavailable");
          return NONE;
      }
      else
         return getCompassDir(xAxisIdx, yAxisIdx);
    } // end of getXYStickDir()


    public int getZRZStickDir()
    // return the (z,rz) analog stick compass direction
    {
        if ((zAxisIdx == -1) || (rzAxisIdx == -1)) {
            System.out.println("(z,rz) axis data unavailable");
            return NONE;
        }
        else
            return getCompassDir(zAxisIdx, rzAxisIdx);
    } // end of getXYStickDir()


    private int getCompassDir(int xA, int yA)
    // Return the axes as a single compass value
    {
        float xCoord = comps[ xA ].getPollData();
        float yCoord = comps[ yA ].getPollData();
        // System.out.println("(x,y): (" + xCoord + "," + yCoord + ")");

        int xc = Math.round(xCoord);
        int yc = Math.round(yCoord);
        // System.out.println("Rounded (x,y): (" + xc + "," + yc + ")");

        if ((yc == -1) && (xc == -1))   // (y,x)
            return NW;
        else if ((yc == -1) && (xc == 0))
            return NORTH;
        else if ((yc == -1) && (xc == 1))
            return NE;
        else if ((yc == 0) && (xc == -1))
            return WEST;
        else if ((yc == 0) && (xc == 0))
            return NONE;
        else if ((yc == 0) && (xc == 1))
            return EAST;
        else if ((yc == 1) && (xc == -1))
            return SW;
        else if ((yc == 1) && (xc == 0))
            return SOUTH;
        else if ((yc == 1) && (xc == 1))
            return SE;
        else {
            System.out.println("Unknown (x,y): (" + xc + "," + yc + ")");
            return NONE;
        }
    }  // end of getCompassDir()

    public int getHatDir()
    // Return the POV hat's direction as a compass direction
    {
        if (povIdx == -1) {
            System.out.println("POV hat data unavailable");
            return NONE;
        }
        else {
            float povDir = comps[povIdx].getPollData();
            if (povDir == POV.CENTER)  //   0.0f
                return NONE;
            else if (povDir == POV.DOWN)  // 0.75f
                return SOUTH;
            else if (povDir == POV.DOWN_LEFT)  // 0.875f
                return SW;
            else if (povDir == POV.DOWN_RIGHT)  // 0.625f
                return SE;
            else if (povDir == POV.LEFT)  // 1.0f
                return WEST;
            else if (povDir == POV.RIGHT)  // 0.5f
                return EAST;
            else if (povDir == POV.UP)  // 0.25f
                return NORTH;
            else if (povDir == POV.UP_LEFT)  // 0.125f
                return NW;
            else if (povDir == POV.UP_RIGHT)  // 0.375f
                return NE;
            else  { // assume center
                System.out.println("POV hat value out of range: " + povDir);
                return NONE;
            }
        }
    }  // end of getHatDir()


    public boolean[] getButtons()
    /* Return all the buttons in a single array. Each button value is
       a boolean. */
    {
        boolean[] buttons = new boolean[NUM_BUTTONS];
        float value;
        for(int i=0; i < NUM_BUTTONS; i++) {
            value = comps[ buttonsIdx[i] ].getPollData();
            buttons[i] = ((value == 0.0f) ? false : true);
        }
        return buttons;
    }  // end of getButtons()


    public boolean isButtonPressed(int pos)
    /* Return the button value (a boolean) for button number 'pos'.
       pos is in the range 1-NUM_BUTTONS to match the game pad
       button labels.
    */
    {
      if ((pos < 1) || (pos > NUM_BUTTONS)) {
          System.out.println("Button position out of range (1-" +
                              NUM_BUTTONS + "): " + pos);
          return false;
      }

      if (buttonsIdx[pos-1] == -1)   // no button found at that pos
          return false;

      float value = comps[ buttonsIdx[pos-1] ].getPollData();
         // array range is 0-NUM_BUTTONS-1

      return ((value == 0.0f) ? false : true);
    } // end of isButtonPressed()


    // ------------------- Trigger a rumbler -------------------

    public void setRumbler(boolean switchOn)
    // turn the rumbler on or off
    {
        if (rumblerIdx != -1) {
            if (switchOn)
                rumblers[rumblerIdx].rumble(0.8f);  // almost full on for last rumbler
            else  // switch off
                rumblers[rumblerIdx].rumble(0.0f);
            rumblerOn = switchOn;    // record rumbler's new status
        }
    }  // end of setRumbler()

    public boolean isRumblerOn()
    {  return rumblerOn;  }

} // end of GamePadController class

3 个答案:

答案 0 :(得分:3)

我认为你在这里使用了错误的设计模式。你应该使用observer pattern来做这类事情。

轮询循环效率不高,正如您所注意到的那样,并没有真正产生预期效果。

我不确定你在对象中使用了什么来检测是否按下了某个键,但是如果它是一个GUI架构,例如SwingAWT,它将基于观察者模式通过使用EventListeners等

答案 1 :(得分:1)

这是一个(略微简化的)观察者模式 适用于你的情况。

这种设计的优点是当一个按钮 按下并按住,方法'buttonChanged'将 仍然只被召唤一次,而不是开始 每50毫秒'重复一次'。

  public static final int BUTTON_01 = 0x00000001;
  public static final int BUTTON_02 = 0x00000002;
  public static final int BUTTON_03 = 0x00000004;
  public static final int BUTTON_04 = 0x00000008; // hex 8  == dec 8  
  public static final int BUTTON_05 = 0x00000010; // hex 10 == dec 16
  public static final int BUTTON_06 = 0x00000020; // hex 20 == dec 32
  public static final int BUTTON_07 = 0x00000040; // hex 40 == dec 64
  public static final int BUTTON_08 = 0x00000080; // etc.
  public static final int BUTTON_09 = 0x00000100;
  public static final int BUTTON_10 = 0x00000200;
  public static final int BUTTON_11 = 0x00000400;
  public static final int BUTTON_12 = 0x00000800;

  private int previousButtons = 0;

  void poll()
  {         
    rockbandDrum.poll();
    handleButtons();
  }

  private void handleButtons()
  {
    boolean[] buttons  = getButtons();
    int pressedButtons = getPressedButtons(buttons);    
    if (pressedButtons != previousButtons)
    {         
      buttonChanged(pressedButtons); // Notify 'listener'.
      previousButtons = pressedButtons;
    }   
  }

  public boolean[] getButtons()
  {   
    // Return all the buttons in a single array. Each button-value is a boolean.

    boolean[] buttons = new boolean[MAX_NUMBER_OF_BUTTONS];
    float value;
    for (int i = 0; i < MAX_NUMBER_OF_BUTTONS-1; i++)
    {
      int index = buttonsIndex[i];
      if (index < 0) { continue; }

      value = comps[index].getPollData();
      buttons[i] = ((value == 0.0f) ? false : true);
    }
    return buttons;
  }

  private int getPressedButtons(boolean[] array)
  {      
    // Mold all pressed buttons into a single number by OR-ing their values.

    int pressedButtons = 0;    
    int i = 1;
    for (boolean isBbuttonPressed : array)
    {
      if (isBbuttonPressed) { pressedButtons |= getOrValue(i); }
      i++;
    }    
    return pressedButtons;    
  }

  private int getOrValue(int btnNumber) // Get a value to 'OR' with.
  {
    int btnValue = 0;    
    switch (btnNumber)
    {
      case 1  : btnValue = BUTTON_01; break;
      case 2  : btnValue = BUTTON_02; break;
      case 3  : btnValue = BUTTON_03; break;
      case 4  : btnValue = BUTTON_04; break;
      case 5  : btnValue = BUTTON_05; break;
      case 6  : btnValue = BUTTON_06; break;
      case 7  : btnValue = BUTTON_07; break;
      case 8  : btnValue = BUTTON_08; break;
      case 9  : btnValue = BUTTON_09; break;
      case 10 : btnValue = BUTTON_10; break;
      case 11 : btnValue = BUTTON_11; break;
      case 12 : btnValue = BUTTON_12; break;
      default : assert false : "Invalid button-number";
    }
    return btnValue;
  }

  public static boolean checkButton(int pressedButtons, int buttonToCheckFor)
  {
    return (pressedButtons & buttonToCheckFor) == buttonToCheckFor;
  }   

  public void buttonChanged(int buttons)
  {
    if (checkButton(buttons, BUTTON_01)
    {
      drum.playSound("hiHat.wav");
    }

    if (checkButton(buttons, BUTTON_02)
    {
      drum.playSound("crash.wav");
    }
  }

答案 2 :(得分:0)

请发布有关您正在使用的GamePadController课程的更多信息。

很可能,同一个库将提供一个“事件”API,一旦用户按下按钮,就会调用您向游戏手柄对象注册的“回调”。使用这种设置,“轮询”循环在框架中,而不是您的应用程序,并且它可以更高效,因为它使用来自硬件的信号而不是忙等待轮询循环。


好的,我查看了JInput API,它实际上不是事件驱动的;你必须像你一样轮询它。释放按钮时声音是否会停止循环?如果是这样,你的目标是让声音只播放一次,而不是再次释放并按下按钮之前?在这种情况下,您需要每次循环时跟踪上一个按钮状态。

人体反应时间约为250毫秒(对于像我这样的老家伙,无论如何)。如果你每50毫秒轮询一次,我希望控制器报告按下按钮几次循环。你能尝试这样的事吗:

boolean played = false;
while (true) {
  String sound = null;
  if (controller.isButtonPressed(1)) 
    sound = "hiHat.wav";
  if (controller.isButtonPressed(2)) 
    sound = "crash.wav";
  if (sound != null) {
    if (!played) {
      drum.playSound(sound);
      played = true;
    }
  } else {
    played = false;
  }
  Thread.sleep(50);
}