当前位置: 首页 > 知识库问答 >
问题:

Java键盘输入-游戏开发

皮嘉德
2023-03-14
private class KeyControl implements KeyListener {

    private int dx = 20;

    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
            if(dx < 0 )
                dx = -dx;
            gamePanel.movePlatform(dx);
        }

        if(e.getKeyCode() == KeyEvent.VK_LEFT) {
            if(dx > 0 )
                dx = -dx;
            gamePanel.movePlatform(dx);
        }

        if(e.getKeyCode() == KeyEvent.VK_SPACE) {
            System.out.println("space");
            gamePanel.play();
        }

        if(e.getKeyCode() == KeyEvent.VK_ESCAPE) {
            gamePanel.pause();
        }

    }
}
public void movePlatform(int dx) {
        int nextDX = dx;

        if(paused || init) {
            dx = 0;
        }

        // make sure platform doesnt exceed right border
        if(platform.getX() + platform.getWidth()  + dx> size.getWidth()) {
            if(nextDX < 0)
                dx = nextDX;
            else
                dx = 0;
        }

        // make sure platform doesnt exceed left border
        if(platform.getX() + dx <= 0) {
            if(nextDX > 0)
                dx = nextDX;
            else
                dx = 0;
        }

        platform.setFrame(platform.getX() + dx, platform.getY(), platform.getWidth(), platform.getHeight());
        platformIntervalX = new Interval((int)platform.getX(), (int)(platform.getX() + platform.getWidth()));
        platformIntervalY = new Interval((int)(platform.getY() - platform.getHeight()), (int)platform.getY());
        repaint();
    }

共有1个答案

广晔
2023-03-14

解决办法是不要使用KeyListener的按键来移动精灵。关键不是依赖于硬件特定的按键频率,而是使用Swing计时器来创建自己的频率。取而代之的是使用键绑定和Swing计时器。按下键开始时间,释放键停止时间。

例如,运行以下代码并按下并释放向上箭头键:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.*;

@SuppressWarnings("serial")
public class KeyBindingEg extends JPanel {
   private static final String UP_KEY_PRESSED = "up key pressed";
   private static final String UP_KEY_RELEASED = "up key released";
   private static final int UP_TIMER_DELAY = 50;
   private static final Color FLASH_COLOR = Color.red;

   private Timer upTimer;
   private JLabel label = new JLabel();

   public KeyBindingEg() {
      label.setFont(label.getFont().deriveFont(Font.BOLD, 32));
      label.setOpaque(true);
      add(label);

      setPreferredSize(new Dimension(400, 300));

      int condition = WHEN_IN_FOCUSED_WINDOW;
      InputMap inputMap = getInputMap(condition);
      ActionMap actionMap = getActionMap();
      KeyStroke upKeyPressed = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false);
      KeyStroke upKeyReleased = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true);

      inputMap.put(upKeyPressed, UP_KEY_PRESSED);
      inputMap.put(upKeyReleased, UP_KEY_RELEASED);

      actionMap.put(UP_KEY_PRESSED, new UpAction(false));
      actionMap.put(UP_KEY_RELEASED, new UpAction(true));

   }

   private class UpAction extends AbstractAction {
      private boolean onKeyRelease;

      public UpAction(boolean onKeyRelease) {
         this.onKeyRelease = onKeyRelease;
      }

      @Override
      public void actionPerformed(ActionEvent evt) {
         if (!onKeyRelease) {
            if (upTimer != null && upTimer.isRunning()) {
               return;
            }
            System.out.println("key pressed");
            label.setText(UP_KEY_PRESSED);

            upTimer = new Timer(UP_TIMER_DELAY, new ActionListener() {

               @Override
               public void actionPerformed(ActionEvent e) {
                  Color c = label.getBackground();
                  if (FLASH_COLOR.equals(c)) {
                     label.setBackground(null);
                     label.setForeground(Color.black);
                  } else {
                     label.setBackground(FLASH_COLOR);
                     label.setForeground(Color.white);
                  }
               }
            });
            upTimer.start();
         } else {
            System.out.println("Key released");
            if (upTimer != null && upTimer.isRunning()) {
               upTimer.stop();
               upTimer = null;
            }
            label.setText("");
         }
      }

   }

   private static void createAndShowGui() {
      KeyBindingEg mainPanel = new KeyBindingEg();

      JFrame frame = new JFrame("KeyBindingEg");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

编辑

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.util.EnumMap;
import java.util.Map;

import javax.swing.*;

@SuppressWarnings("serial")
public class KeyBindingEg2 extends JPanel {
   enum Dir {
      LEFT("Left", KeyEvent.VK_LEFT, -1, 0),
      RIGHT("Right", KeyEvent.VK_RIGHT, 1, 0),
      UP("Up", KeyEvent.VK_UP, 0, -1),
      DOWN("Down", KeyEvent.VK_DOWN, 0, 1);

      private String name;
      private int keyCode;
      private int deltaX;
      private int deltaY;
      private Dir(String name, int keyCode, int deltaX, int deltaY) {
         this.name = name;
         this.keyCode = keyCode;
         this.deltaX = deltaX;
         this.deltaY = deltaY;
      }
      public String getName() {
         return name;
      }
      public int getKeyCode() {
         return keyCode;
      }
      public int getDeltaX() {
         return deltaX;
      }
      public int getDeltaY() {
         return deltaY;
      }      
   }
   public static final int TIMER_DELAY = 10;
   public static final int DELTA_X = 2;
   public static final int DELTA_Y = DELTA_X;
   public static final int SPRITE_WIDTH = 10;
   public static final int SPRITE_HEIGHT = SPRITE_WIDTH;
   private static final String PRESSED = "pressed";
   private static final String RELEASED = "released";
   private static final int PREF_W = 800;
   private static final int PREF_H = 650;
   private Map<Dir, Boolean> dirMap = new EnumMap<>(Dir.class);
   private int spriteX = 0;
   private int spriteY = 0;
   private BufferedImage sprite;
   private Timer animationTimer = new Timer(TIMER_DELAY, new AnimationListener());

   public KeyBindingEg2() {
      for (Dir dir : Dir.values()) {
         dirMap.put(dir, Boolean.FALSE);
      }
      sprite = createSprite();
      setKeyBindings();
      animationTimer.start();
   }

   private BufferedImage createSprite() {
      BufferedImage sprt = new BufferedImage(SPRITE_WIDTH, SPRITE_HEIGHT, BufferedImage.TYPE_INT_ARGB);
      Graphics g = sprt.getGraphics();
      g.setColor(Color.RED);
      g.fillRect(0, 0, SPRITE_WIDTH, SPRITE_HEIGHT);
      g.dispose();
      return sprt;
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (sprite != null) {
         g.drawImage(sprite, spriteX, spriteY, this);
      }
   }

   private void setKeyBindings() {
      int condition = WHEN_IN_FOCUSED_WINDOW;
      InputMap inputMap = getInputMap(condition);
      ActionMap actionMap = getActionMap();

      for (Dir dir : Dir.values()) {
         KeyStroke keyPressed = KeyStroke.getKeyStroke(dir.getKeyCode(), 0, false);
         KeyStroke keyReleased = KeyStroke.getKeyStroke(dir.getKeyCode(), 0, true);

         inputMap.put(keyPressed, dir.toString() + PRESSED);
         inputMap.put(keyReleased, dir.toString() + RELEASED);

         actionMap.put(dir.toString() + PRESSED, new DirAction(dir, PRESSED));
         actionMap.put(dir.toString() + RELEASED, new DirAction(dir, RELEASED));
      }

   }

   private class AnimationListener implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         int newX = spriteX;
         int newY = spriteY;
         for (Dir dir : Dir.values()) {
            if (dirMap.get(dir)) {
               newX += dir.getDeltaX() * DELTA_X;
               newY += dir.getDeltaY() * DELTA_Y;
            }
         }
         if (newX < 0 || newY < 0) {
            return;
         }
         if (newX + SPRITE_WIDTH > getWidth() || newY + SPRITE_HEIGHT > getHeight()) {
            return;
         }
         spriteX = newX;
         spriteY = newY;
         repaint();         
      }
   }

   private class DirAction extends AbstractAction {

      private String pressedOrReleased;
      private Dir dir;

      public DirAction(Dir dir, String pressedOrReleased) {
         this.dir = dir;
         this.pressedOrReleased = pressedOrReleased;
      }

      @Override
      public void actionPerformed(ActionEvent evt) {
         if (pressedOrReleased.equals(PRESSED)) {
            dirMap.put(dir, Boolean.TRUE);
         } else if (pressedOrReleased.equals(RELEASED)) {
            dirMap.put(dir, Boolean.FALSE);
         }
      }

   }

   private static void createAndShowGui() {
      KeyBindingEg2 mainPanel = new KeyBindingEg2();

      JFrame frame = new JFrame("KeyBindingEg");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}
 类似资料:
  • 问题内容: 我正在用Java编写游戏,现在是Swing + JOGL-一个带有GLCanvas的JFrame。 我使用etc.事件()处理输入,但似乎无法正常工作: 当我同时按下3个以上的键时,它们无法正确注册 -显然这是键盘的错误,我必须找到替代的控制方案。 窗口丢失后,重新获得焦点,输入完全停止工作… 我究竟做错了什么? 有没有更好的方法来处理Java中的键盘输入? (除非我别无选择,否则我不

  • 问题内容: 我已经用Java设计了自己的合成器,现在我想将其与Midi键盘连接。我在下面的课程搜索所有带有发射器的Midi设备。它成功找到了我的Midi键盘。我将自己的接收器添加到每个设备的每个发送器中,以便它可以接收所有可能的信息。通过阅读所有帮助文档和Java文档,我知道Transmitter将MidiEvents发送给Receiver,然后由Receiver使用send方法处理它们。因此,我

  • 本文向大家介绍Java游戏开发拼图游戏经典版,包括了Java游戏开发拼图游戏经典版的使用技巧和注意事项,需要的朋友参考一下 游戏介绍: 拼图游戏是一款经典的益智游戏,游戏难度分为 简单、正常、困难 三种难度,分别对应3*3,4*4,5*5布局,游戏开始前图片被随机打乱,空块位于最右下角,玩家通过点击空块周围图片或者按键方式对图片和空块进行相互交换,直到所有图片都回到原位即为游戏胜利。 本次制作的拼

  • 问题内容: 我正在使用Java swing使用计算器,并且希望能够通过键盘输入数字和操作。我似乎无法正常工作。 问题答案: 我认为这是问题所在: 从JComponent.getInputMap() javadoc: 返回组件具有焦点时使用的。这是的便捷方法。 因此,按钮必须具有焦点才能正常工作。由于您正在使用计算器,因此建议您改用以下方法: JComponent.getInputMap(int c

  • 8.3.1 键盘输入的中断功能 键盘输入是绝大多数程序的主要输入方式,学习和掌握有关键盘输入中断的使用方法对编写交互式程序是非常重要的,也能更进一步理解计算机是如何接受键盘输入的。 1、键盘缓冲区 键盘缓冲区是一个先进先出的环形队列,其所占内存区域如下: KBHead DW ? ;其内存地址为0000:041AH,缓冲区头指针 KBTail DW ? ;其内存地址为0000:041CH,缓冲区尾指

  • 全球理念:假设我想做一个游戏/电影/剪辑。为此,我需要这个(不)简单的动画得到工作。 这个问题的一个例子:我得到了类Screen,它有JFrame的Screen Stuff声明,设置它的配置(大小、关闭操作等),然后创建类Box的对象,显示在框架上。请检查这个类的图像/图表(希望我写的是正确的):ClassesDiagram 现在,class Box扩展了JPanel。我从JPanel继承了方法P