Java Space Invader子弹运动

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 SwingPainting in AWT and Swing了解更多详情。

现在来解决。

有很多方法可以做到这一点。一般而言,您需要某种能够运行背景的“引擎”或“控制器”,更新游戏中的各种对象并将结果呈现在屏幕上。

这提出了一些重要的问题。首先,与用户界面的所有交互都必须在EDT的背景下执行。这意味着,您绝不应该创建或更新EDT之外的任何UI组件。

第二种方法是确保您不会改变渲染器所依赖的游戏模型的任何部分(因为您实际上不控制重绘过程)。

最简单的解决方案是使用BufferedImage,您可以在其中绘制(在背景Thread内)。

这将允许您更新游戏模型,将结果呈现给后台缓冲区,将该缓冲区重新同步到UI,然后稍微等待以允许UI时间赶上。简单:D

+0

您是否想说我需要使用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

+0

不,我是说,你需要使用至少两个'BufferedImage's向渲染你整场比赛状态。一个将被渲染器用于屏幕(通过一种“paint”方法),另一个将被游戏线程引擎用来更新世界上所有对象的状态。然后你会交换引用,这意味着当你更新游戏状态时,任何由Swing绘制的东西都不会过早渲染。 – MadProgrammer 2013-03-12 02:52:12