2014-12-07 34 views
0

我想創建一個基本的項目符號動畫,當按下空格鍵時,計時器會關閉,大約每秒鐘將項目符號的y值增加100。然而,當我按空格鍵時,沒有任何東西出現,就好像子彈沒有得到它的y座標。這一切都發生在一個while循環內,當子彈熄滅屏幕時使用計時器的基本java項目符號動畫

Timer t = new Timer(); 

if (e.getKeyCode() == KeyEvent.VK_SPACE) { 
    bullet.x = 100; 
    while (bullet.y<400) { 
     t.schedule(new TimerTask() { 
      @Override 
      public void run() { 
       bullet.y = bullet.y + 100; 
      } 
     }, 800); 
    } 
} 
+0

使用keyblind不是awt keyevents.because子彈需要重點來聽awt keyevent.put內keyaction並看到它沒有得到打印 – 2014-12-07 17:32:45

+0

感謝您的輸入,不太明白,雖然 – wilkers 2014-12-07 17:46:33

+0

1-使用擺動計時器,因爲它在事件分派線程的上下文中觸發它的更新; 2-調用repaint觸發和uodate; 3-考慮使用密鑰綁定API而不是KeyListener – MadProgrammer 2014-12-07 21:10:08

回答

1

我把一個基本的子彈示範。

子彈(橢圓形)從左到右(x座標)以每秒100像素的速度移動。當您按下空格鍵時,將從x = 20像素和隨機的y座標中觸發子彈。子彈從繪圖面板右邊緣消失20個像素。

Bullet Demonstration

我用model/view/controller pattern把這個演示起來。我編寫了2個模型類,2個視圖類,2個控制器類和一個類來啓動Java Swing應用程序。

第一個類BulletDemo啓動Java Swing應用程序。

package com.ggl.bullet; 

import javax.swing.SwingUtilities; 

import com.ggl.bullet.model.BulletDemoModel; 
import com.ggl.bullet.view.BulletDemoFrame; 

public class BulletDemo implements Runnable { 

    @Override 
    public void run() { 
     new BulletDemoFrame(new BulletDemoModel()); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new BulletDemo()); 
    } 

} 

Swing packed goodness的19行。這個類做了3件事情來啓動Swing應用程序。

  1. 通過對SwingUtilities invokeLater方法的調用,在Event Dispatch thread(EDT)上放置Swing應用程序。
  2. 實例化子彈演示模型。
  3. 實例化子彈演示框架。

接下來,我們來看看BulletDemoModel類。

package com.ggl.bullet.model; 

import java.awt.Dimension; 
import java.awt.Graphics; 
import java.util.ArrayList; 
import java.util.List; 

public class BulletDemoModel { 

    private int panelWidth = 600; 
    private int panelHeight = 300; 

    private List<Bullet> bullets; 

    public BulletDemoModel() { 
     this.bullets = new ArrayList<Bullet>(); 
    } 

    public Dimension getPanelDimension() { 
     return new Dimension(panelWidth, panelHeight); 
    } 

    public int getPanelWidth() { 
     return panelWidth; 
    } 

    public int getPanelHeight() { 
     return panelHeight; 
    } 

    public void addBullet(Bullet bullet) { 
     this.bullets.add(bullet); 
    } 

    public void removeBullets() { 
     for (int i = bullets.size() - 1; i >= 0; i--) { 
      if (!bullets.get(i).onScreen()) { 
       bullets.remove(i); 
      } 
     } 
    } 

    public void moveBullets(int time) { 
     for (Bullet bullet : bullets) { 
      bullet.moveBullet(time); 
     } 
    } 

    public void draw(Graphics g) { 
     for (Bullet bullet : bullets) { 
      bullet.draw(g); 
     } 
    } 

} 

該類保留了我們稍後討論的繪圖面板的寬度和高度。這個班也跟蹤子彈。子彈可以添加,移動和刪除。

繪製方法包含在模型中,因爲繪製對象更容易。繪製方法作爲視圖的一部分執行,所以我們仍然有一個關注點分離。

接下來,我們來看看另一個模型類Bullet。

package com.ggl.bullet.model; 

import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.geom.Point2D; 

public class Bullet { 

    private int maxX; 

    private Point2D location; 

    public Bullet(Point2D location, int maxX) { 
     this.location = location; 
     this.maxX = maxX; 
    } 

    public void moveBullet(int time) { 
     double x = this.location.getX(); 
     double y = this.location.getY(); 

     x += 100D * (double) time/6000D; 

     this.location.setLocation(x, y); 
    } 

    public boolean onScreen() { 
     int x = (int) Math.round(this.location.getX()); 
     return x < maxX; 
    } 

    public void draw(Graphics g) { 
     int x = (int) Math.round(this.location.getX()); 
     int y = (int) Math.round(this.location.getY()); 

     if (onScreen()) { 
      g.setColor(Color.BLACK); 
      g.fillOval(x, y, 10, 10); 
     } 
    } 

} 

該類封裝了與子彈有關的字段和方法。

接下來,我們將看看視圖類,從BulletDemoFrame類開始。

package com.ggl.bullet.view; 

import java.awt.event.WindowAdapter; 
import java.awt.event.WindowEvent; 

import javax.swing.InputMap; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.KeyStroke; 

import com.ggl.bullet.controller.BulletRunnable; 
import com.ggl.bullet.controller.ShootBulletAction; 
import com.ggl.bullet.model.BulletDemoModel; 

public class BulletDemoFrame { 

    private BulletDemoModel model; 

    private BulletRunnable bulletRunnable; 

    private DrawingPanel drawingPanel; 

    private JFrame frame; 

    public BulletDemoFrame(BulletDemoModel model) { 
     this.model = model; 
     createPartControl(); 
    } 

    private void createPartControl() { 
     drawingPanel = new DrawingPanel(model); 

     frame = new JFrame(); 
     frame.setTitle("Bullet Demo"); 
     frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); 
     frame.addWindowListener(new WindowAdapter() { 
      @Override 
      public void windowClosing(WindowEvent event) { 
       exitProcedure(); 
      } 
     }); 

     setKeyBindings(); 

     JPanel mainPanel = new JPanel(); 
     mainPanel.add(drawingPanel); 

     frame.add(mainPanel); 
     frame.setLocationByPlatform(true); 
     frame.pack(); 
     frame.setVisible(true); 

     this.bulletRunnable = new BulletRunnable(this, model); 
     new Thread(bulletRunnable).start(); 
    } 

    private void setKeyBindings() { 
     InputMap inputMap = drawingPanel 
       .getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW); 
     inputMap.put(KeyStroke.getKeyStroke("SPACE"), "shoot bullet"); 

     inputMap = drawingPanel.getInputMap(JPanel.WHEN_FOCUSED); 
     inputMap.put(KeyStroke.getKeyStroke("SPACE"), "shoot bullet"); 

     drawingPanel.getActionMap().put("shoot bullet", 
       new ShootBulletAction(model)); 
    } 

    public void exitProcedure() { 
     bulletRunnable.setRunning(false); 
     frame.dispose(); 
     System.exit(0); 
    } 

    public void repaintDrawingPanel() { 
     drawingPanel.repaint(); 
    } 

} 

注意我們如何使用JFrame。我們不擴展Swing組件或任何Java類,除非我們想重寫其中一個類方法。

createPartControl方法主要是樣板,適用於幾乎所有的Swing應用程序。

setKeyBindings方法是我們將空格鍵設置爲ShootBulletAction類的地方,我們將在後面討論它。

windowListener和exitProcedure允許我們在退出之前停止子彈線程。

接下來,我們將看看DrawingPanel類。

package com.ggl.bullet.view; 

import java.awt.Graphics; 

import javax.swing.JPanel; 

import com.ggl.bullet.model.BulletDemoModel; 

public class DrawingPanel extends JPanel { 

    private static final long serialVersionUID = 6510468728309920700L; 

    private BulletDemoModel model; 

    public DrawingPanel(BulletDemoModel model) { 
     this.model = model; 
     this.setPreferredSize(model.getPanelDimension()); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     model.draw(g); 
    } 

} 

這裏沒有太多,因爲所有的繪圖代碼都在模型中。

我們擴展了JPanel,所以我們可以覆蓋paintComponent方法。在paintComponent方法中,我們調用super方法,然後重繪整個面板。做得這麼快就會產生動畫幻覺。

接下來,我們來看看控制器類。我們先看看ShootBulletAction類。

package com.ggl.bullet.controller; 

import java.awt.event.ActionEvent; 
import java.awt.geom.Point2D; 
import java.util.Random; 

import javax.swing.AbstractAction; 

import com.ggl.bullet.model.Bullet; 
import com.ggl.bullet.model.BulletDemoModel; 

public class ShootBulletAction extends AbstractAction { 

    private static final long serialVersionUID = -5783106403902351044L; 

    private BulletDemoModel model; 

    private Random random; 

    public ShootBulletAction(BulletDemoModel model) { 
     this.model = model; 
     this.random = new Random(); 
    } 

    @Override 
    public void actionPerformed(ActionEvent event) { 
     double x = 20D; 
     double y = (double) random.nextInt(model.getPanelHeight() - 20) + 10; 
     Bullet bullet = new Bullet(new Point2D.Double(x, y), 
       model.getPanelWidth() - 20); 
     model.addBullet(bullet); 
    }  

} 

這個班每次按下空格鍵都會創建一個子彈。

最後,我們來看看BulletRunnable類。

package com.ggl.bullet.controller; 

import javax.swing.SwingUtilities; 

import com.ggl.bullet.model.BulletDemoModel; 
import com.ggl.bullet.view.BulletDemoFrame; 

public class BulletRunnable implements Runnable { 

    private volatile boolean running; 

    private long sleepTime = 100L; 

    private BulletDemoFrame frame; 

    private BulletDemoModel model; 

    public BulletRunnable(BulletDemoFrame frame, BulletDemoModel model) { 
     this.frame = frame; 
     this.model = model; 
    } 

    @Override 
    public void run() { 
     running = true; 

     while (running) { 
      model.moveBullets((int) sleepTime); 
      redraw(); 
      sleep(); 
     } 
    } 

    private void sleep() { 
     try { 
      Thread.sleep(sleepTime); 
     } catch (InterruptedException e) { 

     } 
    } 

    private void redraw() { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       frame.repaintDrawingPanel(); 
      } 
     }); 
    } 

    public synchronized void setRunning(boolean running) { 
     this.running = running; 
    } 

} 

該類是基本的更新模型,繪製模型,控制大多數動畫的睡眠循環。

我們以每秒10幀的速度運行,這有點波動。如果你願意,你可以睡更少的時間,每秒運行更多幀。

我知道這是一個很長的答案,但這是你如何在Swing中做基本的動畫。謝謝閱讀。

+0

我爲該程序添加了一個下載鏈接:http://s000.tinyupload.com/index.php?file_id=01247857767704445193 – 2014-12-07 23:37:05

+0

爲什麼不是這個答案獲得了投票先前? – 2017-07-28 01:41:34