Как мне лучше реализовать привязки клавиш и таймер качания? - PullRequest
1 голос
/ 05 августа 2020

Привет, спасибо, что посмотрели мой пост. Летом я работал над интересным проектом, и эта проблема возникла. Во-первых, это может считаться повторяющимся вопросом, но я просматривал этот сайт и Oracle в поисках исправления и не смог его найти, или, что более вероятно, я просто не понимаю код, с которым работаю. Одним из основных помощников является одно судно на воздушной подушке, полное угрей, в ответ на такие вопросы, как этот .

Я хочу получить ящик JPanel, чтобы перемещаться по JFrame, ну и еще JPanel, с помощью клавиш w, a, s, d. Сначала я создал свою собственную панель, расширив JPanel. Оттуда мне удалось заставить работать движение, но есть заикание из-за того, как работают привязки клавиш, и я читал, что добавление таймера качания улучшит заикание. Первоначально я предполагаю, что я что-то реализую неправильно или недостаточно знаю о том, что делаю, чтобы увидеть свою ошибку. Я также пробовал свои силы в установке флага, чтобы помочь непрерывному движению. Сообщений об ошибках нет, и мне еще нужно кое-что реализовать, например, предотвратить выход за границы. Вот что у меня есть:

public class PlayerPanel extends JPanel {
    private static final int width = 100;
    private static final int height = 200;
    private int xPos, yPos;
    private boolean movingUp, movingDown, movingLeft, movingRight;
    private static final int SPIN_TIMER_PERIOD = 20;
    private Timer timer;
    
    public PlayerPanel() {
        xPos = this.getX();
        yPos = this.getY();
        movingUp = movingDown = movingLeft = movingRight = false;
        timer = new Timer(SPIN_TIMER_PERIOD, new SpinTimerListener());
        timer.setInitialDelay(0);
        timer.start();
        
        setPreferredSize(new Dimension(width, height));
        setBackground(Color.cyan);
        setUpKeyBindings();
    }
    
    private void setUpKeyBindings() {
        int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
        InputMap inMap = this.getInputMap(condition);
        ActionMap actMap = this.getActionMap();
        
        inMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "moveUp");
        actMap.put("moveUp", new KeyAction("up"));
        
        inMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), "moveDown");
        actMap.put("moveDown", new KeyAction("down"));
        
        inMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "moveLeft");
        actMap.put("moveLeft", new KeyAction("left"));
        
        inMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "moveRight");
        actMap.put("moveRight", new KeyAction("right"));
    }
    
    public class KeyAction extends AbstractAction {
        private String direction;
        private int delta = 2;

        public KeyAction(String direction) {
            this.direction = direction;
        }
        
        @Override
        public void actionPerformed(ActionEvent e) {
            switch(direction) {
                case "up":
                    movingUp = true;
                    yPos -= delta;
                    break;
                case "down":
                    movingDown = true;
                    yPos += delta;
                    break;
                case "right":
                    movingRight = true;
                    xPos += delta;
                    break;
                case "left":
                    movingLeft = true;
                    xPos -= delta;
                    break;
                default:
                    break;
            }
        }
    }
    
    private class SpinTimerListener implements ActionListener{

        @Override
        public void actionPerformed(ActionEvent e) {
            int delta = 5;

            if(movingUp) {
                yPos -= delta;
                movingUp = false;
            }
            else if(movingDown) {
                yPos += delta;
                movingDown = false;
            }
            else if(movingLeft) {
                xPos -= delta;
                movingLeft = false;
            }
            else if(movingRight) {
                xPos += delta;
                movingRight = false;
            }
            setLocation(xPos, yPos);
        }
    }
}

Я старался, чтобы мой код был минимальным, и это то, что я создал.

Да, есть более эффективные способы кодирования этого, например использование enum для настройки привязок клавиш, но моя философия кодирования такова:

  • выяснить, что я хочу сделать, заставить его работать (обычно с тем, что я называю кодом грубой силы)
  • понять, почему это работает
  • сделать его лучше и красивее.

Я нахожусь в фазе понимания. Еще один очень важный момент: почему я не использую Graphics, как в Graphics g.draw (бла). ТБХ Понятия не имею. Мне не удалось заставить его работать, и мне нужно потратить больше времени на него, прежде чем я задам вопрос, связанный с ним, поскольку просить кого-нибудь научить меня, как использовать графику, здесь не кажется уместным. как и должно быть, как мне лучше реализовать привязку клавиш и таймер качания. Я думал, что использование setLocation может быть проблемой вместо использования graphics.repaint или чего-то еще, но setLocation вызывает перерисовку, поэтому я не думаю, что это основная проблема, но, вероятно, тем не менее. Я прошу прощения за стену с текстом, но я хочу попытаться быть внимательным, поэтому ...

TL: DR; Я делаю обычай JPanel перемещаться с привязкой клавиш и таймером поворота. Движение заикается, и я бы тоже этого не хотел. После публикации и некоторого отдыха я объединю четыре движущихся логических значения в одно, поскольку это тоже может не помочь, и добавлю переменную состояния для направления и попытаюсь разложить свой код. Спасибо, что посмотрели мой код, и любая помощь приветствуется. Мне нравится учиться программировать и читать любое количество ссылок, которые, по вашему мнению, мне было лень искать.

Также вот мой основной код, если вы хотите запустить именно то, что я запускаю, PlayerPanel и Класс Driver с основным методом - это мои единственные два файла, с которыми я работаю.

public class Driver {

    public static void main(String args[]) {
        JFrame frame = new JFrame();
        frame.setSize(1000, 500);
        
        JPanel background = new JPanel();
        background.setBackground(Color.BLACK);
        
        PlayerPanel player = new PlayerPanel();
        background.add(player);
        
        frame.add(background);
        frame.setVisible(true);
    }
}
...