首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Java键绑定的触发非常不一致

Java键绑定的触发非常不一致
EN

Stack Overflow用户
提问于 2018-12-09 07:13:02
回答 1查看 38关注 0票数 1

我正在开发一个游戏,它有一个玩家,我想使用WASD移动。我决定使用键绑定来尝试解决我遇到的键侦听器的问题,即使在切换到键绑定之后,这个问题仍然在发生。问题是,即使按下这些键是在移动播放器,但在移动播放器几次之后,输入几乎完全停止工作。这发生在可能只有1/10的按键移动玩家的情况下。我能做错什么呢?任何帮助都将不胜感激。

下面是我的游戏的主类和键绑定:(如果我应该发布剩下的代码,请告诉我)

代码语言:javascript
运行
复制
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);
   }
}
EN

回答 1

Stack Overflow用户

发布于 2018-12-09 08:16:10

至于“为什么”你有问题,我只能猜测,因为我们只有一个脱离上下文的片段要处理,然而,有许多事情可以改进,这可能有助于解决问题。

调用getInputMap时的

  • User WHEN_IN_FOCUSED_WINDOW

这适用于何时实际触发按键事件的上下文,在上述情况下,无论当前哪个组件具有键盘焦点,只要窗口有焦点,就会触发按键事件。

paint相比,

  • 更喜欢覆盖paintComponent

Swing中的绘画有些复杂,正如一般建议的那样,当你想要执行自定义绘画时,最好覆盖paintComponent。这样做的一个很好的副作用是,它将为您的组件绘制背景颜色,您需要做的事情就少了一件;)

当您需要为

  • 提供大小调整提示时,

首选覆盖getPreferredSize

覆盖getWidthgetHeight将会导致无休止的问题,最好避免。相反,覆盖getPreferredSize,这样,您就参与到了布局应用程序接口中,并获得了它的所有优势,例如能够在JFrame上调用pack,并让它处理围绕框架装饰的所有奇怪之处。

  • 将状态的更改与用于影响该状态的机制分开

“解耦你的代码”这句话用得很好。在您的代码中,播放器的状态直接由按键操作更改。这不仅是一个糟糕的想法,而且可能会产生意想不到的副作用,并且随着需求变得越来越复杂,管理也会变得越来越困难。这也使得改变输入的方式变得困难。例如,您可以包含不同的输入方法,例如操纵杆,但是您必须为它编写相同的代码。

相反,你应该有一个简单的“状态管理器”,它携带输入的当前状态,当你的“主循环”准备好时,它会将该状态作为单独的步骤应用到模型中。

“主循环”并不关心状态是如何更新的,只关心它可以获得所需的信息来决定如何应用它。

下面是我上面讨论的所有内容的粗略示例,在我的测试中,我没有遇到绑定“拖延”的问题。

代码语言:javascript
运行
复制
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中放置一堆“标志”

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53687927

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档