在创建简单的子弹地狱游戏时,我遇到了键绑定问题。
我将提供有关键绑定的游戏机制的一些背景信息。在这个二维游戏中,你的角色可以通过按住非小键盘箭头键组合(向上,向左和向下+向右分别为北,东和西南方向)以恒定速度在所有八个方向上移动。 )您也可以按住Shift键并结合之前提到的任何键组合,以相同的方向移动,但速度较慢。
以下是遇到此问题的程序示例的代码。这个例子中的问题与相对较大的子弹地狱计划中的问题相同。
/*
* Keybind feedback, by Nematodes
*/
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
public class keybindFeedback extends JFrame
{
private static final long serialVersionUID = 0L;
JPanel framePanel = new JPanel();
private static Action moveUpTrue;
private static Action moveUpFalse;
private static Action moveUpFocusedTrue;
private static Action moveUpFocusedFalse;
public static void main(String[] args)
{
keybindFeedback createFrame = new keybindFeedback();
createFrame.constructFrame();
}
public void constructFrame()
{
// Construct the frame and frame components
setTitle("Keybind Feedback");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
getContentPane().setLayout(new GridBagLayout());
setVisible(true);
GridBagConstraints gridConstraints;
// This JPanel only exists so that it is easier to focus on the window, so that keyevents will register
gridConstraints = new GridBagConstraints();
gridConstraints.gridx = 0;
gridConstraints.gridy = 0;
framePanel.setBackground(Color.BLACK);
framePanel.setPreferredSize(new Dimension(700, 700));
getContentPane().add(framePanel, gridConstraints);
pack();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setBounds((int) (0.5 * (screenSize.width - getWidth())),
(int) (0.5 * (screenSize.height - getHeight())), getWidth(), getHeight());
// Initialize and map all of the keybinds
moveUpTrue = new MoveUpTrue();
moveUpFalse = new MoveUpFalse();
moveUpFocusedTrue = new MoveUpFocusedTrue();
moveUpFocusedFalse = new MoveUpFocusedFalse();
// Code spacing for placing things in the input map is only wonky in this code-formatting block due to strange spacing issues in stackoverflow
framePanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("UP"), "doMoveUpTrue");
framePanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released UP"), "doMoveUpFalse");
framePanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("shift UP"), "doMoveUpFocusedTrue");
framePanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("shift released UP"), "doMoveUpFocusedFalse");
framePanel.getActionMap().put("doMoveUpTrue", moveUpTrue);
framePanel.getActionMap().put("doMoveUpFalse", moveUpFalse);
framePanel.getActionMap().put("doMoveUpFocusedTrue", moveUpFocusedTrue);
framePanel.getActionMap().put("doMoveUpFocusedFalse", moveUpFocusedFalse);
}
// Keybind actions for up, up released, shift-up, and shift-up released
class MoveUpTrue extends AbstractAction
{
public void actionPerformed(ActionEvent e)
{
System.out.println("Up");
}
}
class MoveUpFalse extends AbstractAction
{
public void actionPerformed(ActionEvent e)
{
System.out.println("Up released");
}
}
class MoveUpFocusedTrue extends AbstractAction
{
public void actionPerformed(ActionEvent e)
{
System.out.println("Shift-up");
}
}
class MoveUpFocusedFalse extends AbstractAction
{
public void actionPerformed(ActionEvent e)
{
System.out.println("Shift-up released");
}
}
}
如果您按下几秒钟然后释放它,程序将触发许多按下的事件,然后是一个向上发布的事件。在游戏中,这将以标准速度向上移动。
如果按下shift键,然后向上按几秒钟,然后松开,程序将触发许多升档按下的事件,然后发布升档事件。必须首先按下Shift键,然后最后释放(如果你完全释放它),这样才能工作。在游戏中,这将以较慢的速度向上移动。
如果你按下shift,然后向上按几秒钟,然后释放换档,然后在释放换档后释放几秒钟,程序将首先发出大量按下升档的事件,然后启动按下的事件,最后发布了一个已发布的事件。在游戏中,这将以较慢的速度向上移动,然后决定以更快的速度向上移动。
如果你按下几秒钟,然后按下shift键,程序将首先发出大量按下的事件,然后在按住shift键时不发出任何事件。预期的行为是,一旦在按下时按下它,它应该开始触发向上移动的按下事件而不是向上按下的事件。如果玩家以标准速度向上移动,然后想要以较慢的速度移动,这将适用于游戏中
继续前一个场景:
如果你在按下的同时释放换档,尽管你现在只是按下它,它不会发出任何向上按下的事件。如果你现在释放它,它仍然会触发一个向上释放的事件,即使它永远不会触发任何压制事件
如果你在仍然保持换档的情况下释放,它将触发一次升级释放事件,即使它永远不会触发任何升档压力事件。
这不是我键盘上的按键翻转问题,因为它可以将所有这些按键合并按下。
这不是java不接受键事件的问题。
这是自然的Windows 7(我正在使用的操作系统)行为,这恰好是有问题的。在普通文本框中使用shift和字母键时,会看到相同的行为。
现在问一下,有没有办法绕过操作系统的关键事件处理,以便在按住时按下shift会触发向上移动的按下事件?