我正在为我的中期项目做空气曲棍球比赛。
我处理两个图形时遇到问题,在这种情况下,两个手柄各有3个圆圈。
由于keyPressed
方法,我只能移动一个句柄。
另一个问题是我无法限制移动域,例如当您按→时,红色手柄可以超出帧宽。
我知道第一个问题与线程有关,但我从上周开始研究这个问题。
我的问题出现在这堂课上:
public class StartGamePanel extends JPanel implements KeyListener, ActionListener {
double xCircle1 = 200;
double yCircle1 = 100;
double xCircle2 = 200;
double yCircle2 = 700;
double velX = 0, velY = 0;
public StartGamePanel() {
Timer t = new Timer(5, this);
t.start();
addKeyListener(this);
setFocusable(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g.setColor(new Color(51, 153, 255));
g.fillRoundRect(5, 5, 485, 790, 10, 10);
addKeyListener(this);
Graphics2D southArc = (Graphics2D) g;
southArc.setColor(Color.WHITE);
southArc.setStroke(new BasicStroke(3));
southArc.drawArc(98, 640, 300, 300, 0, 180);
//
Graphics2D northArc = (Graphics2D) g;
northArc.setColor(Color.WHITE);
northArc.setStroke(new BasicStroke(3));
northArc.drawArc(98, -143, 300, 300, 180, 180);
Graphics2D line = (Graphics2D) g;
line.setStroke(new BasicStroke(3));
line.setColor(Color.white);
line.drawLine(6, 395, 488, 395);
Graphics2D dot = (Graphics2D) g;
dot.setColor(Color.black);
for (int j = 10; j < 800; j += 20) {
for (int i = 6; i < 502; i += 20) {
dot.drawLine(i, j, i, j);
}
}
Graphics2D circle1 = (Graphics2D) g;
circle1.setColor(new Color(255, 51, 51));
Shape theCircle = new Ellipse2D.Double(xCircle1 - 40, yCircle1 - 40, 2.0 * 40, 2.0 * 40);
circle1.fill(theCircle);
Graphics2D circle2 = (Graphics2D) g;
circle2.setColor(new Color(255, 102, 102));
Shape theCircle2 = new Ellipse2D.Double(xCircle1 - 35, yCircle1 - 35, 2.0 * 35, 2.0 * 35);
circle2.fill(theCircle2);
Graphics2D circle3 = (Graphics2D) g;
circle3.setColor(new Color(255, 51, 51));
Shape theCircle3 = new Ellipse2D.Double(xCircle1 - 20, yCircle1 - 20, 2.0 * 20, 2.0 * 20);
circle3.fill(theCircle3);
Graphics2D circleprim = (Graphics2D) g;
circleprim.setColor(new Color(0, 51, 102));
Shape theCircleprim = new Ellipse2D.Double(xCircle2 - 40, yCircle2 - 40, 2.0 * 40, 2.0 * 40);
circleprim.fill(theCircleprim);
Graphics2D circle2prim = (Graphics2D) g;
circle2prim.setColor(new Color(0, 102, 204));
Shape theCircle2prim = new Ellipse2D.Double(xCircle2 - 35, yCircle2 - 35, 2.0 * 35, 2.0 * 35);
circle2prim.fill(theCircle2prim);
Graphics2D circle3prim = (Graphics2D) g;
circle3prim.setColor(new Color(0, 51, 102));
Shape theCircle3prim = new Ellipse2D.Double(xCircle2 - 20, yCircle2 - 20, 2.0 * 20, 2.0 * 20);
circle3prim.fill(theCircle3prim);
Graphics2D ball = (Graphics2D) g;
ball.setColor(new Color(224, 224, 224));
Shape theball = new Ellipse2D.Double(200 - 20, 400 - 20, 2.0 * 20, 2.0 * 20);
ball.fill(theball);
Graphics2D ball2 = (Graphics2D) g;
ball2.setColor(new Color(160, 160, 160));
Shape theball2 = new Ellipse2D.Double(200 - 15, 400 - 15, 2.0 * 15, 2.0 * 15);
ball2.fill(theball2);
Graphics2D goal = (Graphics2D) g;
goal.setColor(Color.BLACK);
goal.fill3DRect(100, 0, 300, 10, true);
Graphics2D goal2 = (Graphics2D) g;
goal2.setColor(Color.BLACK);
goal2.fill3DRect(100, 790, 300, 10, true);
}
@Override
public void actionPerformed(ActionEvent e) {
repaint();
xCircle1 += velX;
yCircle1 += velY;
}
@Override
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if (code == KeyEvent.VK_UP) {
velY = -2;
velX = 0;
}
if (code == KeyEvent.VK_DOWN) {
velY = 2;
velX = 0;
}
if (code == KeyEvent.VK_LEFT) {
if (xCircle1 < 0) {
velY = 0;
velX = 0;
} else {
velY = 0;
velX = -2;
}
}
if (code == KeyEvent.VK_RIGHT) {
if (xCircle1 > 200) {
velY = 0;
velX = 0;
}
velY = 0;
velX = 2;
}
}
@Override
public void keyReleased(KeyEvent e) {
int code = e.getKeyCode();
if (code == KeyEvent.VK_UP) {
velY = 0;
velX = 0;
}
if (code == KeyEvent.VK_DOWN) {
velY = 0;
velX = 0;
}
if (code == KeyEvent.VK_LEFT) {
velY = 0;
velX = 0;
}
if (code == KeyEvent.VK_RIGHT) {
velY = 0;
velX = 0;
}
}
@Override
public void keyTyped(KeyEvent e) { }
}
谢谢!
答案 0 :(得分:1)
您的密钥监听器应尽可能快,以免阻止关键事件发生。由于几个人几乎同时按键,这种情况在游戏中很常见。
所以建议是使用单独的线程来监听按键,这会快速将事件添加到队列中。然后将在EDT(Swing主线程)上处理此队列并绘制结果。
答案 1 :(得分:1)
您可以查看Motion Using The Keyboard中的KeyboardAnimation.java
示例。它试图解释为什么Key Bindings比使用KeyListener更受欢迎。
示例代码将为两个图像设置动画。左图像由W,A,S,D控制,右图像由上,下,左,右箭头键控制。它还将图像保持在窗口范围内。代码不是真正的游戏,它只是为了展示一种使用可配置键绑定的方法。
答案 2 :(得分:0)
您可能还想更改按键的处理方式。目前(我认为)你一次只能检测到一个键。
您可能需要为“holdkeys”创建一个数组,并且每次键都关闭时,添加到该数组。释放密钥后,从中减去该密钥。
然后,每隔一段时间,检查“holdkeys”数组中的哪些键并对其进行操作。 至少,如果你计划有两名球员,你可能需要这样的东西。 (谁都应该能够同时按键)。
我不知道Swing是否足以为您提供准确的代码,但它会是类似的;
//an array of numbers to hold the key-codes of the keys currently held down
HashSet<Integer> HeldKeys = new HashSet<Integer>();
@Override
public void keyDown(KeyEvent e) {
// add key to keys currently held down
HeldKeys.add(e.getKeyCode());
}
@Override
public void keyUp(KeyEvent e) {
//remove key from list of things currently held
HeldKeys.remove(e.getKeyCode());
}
@Override
public void keyPress(KeyEvent e) {
Iterator<Integer> kit = HeldKeys.iterator();
//we loop over every key currently held down, running actions for them if
//there is any assigned.
//For example, one button might move a sprite on the left down
//Another might move a sprite on the right. One, the other, or both should be
//able to all move without waiting for the other.
while (kit.hasNext()) {
int keycode = kit.next();
if (keycode==48){
//do stuff if key with code 48 is held
//(move one of the circles, etc)
}
if (keycode==46){
//do stuff if key with code 46 is held
}
//...etc, for any number of keys you want to do different things for.
}
}
请注意;使用此方法,您不会检测到按键是一回事,而是检测按下的键,然后将键作为单独的事件释放。 由于人们不会在同一时间点击按键,因此可以让您同时检测到许多按键。
这段代码是我的头脑,Java,但我有一个gwt背景,所以“keydown”和“keyup”等的名称可能会有所不同。 gwt中的“keypress”事件将自动重复,如果在Swing中不是这种情况,则可能需要使用Timer,而不是间隔运行。 (你可能更喜欢这个,因为它更可控)。