我正在尝试编写一个Space Invader游戏,以提升我在AP计算机科学中学到的技能。我遇到了一个问题。当我按空格键(开火按钮)时,无法看到前往顶部的子弹动画。相反,子弹只会出现在屏幕顶部,从那里开始射击。这是包含子弹触发的代码:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
import javax.swing.Timer;
public class AlienInvader extends JPanel implements KeyListener, ActionListener {
Constants constant = new Constants();
Timer timer = new Timer(5, this);
Sprite images = new Sprite();
public void update() {
timer.start();
images.loadImage();
addKeyListener(this);
setFocusable(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, 500, 500);
g.drawImage(images.spaceship, constant.x, constant.y, null);
g.drawImage(images.bullet, constant.bulletx, constant.bullety, null);
}
@Override
public void keyPressed(KeyEvent e) {
System.out.println(constant.x);
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT:
constant.xvel = -1 * constant.STEP;
repaint();
break;
case KeyEvent.VK_RIGHT:
constant.xvel = 1 * constant.STEP;
repaint();
break;
case KeyEvent.VK_SPACE:
constant.xvel = 0;
constant.bulletx = constant.x;
constant.bullety = constant.y;
while (constant.bullety > 0) {
constant.bullety = constant.bullety - 1;
repaint();
}
}
constant.x += constant.xvel;
}
@Override
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT:
constant.xvel = -1;
break;
case KeyEvent.VK_RIGHT:
constant.xvel = 1;
break;
}
}
@Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
我如何制作它以便用户可以看到当你开火时子弹在屏幕上移动?
答案 0 :(得分:3)
您已经遇到阻止事件调度线程""问题,这似乎是一个非常普遍的问题....
基本上这个代码正在执行....
while (constant.bullety > 0) {
constant.bullety = constant.bullety - 1;
repaint();
}
无法绘制任何内容,因为您正在阻止负责处理重新绘制的线程。
repaint
是一个请求重绘管理器更新屏幕上的部分的请求。重绘管理器是为性能而设计的,所以它会尝试将所有各种重绘请求折叠成尽可能少的调用,然后在事件调度线程上添加重绘请求....
所以,当你阻止EDT时,什么都不能重新粉刷。
请查看Concurrency in Swing和Painting in AWT and Swing了解详情。
现在,找到解决方案。
有很多方法可以实现这一目标。一般来说,你需要某种"引擎"或"控制器"能够运行背景,更新游戏中的各种对象并将结果呈现给屏幕。
这提出了许多重要问题。首先,必须在EDT的上下文中执行与UI的所有交互。这意味着,您永远不应该从EDT外部创建或更新任何UI组件。
第二个是确保你不会改变渲染器所依赖的游戏模型的任何部分(因为你实际上并没有控制重绘过程)。
这个最简单的解决方案是使用BufferedImage
,您可以将其绘制到它(在背景Thread
内)。
这将允许您更新游戏模型,将结果呈现给后备缓冲区,将该缓冲区重新同步到UI,然后稍微等待以允许UI时间赶上。简单:D