Java Space Invader子弹运动
问题描述:
我想编写一个Space Invader游戏来刷新我在AP计算机科学中学到的技能。我遇到了一个问题。当我按下空格键(火按钮)时,顶部的子弹动画不可见。相反,子弹刚刚出现在屏幕的顶部,从你开枪的地方。这是一个包含了子弹的击发代码:Java Space Invader子弹运动
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
}
}
我将如何使它所以用户可以看到子弹向上行进时,从你火的屏幕?
答
你碰上了“阻塞事件调度线程”的问题,这似乎是一个非常普遍的问题在这里....
而这种代码执行基本上....
while (constant.bullety > 0) {
constant.bullety = constant.bullety - 1;
repaint();
}
没有东西可以被绘制,因为你阻塞负责处理重绘的线程。
A repaint
是一个要求重绘管理器更新屏幕上的一部分。重绘管理器是为了性能而设计的,因此它会尝试将所有重绘请求折叠成尽可能少的呼叫,然后在重新分配线程上添加重绘请求....
所以,当你'阻止美国东部时间,没有东西可以重新粉刷。
查看Concurrency in Swing和Painting in AWT and Swing了解更多详情。
现在来解决。
有很多方法可以做到这一点。一般而言,您需要某种能够运行背景的“引擎”或“控制器”,更新游戏中的各种对象并将结果呈现在屏幕上。
这提出了一些重要的问题。首先,与用户界面的所有交互都必须在EDT的背景下执行。这意味着,您绝不应该创建或更新EDT之外的任何UI组件。
第二种方法是确保您不会改变渲染器所依赖的游戏模型的任何部分(因为您实际上不控制重绘过程)。
最简单的解决方案是使用BufferedImage
,您可以在其中绘制(在背景Thread
内)。
这将允许您更新游戏模型,将结果呈现给后台缓冲区,将该缓冲区重新同步到UI,然后稍微等待以允许UI时间赶上。简单:D
您是否想说我需要使用BufferedImage才能将图像添加到控制台?我已经做到了。这里是代码: import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio。ImageIO的; 公共类精灵{ \t \t BufferedImage spaceship,bullet; \t \t公共无效的LoadImage(){ \t \t尝试{ \t \t \t飞船= ImageIO.read(新文件( “spaceship.png”)); \t \t \t bullet = ImageIO.read(new File(“bullet.png”)); \t \t}赶上(IOException的发送){ \t \t \t // TODO自动生成的catch程序块 \t \t \t e.printStackTrace(); \t \t} \t} } – user1881401 2013-03-12 02:43:31
不,我是说,你需要使用至少两个'BufferedImage's向渲染你整场比赛状态。一个将被渲染器用于屏幕(通过一种“paint”方法),另一个将被游戏线程引擎用来更新世界上所有对象的状态。然后你会交换引用,这意味着当你更新游戏状态时,任何由Swing绘制的东西都不会过早渲染。 – MadProgrammer 2013-03-12 02:52:12