簡體   English   中英

如何使用Swing組件向JLabel添加刷新計時器

[英]How could I add a refreshing timer to a JLabel using swing components

我正在創建一個迷宮游戲,並希望在gameStage上顯示一個計時器。 我嘗試使用java.util,但它需要我擺脫揮桿計時器。我該如何為游戲添加刷新計時器

此代碼用於制作包含按鈕窗格和gameStage的游戲框架。

import java.awt.CardLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.HashSet;
import java.util.Set;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

/**
 * This class Holds the game pane that has the moving player. It also contains
 * the GamePane
 * 
 * @author 602052004
 *
 */

public class GamePane extends JPanel implements ActionListener, KeyListener {// *change
                                                                                // GamePane
                                                                                // to
                                                                                // GamePane
    // This is were the game screen is made and the player is created.

    static final long serialVersionUID = 1L;
    JLabel player = new JLabel();
    JLabel finish = new JLabel();
    JFrame gameFrame;
    int playerSpeed = 4;
    int FPS = 40;
    // This array holds my JLabels for the walls.I used it so that i can have a
    // for loop with an index for the labels.
    JLabel[] walls = new JLabel[3];
    {

        walls[0] = new JLabel();
        walls[1] = new JLabel();
        walls[2] = new JLabel();

    }
    private final Set<Integer> keys = new HashSet<>();

    // The keys set holds the keys being pressed

    public static void main(String[] args) {
        // Open the GUI window
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                // Create a new object and
                // run its go() method
                new GamePane().go();
            }
        });
    }

    GamePane() {
        // Run the parent class constructor
        super();
        // Allow the panel to get focus
        setFocusable(true);
        // Don't let keys change the focus

    }

    /**
     * This method creates the gameFrame and sets its layout to a cardlayout.It
     * then proceeds the set up the GameFrame.The gameFrame contains the button
     * pane and the gameStage
     * 
     * The walls are an array and are used to create an index which is then used
     * for the collisions.I set up the walls location here
     */
    protected void go() {
        setLayout(new CardLayout());
        // Setup the window
        gameFrame = new JFrame();
        // Add this panel to the window
        gameFrame.setLayout(new CardLayout());
        gameFrame.add(this, "main");
        gameFrame.setContentPane(this);

        // Set's the window properties
        gameFrame.setTitle("main");
        gameFrame.setSize(800, 600);
        gameFrame.setResizable(false);
        gameFrame.setLocationRelativeTo(null);
        gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        gameFrame.setVisible(true);
        gameFrame.add(new ButtonPane(gameFrame), "buttons");
        // Creates the new JPanel that will hold the game.
        JPanel gamestage = new JPanel();
        gamestage.setBackground(Color.darkGray);
        gameFrame.add(gamestage, "game");
        gamestage.setLayout(null);
        // *Move the setup of the player and the timer under the walls
        // Get a sample of collisions going so that i can do it over the weekend
        // Setup the movable box
        player.setBounds(25, 25, 20, 20);
        player.setVisible(true);
        player.setBackground(Color.red);
        // Opaque makes the background visible
        player.setOpaque(true);

        // Setup the key listener
        addKeyListener(this);
        // Null layout allows moving objects!!!
        gamestage.add(player);
        // Set the timer
        Timer tm = new Timer(1000 / FPS, this);
        tm.start();

        walls[0].setBounds(10, 15, 10, 480);// left height
        walls[0].setVisible(true);
        walls[0].setBackground(Color.white);
        walls[0].setOpaque(true);
        gamestage.add(walls[0]);

        walls[1].setBounds(10, 10, 490, 10);// top width
        walls[1].setVisible(true);
        walls[1].setBackground(Color.white);
        walls[1].setOpaque(true);
        gamestage.add(walls[1]);

        // wall3.setBounds(x, y, width, height);
        walls[2].setBounds(10, 100, 100, 10);
        walls[2].setVisible(true);
        walls[2].setBackground(Color.white);
        walls[2].setOpaque(true);
        gamestage.add(walls[2]);



        finish.setBounds(30, 455, 20, 20); // *make the game change to the main
                                            // screen when finished
                                            // Add a timer
        finish.setVisible(true);
        finish.setBackground(Color.LIGHT_GRAY);
        finish.setOpaque(true);
        gamestage.add(finish);

    }

    /**
     * Check if two JLabel objects are touching
     * 
     * @param a
     *            The first JLabel
     * @param b
     *            The second JLabel
     * @return true if the JLabels are touching
     */
    public boolean areColliding(JLabel a, JLabel b) {
        return a.getBounds().intersects(b.getBounds());
    }

    /**
     * this method makes the player move. It takes the players speed and
     * subtracts or adds the player speed to the current position of the player.
     * It also figures out were the player is at currently aswell.
     * 
     * @param arg0
     */
    @Override
    public void actionPerformed(ActionEvent arg0) {
        // Move up if W is pressed
        if (keys.contains(KeyEvent.VK_W)) {
            player.setLocation(player.getX(), player.getY() - playerSpeed);
        }
        // Move right if D is pressed
        if (keys.contains(KeyEvent.VK_D)) {
            player.setLocation(player.getX() + playerSpeed, player.getY());
        }
        // Move down if S is pressed
        if (keys.contains(KeyEvent.VK_S)) {
            player.setLocation(player.getX(), player.getY() + playerSpeed);
        }
        // Move left if A is pressed
        if (keys.contains(KeyEvent.VK_A)) {
            player.setLocation(player.getX() - playerSpeed, player.getY());
        }

        for (int i = 0; i < walls.length; i++) {
            // I created a for loop instead
            // of a do loop because the for
            // loop would have been a lot
            // simpler to manage

            if (areColliding(walls[i], player)) { // Reposition the target
                int newX = (int) (25);
                int newY = (int) (25);
                player.setLocation(newX, newY);

            }
        }

        if (areColliding(finish, player)) {
            // Reposition the target
            int newX = 25;
            int newY = 25;
            player.setLocation(newX, newY);
            CardLayout layout = (CardLayout) gameFrame.getContentPane()
                    .getLayout();
            layout.show(gameFrame.getContentPane(), "buttons");
        }
    }

    @Override
    public void keyPressed(KeyEvent e) {
        // Add the key to the list
        // of pressed keys
        if (!keys.contains(e.getKeyCode())) {
            keys.add(e.getKeyCode());
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        // Remove the key from the
        // list of pressed keys
        keys.remove((Integer) e.getKeyCode());
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }

}

當按下臀部時,此代碼顯示游戲窗格

/**
 * This pane contains the button and sets up the button pane
 */
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class ButtonPane extends JPanel {

    private JButton startBTN;// Calls the JButton
    JFrame game;

    public ButtonPane(JFrame g) {
        game = g;
        setLayout(new GridBagLayout());
        setBackground(Color.gray);// Sets the menu stages color blue
        startBTN = new JButton("Game");// Creates a new button
        add(startBTN);// Adds the button on the startStage

        startBTN.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (game.getContentPane().getLayout() instanceof CardLayout) {
                    CardLayout layout = (CardLayout) getParent().getLayout();
                    layout.show(game.getContentPane(), "game");

                }
            }
        });
    }

}

好的,您已經有了一個Timer ,該Timer每秒的速度為1000/FPS 您真正需要的只是計算兩個時間點之間的差,這非常簡單。

首先定義一個“開始時間”

private Instant startTime;

除非您需要,否則它將為null 當您想啟動計時器時,請使用startTime = Instant.now();

startTime != null ,您要計算它與現在之間的差...

Duration runningTime = Duration.between(startTime, Instant.now());

現在,這告訴您計時器已運行了多長時間。

接下來,我們需要做出一些決定,例如計時器用完時該怎么做,但是為此,我們實際上需要知道計時器應在多長時間內運行...

private Duration timeOutDuration = Duration.ofSeconds(5);

這只是將超時設置為5秒,您可以使用所需的任何范圍。

然后,我們可以計算計時器的剩余時間...

Duration timeRemainig = timeOutDuration.minus(runningTime);

然后決定要做什么...

if (timeRemainig.isNegative() || timeRemainig.isZero()) {
    // Time has run out...
    // startTime = null; // stop the timer
} else {
    // Update the UI
}

Java 8中引入的日期/時間API極其強大和靈活(當您動手時,會帶來很多樂趣)

解決方案可能開始看起來像...

private Duration timeOutDuration = Duration.ofSeconds(5);
private Instant startTime; // Set this when you're ready to start the timer

@Override
public void actionPerformed(ActionEvent arg0) {
    if (startTime != null) {
        Duration runningTime = Duration.between(startTime, Instant.now());
        Duration timeRemainig = timeOutDuration.minus(runningTime);
        if (timeRemainig.isNegative() || timeRemainig.isZero()) {
            // Time has run out...
            // startTime = null; // stop the timer
        } else {
            // Update the UI
        }
    }

格式化輸出的Duration通常看起來像...

long hours = timeRemainig.toHours();
long mins = timeRemainig.minusHours(hours).toMinutes();

// Or if you're lucky enough to be using Java 9+
//String formatted = String.format("%dhrs %02dmins", duration.toHours(), duration.toMinutesPart());
String formatted = String.format("%dhrs %02dmins", hours, mins);

或類似形式,具體取決於您希望的格式

為什么用這種方法代替一些“計數器”

簡單,它(超級)准確。 Timer僅保證一個“至少”間隔,也就是說,它將延遲不小於該值,這意味着隨着時間的推移可能會引入“拖動”,這會使計數器不同步。 當然,在短時間內,這可能沒什么大不了的,但是由於有一種(超級簡單的)更好的方法來完成它,所以為什么不使用它呢。

該解決方案還具有超強的靈活性,適用於廣泛的類似問題。 我將上述概念用作基於時間的動畫的一部分,這些動畫通常會產生遠遠優於總體的效果。

暫無
暫無

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

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