2013-03-12 89 views
0

我想編寫一個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 

    } 

} 

我將如何使它所以用戶可以看到子彈向上行進時,從你火的屏幕?

回答

3

你碰上了「阻塞事件調度線程」的問題,這似乎是一個非常普遍的問題在這裏....

而這種代碼執行

基本上....

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