我正在开发一个游戏,该游戏的玩家希望使用WASD进行移动。我决定使用键绑定,以尝试解决我与键侦听器有关的问题,即使切换到键绑定后,该问题现在仍在发生。问题是,即使按下这些键正在移动播放器,但在移动播放器几次之后,输入几乎完全停止工作。发生这种情况时,可能只有1/10键按下才能移动播放器。我可能做错了什么?任何帮助将不胜感激。
这是我游戏的主要绑定类: (让我知道是否应发布其余代码)
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);
}
}
答案 0 :(得分:1)
关于“为什么”您遇到问题,我只能猜测,因为我们只有一个上下文外代码段可以处理,但是,有很多事情可以改进,这可能会有所帮助解决问题。
WHEN_IN_FOCUSED_WINDOW
在致电getInputMap
这将上下文应用于实际触发按键事件的时间,在上述情况下,无论窗口哪个具有焦点,无论当前哪个组件具有键盘焦点,按键事件都会被触发。
paintComponent
上优先覆盖paint
Swing中的绘画有些复杂,作为一般建议,当您要执行自定义绘画时,最好覆盖paintComponent
。一个不错的副作用是,它将为您绘制组件的背景颜色,这是您要做的一件事;)
getPreferredSize
覆盖getWidth
和getHeight
不会引起任何可能的问题,最好避免。相反,以这种方式覆盖getPreferredSize
,您将参与布局API并获得其所有优点,例如能够在pack
上调用JFrame
并使其得到照顾奇怪的是围绕着框架装饰。
好意思的“解耦代码”。在您的代码中,播放器的状态可以通过按键操作直接更改。这不仅是一个坏主意,它还会产生意想不到的副作用,并且随着需求变得越来越复杂,变得越来越难以管理。这也使得很难改变输入的方式。例如,您可以包括不同的输入法,例如操纵杆,但是您必须为其编写相同的代码。
相反,您应该简单地使用一个“状态管理器”来承载输入的当前状态,当您的“主循环”准备就绪时,它将作为单独的步骤将该状态应用于模型。
“主循环”不在乎状态如何更新,只是它可以获取决定如何应用状态所需的信息。
下面是我上面讨论的所有内容的一个粗略示例,在测试中,绑定“ stalling”没有问题
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
中放置一堆“标志”