1

我正在尝试制作一个平台,但我坚持如何一次检测多个按键。例如,如果我使用运行键并向前跑,然后我按了跳跃键,游戏仍然需要知道运行键是否被按下

4

2 回答 2

2

这比我正常做的要复杂一些。通常我会允许每个Action人直接改变游戏状态。

此示例展示了如何使用键绑定API 来监控某些键的按下/释放以及从中央池中添加/删除它们。

使用这个 API 的主要原因是它克服了KeyListener焦点上下文的限制。只要窗口具有焦点,此示例将检索按键通知。

public class TestMultyKeyPress {

    public static void main(String[] args) {
        new TestMultyKeyPress();
    }

    public TestMultyKeyPress() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new KeyPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class KeyPane extends JPanel implements KeyManager {

        private TrianglePane upPane;
        private TrianglePane downPane;
        private TrianglePane leftPane;
        private TrianglePane rightPane;
        private List<Integer> keysList = new ArrayList<>(25);

        public KeyPane() {
            setLayout(new GridBagLayout());
            upPane = new TrianglePane(0);
            leftPane = new TrianglePane(1);
            downPane = new TrianglePane(2);
            rightPane = new TrianglePane(3);
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 1;
            gbc.gridy = 0;
            add(upPane, gbc);

            gbc.gridx = 0;
            gbc.gridy++;
            add(leftPane, gbc);
            gbc.gridx += 2;
            add(rightPane, gbc);

            gbc.gridx = 1;
            gbc.gridy++;
            add(downPane, gbc);

            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am = getActionMap();

            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "KeyPressed.Left");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "KeyPressed.Right");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "KeyPressed.Up");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "KeyPressed.Down");

            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), "KeyReleased.Left");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), "KeyReleased.Right");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "KeyReleased.Up");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "KeyReleased.Down");

            am.put("KeyPressed.Left", new KeyAction(KeyEvent.VK_LEFT, false, this));
            am.put("KeyPressed.Right", new KeyAction(KeyEvent.VK_RIGHT, false, this));
            am.put("KeyPressed.Up", new KeyAction(KeyEvent.VK_UP, false, this));
            am.put("KeyPressed.Down", new KeyAction(KeyEvent.VK_DOWN, false, this));

            am.put("KeyReleased.Left", new KeyAction(KeyEvent.VK_LEFT, true, this));
            am.put("KeyReleased.Right", new KeyAction(KeyEvent.VK_RIGHT, true, this));
            am.put("KeyReleased.Up", new KeyAction(KeyEvent.VK_UP, true, this));
            am.put("KeyReleased.Down", new KeyAction(KeyEvent.VK_DOWN, true, this));

        }

        @Override
        public void keyPressed(int keyCode) {
            if (!keysList.contains(keyCode)) {
                keysList.add(new Integer(keyCode));
                updateKeyState();
            }
        }

        @Override
        public void keyReleased(int keyCode) {
            keysList.remove(new Integer(keyCode));
            updateKeyState();
        }

        public void updateKeyState() {
            upPane.setActive(keysList.contains(KeyEvent.VK_UP));
            downPane.setActive(keysList.contains(KeyEvent.VK_DOWN));
            leftPane.setActive(keysList.contains(KeyEvent.VK_LEFT));
            rightPane.setActive(keysList.contains(KeyEvent.VK_RIGHT));
        }

    }

    public interface KeyManager {

        public void keyPressed(int keyCode);

        public void keyReleased(int keyCode);

    }

    public class KeyAction extends AbstractAction {

        private int keyCode;
        private boolean released;
        private KeyManager manager;

        public KeyAction(int keyCode, boolean released, KeyManager manager) {
            this.keyCode = keyCode;
            this.released = released;
            this.manager = manager;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (released) {
                manager.keyReleased(keyCode);
            } else {
                manager.keyPressed(keyCode);
            }
        }

    }

    public class TrianglePane extends JPanel {

        private boolean active;
        private TriangleShape shape;

        public TrianglePane(int direction) {

            shape = new TriangleShape(20);
            AffineTransform at = null;
            switch (direction) {
                case 0:
                    at = AffineTransform.getRotateInstance(Math.toRadians(-90), 10, 10); // UP
                    break;
                case 1:
                    at = AffineTransform.getRotateInstance(Math.toRadians(180), 10, 10); // UP
                    break;
                case 2:
                    at = AffineTransform.getRotateInstance(Math.toRadians(90), 10, 10); // UP
                    break;
                case 3:
                    at = AffineTransform.getRotateInstance(Math.toRadians(0)); // UP
                    break;
            }
            shape.transform(at);
        }

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

        public void setActive(boolean value) {
            if (active != value) {
                this.active = value;
                repaint();
            }
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            int x = (getWidth() - shape.getBounds().width) / 2;
            int y = (getHeight() - shape.getBounds().height) / 2;
            if (active) {
                g2d.setColor(Color.BLACK);
            } else {
                g2d.setColor(Color.GRAY);
            }
            g2d.fill(shape);
        }

    }

    public class TriangleShape extends Path2D.Float {

        public TriangleShape(int size) {
            moveTo(1, 1);
            lineTo(size - 1, (size - 1) / 2);
            lineTo(1, size - 1);
            closePath();
        }

    }

}
于 2012-11-24T01:14:33.240 回答
1

试试这个自定义类,它使用 aHashSet来跟踪按下的键...

class MultiKeyPressListener implements KeyListener {

    // Set of currently pressed keys
    private final Set<Character> pressed = new HashSet<Character>();

    @Override
    public synchronized void keyPressed(KeyEvent e) {
        pressed.add(e.getKeyChar());
        if (pressed.size() > 1) {
            // More than one key is currently pressed.
            // Iterate over pressed to get the keys.
        }
    }

    @Override
    public synchronized void keyReleased(KeyEvent e) {
        pressed.remove(e.getKeyChar());
    }

    @Override
    public void keyTyped(KeyEvent e) {/* Not used */ }
}
于 2012-11-23T12:21:22.800 回答