突围游戏多键处理
Breakout Game Multiple Key Handling
我希望我的矩形在用户同时按下左右键时停止。我研究了多个密钥处理,但无法找到任何东西。
package View;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GamePanel extends JPanel {
private final int WIDTH = 600, HEIGHT = 500;
// PROPERTIES
private Timer timer;
int x = 0;
int y = 475;
int velX = 0; // only left or right
// CONSTRUCTOR
public GamePanel() {
setSize(WIDTH, HEIGHT);
setBackground(new Color(240, 255, 255));
timer = new Timer(5, new MyTimerListener());
addKeyListener( new MyKeyListener());
setFocusable(true); // for key listening
setFocusTraversalKeysEnabled(false);
timer.start();
}
// METHODS
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor( new Color(201, 51, 51));
g.fillRoundRect(x, y, 80, 20, 15, 15);
}
public class MyTimerListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
if ( x < 0 )
{
velX = 0;
x = 0;
}
if ( x > 520 )
{
velX = 0;
x = 520;
}
x = x + velX;
repaint();
}
}
public class MyKeyListener implements KeyListener {
@Override
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if ( code == KeyEvent.VK_LEFT )
velX = -1;
if ( code == KeyEvent.VK_RIGHT )
velX = 1;
}
@Override
public void keyReleased(KeyEvent e) {
velX = 0;
}
@Override
public void keyTyped(KeyEvent e) {}
}
}
感谢 heeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep
![两个布偶]
再次说明,使用键绑定而不是 KeyListener。您可能希望对向右和向左箭头键的按键按下和释放使用单独的绑定,并且希望让您的按键绑定操作更改程序状态,这将影响 Swing Timer 如何移动桨。在此示例中(借用我的另一个示例),我创建了一个枚举 Direction 来封装左右方向,并创建了一个 Map<Direction, Boolean>
将布尔值与左右方向相关联。按下右箭头键将更改地图以将 RIGHT 方向与 true
布尔值相关联,而释放键则相反。计时器将轮询地图以查看将桨移动到哪里。例如:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.EnumMap;
import java.util.Map;
import javax.swing.*;
@SuppressWarnings("serial")
public class GamePanel2 extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = 500;
private static final int PADDLE_Y = 475;
private static final int PADDLE_W = 80;
private static final int PADDLE_H = 20;
private static final int PADDLE_ARC = 15;
private static final int TIME_DELAY = 15;
public static final int VEL_X = 2;
private static final Color PADDLE_COLOR = new Color(201, 51, 51);
private int paddleX;
private Timer time = new Timer(TIME_DELAY, new TimerListener());
// key presses and releases will change the boolean values held in this Map
// When an arrow key is pressed, the direction-corresponding boolean is set true
// and likewise when the arrow key is released the direction corresponding boolean is false
private Map<Direction, Boolean> dirMap = new EnumMap<>(Direction.class);
public GamePanel2() {
setKeyBindings();
time.start();
}
private void setKeyBindings() {
int condition = WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();
// iterate through all the Direction enums
for (Direction direction : Direction.values()) {
// set all values to false
dirMap.put(direction, false);
// create two key strokes, one for pressed and one for released
int keyValue = direction.getKeyValue();
KeyStroke pressedKey = KeyStroke.getKeyStroke(keyValue, 0, false);
KeyStroke releasedKey = KeyStroke.getKeyStroke(keyValue, 0, true);
// create two Actions, one for pressed, one for released
Action pressedAction = new KeyAction(direction, true);
Action releasedAction = new KeyAction(direction, false);
// add keystroke to inputMap and use keystroke's toString as binding link
inputMap.put(pressedKey, pressedKey.toString());
inputMap.put(releasedKey, releasedKey.toString());
// link binding links to our actions
actionMap.put(pressedKey.toString(), pressedAction);
actionMap.put(releasedKey.toString(), releasedAction);
}
}
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(PADDLE_COLOR);
g.fillRoundRect(paddleX, PADDLE_Y, PADDLE_W, PADDLE_H, PADDLE_ARC, PADDLE_ARC);
}
private class TimerListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// if JPanel no longer displayed, stop the Timer
if (!GamePanel2.this.isDisplayable()) {
((Timer) e.getSource()).stop();
}
// here's the key: iterate through the Direction enum
for (Direction direction : Direction.values()) {
// get corresponding boolean from dirMap
// and if true, change location of x and y
if (dirMap.get(direction)) {
int possibleX = paddleX + VEL_X * direction.getDeltaX();
if (direction == direction.RIGHT && possibleX + PADDLE_W <= getWidth()) {
paddleX = possibleX;
}
if (direction == Direction.LEFT && possibleX >= 0) {
paddleX = possibleX;
}
}
}
repaint();
}
}
private class KeyAction extends AbstractAction {
private Direction direction;
private boolean pressed;
public KeyAction(Direction direction, boolean pressed) {
this.direction = direction;
this.pressed = pressed;
}
@Override
public void actionPerformed(ActionEvent e) {
dirMap.put(direction, pressed); // key press simply changes the map, that's it.
}
}
private static void createAndShowGui() {
GamePanel2 mainPanel = new GamePanel2();
JFrame frame = new JFrame("GamePanel2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
enum Direction {
LEFT("Left", KeyEvent.VK_LEFT, -1),
RIGHT("Right", KeyEvent.VK_RIGHT, 1);
private String text;
private int keyValue; // KeyEvent.VK_?
private int deltaX;
Direction(String text, int keyValue, int deltaX) {
this.text = text;
this.keyValue = keyValue;
this.deltaX = deltaX;
}
public String getText() {
return text;
}
public int getKeyValue() {
return keyValue;
}
@Override
public String toString() {
return text;
}
public int getDeltaX() {
return deltaX;
}
}
我希望我的矩形在用户同时按下左右键时停止。我研究了多个密钥处理,但无法找到任何东西。
package View;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GamePanel extends JPanel {
private final int WIDTH = 600, HEIGHT = 500;
// PROPERTIES
private Timer timer;
int x = 0;
int y = 475;
int velX = 0; // only left or right
// CONSTRUCTOR
public GamePanel() {
setSize(WIDTH, HEIGHT);
setBackground(new Color(240, 255, 255));
timer = new Timer(5, new MyTimerListener());
addKeyListener( new MyKeyListener());
setFocusable(true); // for key listening
setFocusTraversalKeysEnabled(false);
timer.start();
}
// METHODS
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor( new Color(201, 51, 51));
g.fillRoundRect(x, y, 80, 20, 15, 15);
}
public class MyTimerListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
if ( x < 0 )
{
velX = 0;
x = 0;
}
if ( x > 520 )
{
velX = 0;
x = 520;
}
x = x + velX;
repaint();
}
}
public class MyKeyListener implements KeyListener {
@Override
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if ( code == KeyEvent.VK_LEFT )
velX = -1;
if ( code == KeyEvent.VK_RIGHT )
velX = 1;
}
@Override
public void keyReleased(KeyEvent e) {
velX = 0;
}
@Override
public void keyTyped(KeyEvent e) {}
}
}
感谢 heeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep
再次说明,使用键绑定而不是 KeyListener。您可能希望对向右和向左箭头键的按键按下和释放使用单独的绑定,并且希望让您的按键绑定操作更改程序状态,这将影响 Swing Timer 如何移动桨。在此示例中(借用我的另一个示例),我创建了一个枚举 Direction 来封装左右方向,并创建了一个 Map<Direction, Boolean>
将布尔值与左右方向相关联。按下右箭头键将更改地图以将 RIGHT 方向与 true
布尔值相关联,而释放键则相反。计时器将轮询地图以查看将桨移动到哪里。例如:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.EnumMap;
import java.util.Map;
import javax.swing.*;
@SuppressWarnings("serial")
public class GamePanel2 extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = 500;
private static final int PADDLE_Y = 475;
private static final int PADDLE_W = 80;
private static final int PADDLE_H = 20;
private static final int PADDLE_ARC = 15;
private static final int TIME_DELAY = 15;
public static final int VEL_X = 2;
private static final Color PADDLE_COLOR = new Color(201, 51, 51);
private int paddleX;
private Timer time = new Timer(TIME_DELAY, new TimerListener());
// key presses and releases will change the boolean values held in this Map
// When an arrow key is pressed, the direction-corresponding boolean is set true
// and likewise when the arrow key is released the direction corresponding boolean is false
private Map<Direction, Boolean> dirMap = new EnumMap<>(Direction.class);
public GamePanel2() {
setKeyBindings();
time.start();
}
private void setKeyBindings() {
int condition = WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();
// iterate through all the Direction enums
for (Direction direction : Direction.values()) {
// set all values to false
dirMap.put(direction, false);
// create two key strokes, one for pressed and one for released
int keyValue = direction.getKeyValue();
KeyStroke pressedKey = KeyStroke.getKeyStroke(keyValue, 0, false);
KeyStroke releasedKey = KeyStroke.getKeyStroke(keyValue, 0, true);
// create two Actions, one for pressed, one for released
Action pressedAction = new KeyAction(direction, true);
Action releasedAction = new KeyAction(direction, false);
// add keystroke to inputMap and use keystroke's toString as binding link
inputMap.put(pressedKey, pressedKey.toString());
inputMap.put(releasedKey, releasedKey.toString());
// link binding links to our actions
actionMap.put(pressedKey.toString(), pressedAction);
actionMap.put(releasedKey.toString(), releasedAction);
}
}
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(PADDLE_COLOR);
g.fillRoundRect(paddleX, PADDLE_Y, PADDLE_W, PADDLE_H, PADDLE_ARC, PADDLE_ARC);
}
private class TimerListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// if JPanel no longer displayed, stop the Timer
if (!GamePanel2.this.isDisplayable()) {
((Timer) e.getSource()).stop();
}
// here's the key: iterate through the Direction enum
for (Direction direction : Direction.values()) {
// get corresponding boolean from dirMap
// and if true, change location of x and y
if (dirMap.get(direction)) {
int possibleX = paddleX + VEL_X * direction.getDeltaX();
if (direction == direction.RIGHT && possibleX + PADDLE_W <= getWidth()) {
paddleX = possibleX;
}
if (direction == Direction.LEFT && possibleX >= 0) {
paddleX = possibleX;
}
}
}
repaint();
}
}
private class KeyAction extends AbstractAction {
private Direction direction;
private boolean pressed;
public KeyAction(Direction direction, boolean pressed) {
this.direction = direction;
this.pressed = pressed;
}
@Override
public void actionPerformed(ActionEvent e) {
dirMap.put(direction, pressed); // key press simply changes the map, that's it.
}
}
private static void createAndShowGui() {
GamePanel2 mainPanel = new GamePanel2();
JFrame frame = new JFrame("GamePanel2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
enum Direction {
LEFT("Left", KeyEvent.VK_LEFT, -1),
RIGHT("Right", KeyEvent.VK_RIGHT, 1);
private String text;
private int keyValue; // KeyEvent.VK_?
private int deltaX;
Direction(String text, int keyValue, int deltaX) {
this.text = text;
this.keyValue = keyValue;
this.deltaX = deltaX;
}
public String getText() {
return text;
}
public int getKeyValue() {
return keyValue;
}
@Override
public String toString() {
return text;
}
public int getDeltaX() {
return deltaX;
}
}