Привязки клавиш Java запускаются очень непоследовательно - PullRequest
0 голосов
/ 09 декабря 2018

Я работаю над игрой, в которой есть игрок, которого я хотел бы переместить с помощью WASD.Я решил использовать привязки клавиш, чтобы попытаться исправить проблему с прослушивателями клавиш, которая по-прежнему происходит даже после переключения на привязки клавиш.Проблема в том, что даже при нажатии этих клавиш происходит перемещение плеера, после нескольких перемещений плеера ввод практически перестает работать.Это происходит до точки нажатия клавиш, возможно, 1/10 при перемещении игрока.Что я могу делать не так?Любая помощь будет принята с благодарностью.

Вот основной класс моей игры с привязками клавиш: (Дайте мне знать, если я должен опубликовать остальную часть моего кода)

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.Color;  
import java.awt.Graphics;  
import javax.swing.JComponent;
import java.lang.Math;
import java.util.LinkedList;
import java.awt.event.KeyEvent;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.KeyStroke;

public class ZombieMain extends JPanel implements ActionListener{

   private static int WIDTH = 1600;
   private static int HEIGHT = 900;

   private Action a,s,w,d,ra,rs,rw,rd;

   private LinkedList<Zombie> zombies = new LinkedList();
   Zombie z = new Zombie(100,100,50,30,50);
   static ZombiePlayer player = new ZombiePlayer(950,572,2,30);

   public ZombieMain(){
      this.setFocusable(true);
      this.requestFocus();

      Timer t = new Timer(10,this);
      t.start();

      Action w = new AbstractAction() {
         public void actionPerformed(ActionEvent e) {
            player.vY = -player.speed;
         }
      };
      Action s = new AbstractAction() {
         public void actionPerformed(ActionEvent e) {
            player.vY = player.speed;
         }
      };
      Action d = new AbstractAction() {
         public void actionPerformed(ActionEvent e) {
            player.vX = player.speed;
         }
      };
      Action a = new AbstractAction() {
         public void actionPerformed(ActionEvent e) {
            player.vX = -player.speed;
         }
      };
      Action rw = new AbstractAction() {
         public void actionPerformed(ActionEvent e) {
            player.vY = 0;
         }
      };
      Action rs = new AbstractAction() {
         public void actionPerformed(ActionEvent e) {
            player.vY = 0;
         }
      };
      Action rd = new AbstractAction() {
         public void actionPerformed(ActionEvent e) {
            player.vX = 0;
         }
      };
      Action ra = new AbstractAction() {
         public void actionPerformed(ActionEvent e) {
            player.vX = 0;
         }
      };

     getInputMap().put(KeyStroke.getKeyStroke("W"),"w");
     getInputMap().put(KeyStroke.getKeyStroke("S"),"s");
     getInputMap().put(KeyStroke.getKeyStroke("D"),"d");
     getInputMap().put(KeyStroke.getKeyStroke("A"),"a");
     getInputMap().put(KeyStroke.getKeyStroke("released W"),"rw");
     getInputMap().put(KeyStroke.getKeyStroke("released S"),"rs");
     getInputMap().put(KeyStroke.getKeyStroke("released D"),"rd");
     getInputMap().put(KeyStroke.getKeyStroke("released A"),"ra");

     getActionMap().put("w",w);
     getActionMap().put("s",s);
     getActionMap().put("d",d);
     getActionMap().put("a",a);
     getActionMap().put("rw",rw);
     getActionMap().put("rs",rs);
     getActionMap().put("rd",rd);
     getActionMap().put("ra",ra);
   }

   public void actionPerformed(ActionEvent e){
      repaint();
   }

   public void paint(Graphics g){
      g.setColor(new Color(40,40,40));
      g.fillRect(0,0,WIDTH,HEIGHT);
      z.draw((Graphics)g);
      player.draw((Graphics)g);
   }

   public int getWidth(){
      return WIDTH;
   }
   public int getHeight(){
      return HEIGHT;
   }
   public static void main(String[] args){
        JFrame frame = new JFrame();
        frame.add(new ZombieMain());
        frame.setSize(WIDTH,HEIGHT);  
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);    
        frame.setVisible(true);
        frame.setResizable(false);
   }
}

1 Ответ

0 голосов
/ 09 декабря 2018

Относительно того, «почему» у вас возникают проблемы, я могу только догадываться, поскольку у нас есть только неконтекстный фрагмент кода, однако есть ряд вещей, которые можно улучшить, которые могут помочьрешить проблему.

  • Пользователь WHEN_IN_FOCUSED_WINDOW при вызове getInputMap

Это относится к контексту, когда ключевые события будут фактически инициированы, в вышеупомянутом случае ключевые событиябудет сработать, когда у окна будет фокус, независимо от того, какой компонент в данный момент имеет фокус клавиатуры.

  • Предпочитать переопределение paintComponent над paint

Рисование в Swing - этоНекоторые сложные, как общая рекомендация, лучше переопределить paintComponent, если вы хотите выполнить пользовательскую рисование.Приятным побочным эффектом этого является то, что он закрасит фоновый цвет компонентов для вас, на одну вещь меньше, что вам нужно сделать;)

  • Предпочитать переопределение getPreferredSize, когда вам нужно предоставить подсказки по размеру

Переопределение getWidth и getHeight не вызовет конца возможных проблем, и его лучше всего избегать.Вместо этого переопределите getPreferredSize, таким образом, вы участвуете в API макета и получаете все его преимущества, такие как возможность вызывать pack на JFrame и заставить его позаботиться обо всех странностях, связанных с декорациями кадров.

  • Отделите изменение состояния от механизмов, используемых для воздействия на это состояние

Отличное слово для «развязки вашего кода».В вашем коде состояние плеера меняется непосредственно с помощью ключевых действий.Это не только плохая идея, она может привести к неожиданным побочным эффектам и становится все труднее управлять, поскольку требования становятся более сложными.Это также затрудняет изменение способа ввода.Например, вы можете включить различные методы ввода, такие как джойстики, но вам придется написать для него один и тот же код.

Вместо этого у вас должен быть просто «менеджер состояний», который переносит текущее состояние ввода, когда ваш «основной цикл» готов, он будет применять это состояние к модели как отдельный шаг.

«Основной цикл» не заботится о том, как обновляется состояние, он только может получить информацию, необходимую для принятия решения о том, как его применять.

Ниже приведен пример грубоговсе, что я обсуждал выше, и в моем тестировании у меня не было проблем с привязками "срыв"

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;

public class ZombieMain extends JPanel implements ActionListener {

    enum VerticalDirection {
        UP, DOWN, NONE
    }

    enum HorizontalDirection {
        LEFT, RIGHT, NONE
    }

    public class VerticalStateController {

        private VerticalDirection state = VerticalDirection.NONE;

        public void setState(VerticalDirection state) {
            this.state = state;
        }

        public VerticalDirection getState() {
            return state;
        }

    }

    public class HorizontalStateController {

        private HorizontalDirection state = HorizontalDirection.NONE;

        public void setState(HorizontalDirection state) {
            this.state = state;
        }

        public HorizontalDirection getState() {
            return state;
        }

    }

    public class VerticalAction extends AbstractAction {

        private VerticalStateController controller;
        private VerticalDirection state;

        public VerticalAction(VerticalStateController controller, VerticalDirection state) {
            this.controller = controller;
            this.state = state;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            controller.setState(state);
        }

    }

    public class HorizontalAction extends AbstractAction {

        private HorizontalStateController controller;
        private HorizontalDirection state;

        public HorizontalAction(HorizontalStateController controller, HorizontalDirection state) {
            this.controller = controller;
            this.state = state;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            controller.setState(state);
        }

    }

    private static int WIDTH = 400;
    private static int HEIGHT = 400;

    private Rectangle player = new Rectangle(0, 0, 20, 20);
    private VerticalStateController verticalStateController = new VerticalStateController();
    private HorizontalStateController horizontalStateController = new HorizontalStateController();

    public ZombieMain() {
        setBackground(new Color(40, 40, 40));

        Timer t = new Timer(10, this);
        t.start();

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

        // Pressed
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false), "Pressed.up");
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, false), "Pressed.down");
        // Released
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, true), "Released.up");
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, true), "Released.down");

        // Pressed
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, false), "Pressed.left");
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, false), "Pressed.right");
        // Released
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, true), "Released.left");
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, true), "Released.right");

        am.put("Pressed.up", new VerticalAction(verticalStateController, VerticalDirection.UP));
        am.put("Pressed.down", new VerticalAction(verticalStateController, VerticalDirection.DOWN));
        am.put("Released.up", new VerticalAction(verticalStateController, VerticalDirection.NONE));
        am.put("Released.down", new VerticalAction(verticalStateController, VerticalDirection.NONE));

        am.put("Pressed.left", new HorizontalAction(horizontalStateController, HorizontalDirection.LEFT));
        am.put("Pressed.right", new HorizontalAction(horizontalStateController, HorizontalDirection.RIGHT));
        am.put("Released.left", new HorizontalAction(horizontalStateController, HorizontalDirection.NONE));
        am.put("Released.right", new HorizontalAction(horizontalStateController, HorizontalDirection.NONE));
    }

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

    public void actionPerformed(ActionEvent e) {
        switch (verticalStateController.getState()) {
            case UP:
                player.y -= 4;
                break;
            case DOWN:
                player.y += 4;
                break;
        }
        switch (horizontalStateController.getState()) {
            case LEFT:
                player.x -= 4;
                break;
            case RIGHT:
                player.x += 4;
                break;
        }
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setColor(Color.RED);
        g2d.fill(player);
        g2d.dispose();
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new ZombieMain());
                frame.pack();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }
}

Я должен отметить, что это только один подход.Могли бы также поставить кучу "флагов" в Set какой-то

...