2016-05-18 84 views
1

介紹如何使用計時器重繪一些Swing組件

嗨,大家好,我正在學習如何做一個小遊戲,你是一個球拍(矩形)和所有的小行星(敵人)都掉下屏幕你必須避免他們

問題

當比賽開始的敵人(小行星)是在一個非常高的速度在屏幕上的油漆,他們佔據了屏幕的全尺寸,所以沒有辦法避免它們(嘗試遊戲),我只是想在畫一個敵人和下一個敵人之間有一個最小時間延遲(例如0,5秒DS)。 但我只是不知道該怎麼做,我試圖使用Thread.sleep()和TimeUnit,但他們只是讓遊戲變得更慢。 在stackoverflow上衝浪我發現我可能會嘗試使用Swing計時器,我已經閱讀了網上的一些內容,但我想知道如何在代碼中使用搖擺計時器(如果它們可以解決我的問題)。

這是代碼: 主類:

import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.RenderingHints; 
import java.awt.event.KeyEvent; 
import java.awt.event.KeyListener; 
import java.util.ArrayList; 
import java.util.Random; 
import java.util.concurrent.TimeUnit; 
import javax.swing.JFrame; 
import javax.swing.JOptionPane; 
import javax.swing.JPanel; 
import javax.swing.Timer; 

@SuppressWarnings("serial") 
public class Game extends JPanel { 

    Racquet racquet = new Racquet(this); 
    Enemy Enemy = new Enemy(this); 

    static ArrayList<Enemy> enemyList = new ArrayList<Enemy>(); 


    public Game() { 
     addKeyListener(new KeyListener() { 
      @Override 
      public void keyTyped(KeyEvent e) { 
      } 

      @Override 
      public void keyReleased(KeyEvent e) { 
       racquet.keyReleased(e); 
      } 

      @Override 
      public void keyPressed(KeyEvent e) { 
       racquet.keyPressed(e); 
      } 
     }); 
     setFocusable(true); 
    } 

    /** TO SET THE RANDOM POSITION ON WHERE THE ENEMIES HAVE TO APPEAR ON THE SCREEN **/ 
    public int random(int x, int y, ArrayList<Enemy> pa){ 
     int r = 0; 

     for(int i = 0; i<pa.size(); i++){ 
      Random rand = new Random(); 
      r = rand.nextInt(x+y)-1;     
      return r; 
     } 

     return r; 
    } 

    /** letting the enemies move on the screen **/ 
    private void move() { 
     for(int i = 0; i < enemyList.size(); i++){ 
      enemyList.get(i).move(); 
     } 

     racquet.move();   
    } 

    /** Painting on the screen enemies and the racquet **/ 
@Override 
    public void paint(Graphics g) { 
     super.paint(g); 
     Graphics2D g2d = (Graphics2D) g; 
     g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 

     for(int i = 0; i < enemyList.size(); i++){ 
      enemyList.get(i).paint(g2d); 
     } 
     racquet.paint(g2d); 
    } 

    public void gameOver() { 
     JOptionPane.showMessageDialog(this, "Game Over", "Game Over", JOptionPane.YES_NO_OPTION); 
     System.exit(ABORT); 
    } 

    public void createEnemy(){ 
     enemyList.add(new Enemy(this)); 
    } 

    public static void main(String[] args) throws InterruptedException { 
     JFrame frame = new JFrame("Asteroids"); 
     Game game = new Game(); 
     frame.add(game); 
     frame.setSize(300, 400); 
     frame.setVisible(true); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     game.random(200, 300, enemyList); 

     while (true) { 
      game.createEnemy(); 
      game.move(); 
      game.repaint(); 
      Thread.sleep(5); 
     } 
    } 
} 

球拍類:

import java.awt.Graphics2D; 
import java.awt.Rectangle; 
import java.awt.event.KeyEvent; 

public class Racquet { 
    private static final int Y = 330; 
    private static final int WIDTH = 30; 
    private static final int HEIGHT = 6 ; 
    int x = 0; 
    int xa = 0; 
    private Game game; 

    public Racquet(Game game) { 
     this.game = game; 
    } 

    /** letting the racquet moves on the screen **/ 
    public void move() { 
     if (x + xa > 0 && x + xa < game.getWidth() - WIDTH) 
      x = x + xa; 
    } 

    /** Creating the rectangle racquet **/ 
    public void paint(Graphics2D g) { 
     g.fillRect(x, Y, WIDTH, HEIGHT); 
    } 

    /** // Setting xa everytime to 0, if we don't do this it just takes a single pression to go to a direction until we press the other key **/ 
    public void keyReleased(KeyEvent e) { 
     xa = 0; 
    } 

    /** Choosing the direction **/ 
    public void keyPressed(KeyEvent e) { 
     if (e.getKeyCode() == KeyEvent.VK_LEFT) 
      xa = -1; 
     if (e.getKeyCode() == KeyEvent.VK_RIGHT) 
      xa = 1; 
    } 


    public Rectangle getBounds() { 
     return new Rectangle(x, Y, WIDTH, HEIGHT); 
    } 

    public int getTopY() { 
     return Y; 
    } 
} 

和敵人類:

import java.awt.Graphics2D; 
import java.awt.Rectangle; 
import java.util.*; 

public class Enemy { 

    private Game game; 
    int x = 0; 
    int y = 0; 
    int xa = 1; 
    int ya = 1; 

    /** Generating a random position where the enemies have to appear **/ 
    public Enemy(Game game){ 
     this.game = game; 
     x = game.random(0, 320, game.enemyList); 
    } 

    /** Paint the enemies **/ 
    public void paint(Graphics2D g) { 
     g.fillRect(x, y, 20, 20); 
    } 

    /** move the enemies and detect collisions **/ 
    public void move(){ 
     y += ya; 
     if(collision()){ 
      game.gameOver(); 
     } 
    } 

    /** returns true if the enemy rectangle touch the racquet **/ 
    public boolean collision(){ 
     return game.racquet.getBounds().intersects(getBounds()); 
    } 

    public Rectangle getBounds() { 
     return new Rectangle(x, y, 20, 20); 
    } 
} 

回答

2

建議:

  1. 你的遊戲「打勾」時間是5 mSecs,這是一個不太合理的時間。我建議
    • 你擺脫「神奇」號,用一個常量,
    • ,使抽動大一點,比如說12至15毫秒。
    • 還更好地使用Swing Timer或至少確保您在定義的後臺線程中執行while循環。
  2. 最重要的是,你正在用遊戲循環中的每個勾號創建一個新的敵人,這太快了。相反:
    • 不要創建每個刻度一個新的敵人,
    • 而是保存最後的敵人在田地創建時間,
    • 檢查增量時,current system time - lastEnemyCreationTime,裏面你遊戲循環,
    • 如果德爾塔時間大於一個合理的值,一個常數值或一個字段(而不是一個幻數),那麼只會創建一個新的敵人。
    • 創建新敵人時,將lastEnemyCreationTime重置爲當前系統時間。

相依倫理委員會:

  • 覆蓋Jpanel的paintComponent,而不是paint方法,因爲這將會給你默認雙緩衝,其可導致更平滑的感知圖形。
  • 在KeyListener上使用鍵綁定很有用,因爲這將有助於輕鬆消除使用KeyListeners時固有的焦點問題。
  • +0

    首先感謝您的回答,但我有些疑惑: 1 - 我怎麼能在我的代碼使用擺動計時器,我的意思是,我已經把/使用它呢?我如何使用它?我在谷歌搜索,但我不明白 2 - 我怎樣才能保存最後一個敵人在一個領域創建的時間?我必須寫在我的代碼中? 3 - 你是什麼意思的「魔術」號碼? – Hoffman

    +0

    @霍夫曼:這裏是[魔術數字]的鏈接(http://stackoverflow.com/questions/47882/what-is-a-magic-number-and-why-is-it-bad)。至於「在哪裏放置代碼」最好先檢查一下教程,然後嘗試先自己弄清楚 - 你會學到更多這樣做。如果仍然卡住,編輯您的問題,顯示您的最新嘗試,並告訴您有問題。請注意儘量一次只修復一個問題。 –

    +0

    我刪除了所有的魔法數字,我使用擺動計時器解決了問題,它似乎工作:D謝謝 – Hoffman