簡體   English   中英

如何使用計時器重畫一些擺動組件

[英]How to use a timer to repaint some swing components

介紹

大家好,我正在學習如何制作一個球拍(矩形)而所有小行星(敵人)掉落在屏幕上的小游戲,您必須避免它們

問題

當游戲開始時,敵人(小行星)以很高的速度在屏幕上繪制,並且它們占據了屏幕的所有大小,因此沒有辦法避免它們(嘗試游戲),我只想在繪制一個敵人和下一個敵人有最短延遲時間(例如0.5秒)。 但我只是不知道該怎么做,我嘗試使用Thread.sleep()和TimeUnit,但它們只會使游戲變慢。 在stackoverflow上沖浪時,我發現我可能會嘗試使用Swing計時器,我已經在網上閱讀了一些內容,但是我想知道如何在代碼中使用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);
    }
}

建議:

  1. 您的游戲“滴答”時間為5毫秒,這不是很合理的時間。 我建議
    • 您可以改用常數來擺脫“魔術”數,
    • 並增加tic的大小,例如12至15毫秒。
    • 也最好使用Swing計時器,或者至少確保您在定義的后台線程中執行while循環。
  2. 最重要的是,您要在游戲循環的每一刻創建一個新敵人,這太快了。 代替:
    • 不要在每次打勾時都創建一個新的敵人,
    • 而是節省了在田間創建最后一個敵人的時間,
    • 在游戲循環中檢查時間增量, current system time - lastEnemyCreationTime
    • 僅當增量時間大於合理值(恆定值或字段(不是幻數))時,才創建新敵人。
    • 創建新敵人時,將lastEnemyCreationTime重置為當前系統時間。

不相關的記錄:

  1. 重寫JPanel的paintComponent ,而不是paint方法,因為默認情況下,這將為您提供雙緩沖,這可以使圖形更流暢。
  2. 支持在KeyListener上使用Key Bindings,因為這將有助於輕松消除使用KeyListeners固有的焦點問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM