我正在开发一个游戏,它有一个玩家,我想使用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);
}
}发布于 2018-12-09 08:16:10
至于“为什么”你有问题,我只能猜测,因为我们只有一个脱离上下文的片段要处理,然而,有许多事情可以改进,这可能有助于解决问题。
调用getInputMap时的
WHEN_IN_FOCUSED_WINDOW这适用于何时实际触发按键事件的上下文,在上述情况下,无论当前哪个组件具有键盘焦点,只要窗口有焦点,就会触发按键事件。
与paint相比,
paintComponentSwing中的绘画有些复杂,正如一般建议的那样,当你想要执行自定义绘画时,最好覆盖paintComponent。这样做的一个很好的副作用是,它将为您的组件绘制背景颜色,您需要做的事情就少了一件;)
当您需要为
首选覆盖getPreferredSize
覆盖getWidth和getHeight将会导致无休止的问题,最好避免。相反,覆盖getPreferredSize,这样,您就参与到了布局应用程序接口中,并获得了它的所有优势,例如能够在JFrame上调用pack,并让它处理围绕框架装饰的所有奇怪之处。
“解耦你的代码”这句话用得很好。在您的代码中,播放器的状态直接由按键操作更改。这不仅是一个糟糕的想法,而且可能会产生意想不到的副作用,并且随着需求变得越来越复杂,管理也会变得越来越困难。这也使得改变输入的方式变得困难。例如,您可以包含不同的输入方法,例如操纵杆,但是您必须为它编写相同的代码。
相反,你应该有一个简单的“状态管理器”,它携带输入的当前状态,当你的“主循环”准备好时,它会将该状态作为单独的步骤应用到模型中。
“主循环”并不关心状态是如何更新的,只关心它可以获得所需的信息来决定如何应用它。
下面是我上面讨论的所有内容的粗略示例,在我的测试中,我没有遇到绑定“拖延”的问题。
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中放置一堆“标志”
https://stackoverflow.com/questions/53687927
复制相似问题