【问题标题】:Calling method using KeyBindings使用 KeyBindings 调用方法
【发布时间】:2018-06-04 04:50:49
【问题描述】:

我正在创建一个 2d 游戏,玩家可以在其中射击子弹。我试图弄清楚当玩家按键时如何调用 shoot 方法。我正在使用 Key Bindings,这对我来说是新的。我已经阅读了 API,但仍然无法正常工作。建议会有帮助

这是我的键盘输入代码:

public PlayerTwo (){
    playertwo = Toolkit.getDefaultToolkit().createImage("cal.png");
    bullets = new ArrayList();
    tm.start();
    InputMap im = getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW);
    ActionMap am = getActionMap();

    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "up.pressed");
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "up.released");
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "down.pressed");
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "down.released");
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "left.pressed");
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), "left.released");
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "right.pressed");
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), "right.released");
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false), "space.pressed");
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true), "space.released");


    am.put("up.pressed", new MoveAction(-1, 0));
    am.put("up.released", new MoveAction(0, 0));
    am.put("down.pressed", new MoveAction(1, 0));
    am.put("down.released", new MoveAction(0, 0));
    am.put("left.pressed", new MoveAction(0, -1));
    am.put("left.released", new MoveAction(0, 0));
    am.put("right.pressed", new MoveAction(0, 1));
    am.put("right.released", new MoveAction(0, 0));
    //Shoot.getActionMap();

}

【问题讨论】:

  • am.put("space.pressed", new ShootAction()); ShootAction 类来改变“拍摄”标志的状态,通过它你的“主循环”可以决定应该做什么
  • 我可以重写我的子弹类来改变状态吗?
  • 我会避免它,因为你正在耦合逻辑。最好让“射击动作”改变模型/控制器的状态,让它决定这实际上意味着什么
  • 周围有很多例子,this is one 我最近做了这证明了解耦工作流的想法

标签: java swing graphics jframe key-bindings


【解决方案1】:

键绑定(和动作)API 试图将“输入”的概念与“动作”分离。这允许您拥有多种类型的“输入”,它们都可以触发相同的操作。

例如,您可能有按钮、键盘敲击、操纵杆或其他外部控制器,它们都能够生成“射击”输入。而不是必须为“最终”触发某些动作的每个输入编写代码。您可以简单地将它们全部绑定到单个“动作”,以一种简洁的方式相互分离(绑定操纵杆输入的方式可能与按钮或按键不同)。

所以,我们首先需要以某种方式表明“触发器”已被拉(或释放),可能类似于...

public class ShootAction extends AbstractAction {
    private boolean isShooting;

    public ShootAction(boolean isShooting) {
        this.isShooting = isShooting;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
    }
}

好吧,好吧,这有点无聊,实际上并没有“做”任何事情。我们需要的是某种“状态管理器”,我们可以告诉它触发器已被按下或释放。需要注意的是,ShootActions 没有责任决定“什么”或“如何”拍摄发生,它应该纯粹专注于通知“模型”或“控制器”状态已经改变,以便它可以做出反应以某种有意义的方式。

所以,假设我们有一些控制器提供射击状态管理......

public class SomeAwesomeGameController ... {
    public void setShooting(boolean shooting) {...}
    public boolean isShooting() {...}
}

我们可以将它的一个实例传递给动作并使用它来更新状态...

public class ShootAction extends AbstractAction {
    private boolean isShooting;
    private SomeAwesomeGameController controller;

    public ShootAction(SomeAwesomeGameController controller, boolean isShooting) {
        this.controller = controller;
        this.isShooting = isShooting;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        controller.setShooting(isShooting);
    }
}

这样做的一个原因(除了解耦代码)是因为在第一次击键和重复击键之间存在操作系统延迟。通过消除对实际重复事件的依赖(仅在状态变化时关心),我们消除了这种延迟。

最后,我们可以将它们绑定在一起:P

public class PlayerTwo ... {

    // Don't forget to assign this value ;)
    private SomeAwesomeGameController controller;

    public PlayerTwo() {

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

        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false), "space.pressed");
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true), "space.released");

        am.put("space.pressed", new ShootAction(controller, true));
        am.put("space.released", new ShootAction(controller, false));

【讨论】:

  • 感谢您的帮助。我在将输入添加到我的主游戏类时也遇到了问题,您有什么建议吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-08
  • 2013-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多