键侦听器在活动渲染时不工作



我正在尝试用Java编写一个非常简单的平台游戏。我有一部分使用被动渲染(使用调用repaint()revalidate()等的Timer对象),但我一直在尝试实现主动渲染。它有点工作 - 因为它渲染,动画工作,但它似乎阻止了关键监听器(以前工作正常),出于某种我不太明白的原因。

我已经在下面尽可能少地重现了这个问题。当您按下某个键时,应该有终端输出,但没有。如果有人能告诉我为什么keyPressed等方法没有发射,将不胜感激。

编辑 - 根据请求将演示代码修改为一个复制/粘贴

Edit2 - 正如Andrew Thompson所建议的那样,我已经删除了所有全屏代码,但keylistener仍然不起作用

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
class FullScreenRenderWithListener implements KeyListener {
   private JFrame frame;
   private World  world;
   public static void main(String[] args)
   {
      FullScreenRenderWithListener main = new FullScreenRenderWithListener();
      SwingUtilities.invokeLater(main::run);
   }
   private void run()
   {
      initWindow();
      setupWorld();
      frame.setIgnoreRepaint(true);
      frame.pack();
      frame.createBufferStrategy(2);
      frame.setVisible(true);
      world.startActive(frame.getBufferStrategy());
   }
   private void initWindow()
   {
      frame = new JFrame();
      frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
      frame.setLocationByPlatform(true);
   }
   private void setupWorld()
   {
      world = new World();
      frame.addKeyListener(this);
      frame.add(world);
      world.addKeyListener(this);
   }
   @Override
   public void keyPressed(KeyEvent event)
   {
      System.out.println("Pressed");
   }
   @Override
   public void keyReleased(KeyEvent event)
   {
      System.out.println("Released");
   }
   @Override
   public void keyTyped(KeyEvent event)
   {
      System.out.println("Typed");
   }
}
class World extends JPanel {
   private static final int FRAMES_PER_SEC = 60;
   private static final int MILL_IN_SEC    = 1000;
   private static final int TICK_LENGTH    =
      MILL_IN_SEC / FRAMES_PER_SEC;
   private BufferStrategy strategy;
   private void sleepUntilEndOfFrame()
   {
      try {
         long used = System.currentTimeMillis() % TICK_LENGTH;
         long left = TICK_LENGTH - used;
         Thread.sleep(left);
      } catch(InterruptedException e) {
         // ... Handle this error
      }
   }
   public void startActive(BufferStrategy strategy)
   {
      this.strategy = strategy;
      setIgnoreRepaint(true);
      while(true) {
         doFrame();
      }
   }
   private void doFrame()
   {
      updateGameState();
      activeRenderFrame();
   }
   private void updateGameState()
   {
      // ..
   }
   private void activeRenderFrame()
   {
      Graphics2D graphicsContext = (Graphics2D)strategy
         .getDrawGraphics();
      paintComponent(graphicsContext);
      strategy.show();
      Toolkit.getDefaultToolkit().sync();
      graphicsContext.dispose();
      sleepUntilEndOfFrame();
   }
   @Override
   public Dimension getPreferredSize()
   {
      return new Dimension(500, 500);
   }

   // Have overridden this method because the class
   // also implements passive rendering if active is
   // not supported
   @Override
   public void paintComponent(Graphics g)
   {
      super.paintComponent(g);
      // .. drawing code
   }
}

第一个问题是不要考虑使用KeyBinding策略,而不是在处理JPanel时特别考虑使用KeyListener。您可以通过注释无限while循环(禁用活动渲染)来检查这一点。

当你使用 KeyListener 时,无论是否使用活动渲染过程,都不会触发KeyEvent(或者至少我们可以说我们的侦听器没有调用)。

使用keyBinding将解决此问题。

但是,当您取消注释无限while循环时,问题会再次出现。那么什么可以解决这个问题呢?更新框架的新Thread是关键!

检查您的程序,该程序由KeyBinding和用于使用活动渲染策略更新帧的新Thread

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferStrategy;
import java.util.HashMap;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class FullScreenRenderWithListener implements Runnable
{
    private JFrame frame;
    private World world;
    public static void main ( String[] args )
    {
        FullScreenRenderWithListener main = new FullScreenRenderWithListener ();
        SwingUtilities.invokeLater ( main );
    }
    public void run ()
    {
        initWindow ();
        setupWorld ();
        frame.setIgnoreRepaint ( true );
        frame.pack ();
        frame.createBufferStrategy ( 2 );
        frame.setVisible ( true );
        world.startActive ( frame.getBufferStrategy () );
    }
    private void initWindow ()
    {
        frame = new JFrame ();
        frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
        frame.setLocationByPlatform ( true );
    }
    private void setupWorld ()
    {
        world = new World ();
        frame.add ( world );
        frame.setFocusable ( true );
        world.setFocusable ( true );
    }
}
class World extends JPanel
{
    private static final int FRAMES_PER_SEC = 10;
    private static final int MILL_IN_SEC = 1000;
    private static final int TICK_LENGTH = MILL_IN_SEC / FRAMES_PER_SEC;
    private BufferStrategy strategy;
    //
    private static final String PRESSED = "Pressed";
    private static final String RELEASED = "Released";
    private Map < Direction , Boolean > directionMap = new HashMap < Direction , Boolean > ();
    private void sleepUntilEndOfFrame ()
    {
        try
        {
            long used = System.currentTimeMillis () % TICK_LENGTH;
            long left = TICK_LENGTH - used;
            Thread.sleep ( left );
        }
        catch ( InterruptedException e )
        {
            // ... Handle this error
            e.printStackTrace ();
        }
    }
    private void setBindings() {
          int context = JComponent.WHEN_IN_FOCUSED_WINDOW;
          InputMap inputMap = getInputMap(context);
          ActionMap actionMap = getActionMap();
          for (Direction direction : Direction.values()) {
             inputMap.put(KeyStroke.getKeyStroke(direction.getKeyCode(), 0, false), direction.getName() + PRESSED);
             inputMap.put(KeyStroke.getKeyStroke(direction.getKeyCode(), 0, true), direction.getName() + RELEASED);
             // set corresponding actions for the  key presses and releases above
             actionMap.put(direction.getName() + PRESSED, new ArrowKeyAction(true, direction));
             actionMap.put(direction.getName() + RELEASED, new ArrowKeyAction(false, direction));
          }
    }
    public void startActive ( BufferStrategy strategy )
    {
        for ( Direction direction : Direction.values () )
        {
            directionMap.put ( direction , Boolean.FALSE );
        }
        setBindings ();
        //
        this.strategy = strategy;
        setIgnoreRepaint ( true );
        Thread t = new Thread (){
            @Override
            public void run ()
            {
                while ( true )
                {
                    doFrame ();
                }
            }
        };
        t.start ();
    }
    private void doFrame ()
    {
        updateGameState ();
        activeRenderFrame ();
    }
    private void updateGameState ()
    {
        // ..
    }
    private void activeRenderFrame ()
    {
        Graphics2D graphicsContext = (Graphics2D) strategy.getDrawGraphics ();
        paintComponent ( graphicsContext );
        strategy.show ();
        Toolkit.getDefaultToolkit ().sync ();
        graphicsContext.dispose ();
        sleepUntilEndOfFrame ();
    }
    @Override
    public Dimension getPreferredSize ()
    {
        return new Dimension ( 500 , 500 );
    }
    // Have overridden this method because the class
    // also implements passive rendering if active is
    // not supported
    @Override
    public void paintComponent ( Graphics g )
    {
        super.paintComponent ( g );
        // .. drawing code
    }
    private class ArrowKeyAction extends AbstractAction
    {
        private Boolean pressed;
        private Direction direction;
        public ArrowKeyAction ( boolean pressed , Direction direction )
        {
            this.pressed = Boolean.valueOf ( pressed );
            this.direction = direction;
        }
        @Override
        public void actionPerformed ( ActionEvent arg0 )
        {
            directionMap.put ( direction , pressed );
            System.out.println ("Direction: "+ direction + ", State: " + pressed);
        }
    }
}
enum Direction {
   UP("Up", KeyEvent.VK_UP, new Point(0, -1)),
   DOWN("Down", KeyEvent.VK_DOWN, new Point(0, 1)),
   LEFT("Left", KeyEvent.VK_LEFT, new Point(-1, 0)),
   Right("Right", KeyEvent.VK_RIGHT, new Point(1, 0));
   private String name;
   private int keyCode;
   private Point vector;
   private Direction(String name, int keyCode, Point vector) {
      this.name = name;
      this.keyCode = keyCode;
      this.vector = vector;
   }
   public String getName() {
      return name;
   }
   public int getKeyCode() {
      return keyCode;
   }
   public Point getVector() {
      return vector;
   }
   @Override
   public String toString() {
      return name;
   }
}

此示例仅绑定箭头键的某些KeyBinding。您也可以通过更改setBindings方法签出其他键。此外,您可能希望为其他键定义更多Event和另一个enum

希望这有帮助。

相关内容

  • 没有找到相关文章

最新更新