本文介绍了Java的键盘输入 - 游戏开发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个具体的问题有一场比赛,我创建的类。

本场比赛是打破它的实现。要移动在底部我只是用一个关键的侦听器平台。问题是,在第一密钥preSS之后有一个短暂的滞后或口吃平台开始移动之前。我怎么能prevent这得到平滑的响应?有另一种方式比KeyListener的?键绑定?

下面是关键监听器实现

 私有类KeyControl实现的KeyListener {    私人INT DX = 20;    公共无效键pressed(KeyEvent的E){
        如果(e.getKey code()== KeyEvent.VK_RIGHT){
            如果(DX℃,)
                DX = -dx;
            gamePanel.movePlatform(DX);
        }        如果(e.getKey code()== KeyEvent.VK_LEFT){
            如果(DX大于0)
                DX = -dx;
            gamePanel.movePlatform(DX);
        }        如果(e.getKey code()== KeyEvent.VK_SPACE){
            的System.out.println(空间);
            gamePanel.play();
        }        如果(e.getKey code()== KeyEvent.VK_ESCAPE){
            gamePanel.pause();
        }    }
}

和这里是移动平台周围

方法

 公共无效movePlatform(INT DX){
        INT nextDX = DX;        如果(暂停|| INIT){
            DX = 0;
        }        //确保平台犯规超过右边框
        如果(platform.getX()+ platform.getWidth()+ DX> size.getWidth()){
            如果(nextDX℃,)
                DX = nextDX;
            其他
                DX = 0;
        }        //确保平台犯规超过左边框
        如果(platform.getX()+ DX&下; = 0){
            如果(nextDX大于0)
                DX = nextDX;
            其他
                DX = 0;
        }        platform.setFrame(platform.getX()+ DX,platform.getY(),platform.getWidth(),platform.getHeight());
        platformIntervalX =新间隔((int)的platform.getX(),(INT)(platform.getX()+ platform.getWidth()));
        platformIntervalY =新间隔((int)的(platform.getY() - platform.getHeight()),(INT)platform.getY());
        重绘();
    }


解决方案

解决的办法是不使用的KeyListener的主要preSS移动你的精灵。关键是不依赖于特定的硬件键preSS频率,使用一个Swing计时器来创建自己的频率。而是使用按键绑定和Swing的计时器。启动重点preSS的时间和停止它的键释放。

例如,运行此code和preSS并释放向上箭头键:

 进口java.awt.Color中;
进口java.awt.Dimension中;
进口java.awt.Font中;
进口java.awt.event.ActionEvent中;
进口java.awt.event.ActionListener;
进口java.awt.event.KeyEvent中;进口的javax.swing *。@燮pressWarnings(串行)
公共类KeyBindingEg继承JPanel {
   私有静态最后弦乐UP_KEY_ preSSED =向上键pressed
   私有静态最后弦乐UP_KEY_RELEASED =向上键发布了;
   私有静态最终诠释UP_TIMER_DELAY = 50;
   私有静态最终颜色FLASH_COLOR = Color.red;   私人定时器upTimer;
   私人标签的JLabel =新的JLabel();   公共KeyBindingEg(){
      label.setFont(label.getFont()的deriveFont(Font.BOLD,32));
      label.setOpaque(真);
      添加(标签);      集preferredSize(新尺寸(400,300));      INT条件= WHEN_IN_FOCUSED_WINDOW;
      InputMap中的InputMap = getInputMap中(条件);
      ActionMap中的ActionMap = getActionMap();
      的KeyStroke upKey pressed = KeyStroke.getKeyStroke(KeyEvent.VK_UP,0,FALSE);
      的KeyStroke upKeyReleased = KeyStroke.getKeyStroke(KeyEvent.VK_UP,0,真正的);      inputMap.put(upKey pressed,UP_KEY_ preSSED);
      inputMap.put(upKeyReleased,UP_KEY_RELEASED);      actionMap.put(UP_KEY_ preSSED,新UpAction(假));
      actionMap.put(UP_KEY_RELEASED,新UpAction(真));   }   私有类UpAction扩展AbstractAction {
      私人布尔onKeyRelease;      公共UpAction(布尔onKeyRelease){
         this.onKeyRelease = onKeyRelease;
      }      @覆盖
      公共无效的actionPerformed(ActionEvent的EVT){
         如果(!onKeyRelease){
            如果(upTimer =空&放大器;!&放大器; upTimer.isRunning()){
               返回;
            }
            的System.out.println(键pressed);
            label.setText(UP_KEY_ preSSED);            upTimer =新的Timer(UP_TIMER_DELAY,新的ActionListener(){               @覆盖
               公共无效的actionPerformed(ActionEvent的五){
                  颜色C = label.getBackground();
                  如果(FLASH_COLOR.equals(c))的{
                     label.setBackground(NU​​LL);
                     label.setForeground(Color.black);
                  }其他{
                     label.setBackground(FLASH_COLOR);
                     label.setForeground(Color.white);
                  }
               }
            });
            upTimer.start();
         }其他{
            的System.out.println(键释放);
            如果(upTimer =空&放大器;!&放大器; upTimer.isRunning()){
               upTimer.stop();
               upTimer = NULL;
            }
            label.setText();
         }
      }   }   私有静态无效createAndShowGui(){
      KeyBindingEg的mainPanel =新KeyBindingEg();      JFrame的帧=新的JFrame(KeyBindingEg);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane()加(mainPanel中)。
      frame.pack();
      frame.setLocationByPlatform(真);
      frame.setVisible(真);
   }   公共静态无效的主要(字串[] args){
      SwingUtilities.invokeLater(Runnable的新(){
         公共无效的run(){
            createAndShowGui();
         }
      });
   }
}


修改

或者一个更好的例子,一个基于方向键中的一个关键preSS任何方向移动的精灵。无延迟遇到:

 进口java.awt.Color中;
进口java.awt.Dimension中;
进口java.awt.Graphics;
进口java.awt.event.ActionEvent中;
进口java.awt.event.ActionListener;
进口java.awt.event.KeyEvent中;
进口java.awt.image.BufferedImage中;
进口java.util.EnumMap中;
进口的java.util.Map;进口的javax.swing *。@燮pressWarnings(串行)
公共类KeyBindingEg2继承JPanel {
   枚举目录{
      LEFT(左,KeyEvent.VK_LEFT,-1,0),
      RIGHT(右,KeyEvent.VK_RIGHT,1,0),
      向上(向上,KeyEvent.VK_UP,0,-1),
      DOWN(向下,KeyEvent.VK_DOWN,0,1);      私人字符串名称;
      私人诠释键code;
      私人诠释DELTAX;
      私人诠释DELTAY;
      私人目录(字符串名称,诠释关键code,INT DELTAX,诠释DELTAY){
         this.name =名称;
         this.key code =键code;
         this.deltaX = DELTAX;
         this.deltaY = DELTAY;
      }
      公共字符串的getName(){
         返回名称;
      }
      公众诠释getKey code(){
         返回键code;
      }
      公众诠释getDeltaX(){
         返回DELTAX;
      }
      公众诠释getDeltaY(){
         返回DELTAY;
      }
   }
   公共静态最终诠释TIMER_DELAY = 10;
   公共静态最终诠释DELTA_X = 2;
   公共静态最终诠释DELTA_Y = DELTA_X;
   公共静态最终诠释SPRITE_WIDTH = 10;
   公共静态最终诠释SPRITE_HEIGHT = SPRITE_WIDTH;
   私有静态最后弦乐preSSED =pressed
   RELEASED =私有静态最后弦乐释放;
   私有静态最终诠释preF_W = 800;
   私有静态最终诠释preF_H = 650;
   私人地图<迪尔,布尔> dirMap =新的EnumMap的<>(Dir.class);
   私人INT spriteX = 0;
   私人INT spriteY = 0;
   私人的BufferedImage精灵;
   私人定时器animationTimer =新的Timer(TIMER_DELAY,新AnimationListener());   公共KeyBindingEg2(){
      对于(导演导演:Dir.values​​()){
         dirMap.put(DIR,Boolean.FALSE);
      }
      精灵= createSprite();
      setKeyBindings();
      animationTimer.start();
   }   私人的BufferedImage createSprite(){
      BufferedImage的SPRT =新的BufferedImage(SPRITE_WIDTH,SPRITE_HEIGHT,BufferedImage.TYPE_INT_ARGB);
      图形G = sprt.getGraphics();
      g.setColor(Color.RED);
      g.fillRect(0,0,SPRITE_WIDTH,SPRITE_HEIGHT);
      g.dispose();
      返回SPRT;
   }   @覆盖
   公共尺寸的get preferredSize(){
      返回新的Dimension(preF_W,preF_H);
   }   @覆盖
   保护无效paintComponent(图形G){
      super.paintComponent方法(G);
      如果(精灵!= NULL){
         g.drawImage(雪碧,spriteX,spriteY,这一点);
      }
   }   私人无效setKeyBindings(){
      INT条件= WHEN_IN_FOCUSED_WINDOW;
      InputMap中的InputMap = getInputMap中(条件);
      ActionMap中的ActionMap = getActionMap();      对于(导演导演:Dir.values​​()){
         关键的KeyStroke pressed = KeyStroke.getKeyStroke(dir.getKey code(),0,FALSE);
         的KeyStroke的keyReleased = KeyStroke.getKeyStroke(dir.getKey code(),0,真正的);         inputMap.put(键pressed,dir.toString()+ preSSED);
         inputMap.put(的keyReleased,dir.toString()+释放);         actionMap.put(dir.toString()+ preSSED,新DirAction(DIR,preSSED));
         actionMap.put(dir.toString()+发布新DirAction(DIR发布));
      }   }   私有类AnimationListener实现的ActionListener {
      @覆盖
      公共无效的actionPerformed(ActionEvent的五){
         INT下一页末= spriteX;
         INT newy指定= spriteY;
         对于(导演导演:Dir.values​​()){
            如果(dirMap.get(DIR)){
               下一页末+ = dir.getDeltaX()* DELTA_X;
               newy指定+ = dir.getDeltaY()* DELTA_Y;
            }
         }
         如果(下一页末℃,|| newy指定℃,){
            返回;
         }
         如果(下一页末+ SPRITE_WIDTH>的getWidth()|| newy指定+ SPRITE_HEIGHT>的getHeight()){
            返回;
         }
         spriteX =下一页末;
         spriteY = newy指定;
         重绘();
      }
   }   私有类DirAction扩展AbstractAction {      私人字符串pressedOrReleased;
      私人目录目录;      公共DirAction(迪尔目录,字符串pressedOrReleased){
         this.dir = DIR;
         这pressedOrReleased = pressedOrReleased。
      }      @覆盖
      公共无效的actionPerformed(ActionEvent的EVT){
         如果(pressedOrReleased.equals(preSSED)){
            dirMap.put(DIR,Boolean.TRUE);
         }否则如果(pressedOrReleased.equals(释放)){
            dirMap.put(DIR,Boolean.FALSE);
         }
      }   }   私有静态无效createAndShowGui(){
      KeyBindingEg2的mainPanel =新KeyBindingEg2();      JFrame的帧=新的JFrame(KeyBindingEg);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane()加(mainPanel中)。
      frame.pack();
      frame.setLocationByPlatform(真);
      frame.setVisible(真);
   }   公共静态无效的主要(字串[] args){
      SwingUtilities.invokeLater(Runnable的新(){
         公共无效的run(){
            createAndShowGui();
         }
      });
   }
}

I have a specific "problem" with a game I'm creating for class.

The game is an implementation of "Break it". To move the platform at the bottom I just used a key listener. The problem is that after the first key press there is a short "lag" or "stutter" before the platform starts moving. How could I prevent this to get a smooth response? Is there another way than KeyListener? KeyBindings?

Here is the key listener implementation

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();
        }

    }
}

and here is the method that moves the platform around

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();
    }
解决方案

The solution is not to use the KeyListener's key press for moving your sprite. The key is not to rely on the hardware-specific key press frequency, to use a Swing Timer to create your own frequency. Instead use Key Bindings and a Swing Timer. Start the time on key press and stop it on key release.

For example, run this code and press and release the up-arrow key:

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();
         }
      });
   }
}


Edit

Or a better example, one that moves a sprite in any direction based on a key press of one of the arrow keys. No delay encountered:

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的键盘输入 - 游戏开发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-23 14:00