簡體   English   中英

Java javax.swing.Timer持續時間

[英]Java javax.swing.Timer duration

我需要使用javax.swing.Timer在X秒內執行N次計算(帶有圖形更新)。 最好的方法是什么?

如果我為計時器設置了固定的延遲,則我將超過X秒,因為每次執行所需的時間為delay + calculations

要解決此問題,我嘗試動態設置計時器的delay ,但是時間仍然不准確。

作為最后的機會,我已經盡力了設置dalay到1毫秒,並使用Thread.sleep(sleepTime)控制的持續時間和這項工作完全,不影響動畫。

我的問題是:

這是一個好的解決方案嗎? 我可以在javax.swing.Timer內使用Thread.sleep(sleepTime)嗎?

編輯 ,這是一些更好理解的代碼。 我想說的是,僅需要查看運動是否正確就需要圖形,在最終版本中,我只需要更新游戲並生成比賽結果報告即可。

具有“游戲循環”的主機:

package engine.test;

import engine.entity.Skill;
import engine.math.Point;
import engine.math.Vector;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.Timer;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public final class EngineFrame extends JFrame implements ActionListener
{
    public static final int SCALE = 6;
    public static final int WIDTH = 100 * SCALE;
    public static final int HEIGHT = 60 * SCALE;

    public static final int DURATION = 2; // animation duration in seconds
    public static final int FPS = 60;
    public static final int SKIP_TICKS = 1000 / FPS;

    private final JSONObject data;
    private final ArrayList<Player> players;
    private PlayersPanel playersPanel;

    public EngineFrame(String title) throws JSONException, FileNotFoundException
    {
        super(title);

        setSize(WIDTH, HEIGHT);
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        createMenu();

        data = new JSONObject(loadData());
        players = buildPlayers(data.getJSONArray("teams").getJSONObject(0).getJSONArray("players"));

        playersPanel = new PlayersPanel(players);
        add(playersPanel);
    }

    public ArrayList<Player> getPlayers()
    {
        return players;
    }

    /**
     * Returns the data required to run a match.
     * 
     * @return a json string representing the match data
     * @throws FileNotFoundException 
     */
    private String loadData() throws FileNotFoundException
    {
        Scanner fileInput = new Scanner(new File(
            "C:\\Users\\packard bell\\Documents\\JavaProjects\\Engine\\src\\resources\\data.json"
        ));
        String jsonText = "";

        while (fileInput.hasNextLine()) {
            jsonText += fileInput.nextLine();
        }

        return jsonText;
    }

    /**
     * Creates and returns the player entities.
     * 
     * @param playersData
     * @return 
     */
    private ArrayList<Player> buildPlayers(JSONArray playersData) throws JSONException
    {
        ArrayList<Player> players = new ArrayList<Player>();
        JSONObject playerData;
        Player player;

        for (int i = 0, l = playersData.length(); i < l; i++) {
            playerData = playersData.getJSONObject(i);
            player = new Player.Builder()
                .setId(playerData.getInt("id"))
                .setFirstName(playerData.getString("first_name"))
                .setLastName(playerData.getString("last_name"))
                .setMass(playerData.getInt("weight"))
                .setSkills(buildSkills(playerData.getJSONObject("skills")))
                .setInitialPosition(new Point(0, i * 10 + 20))
                .setInitialVelocity(new Vector(0, 0))
                .build();

            players.add(player);
        }

        return players;
    }

    /**
     * 
     */
    private Map<Skill, Double> buildSkills(JSONObject skillsData) throws JSONException
    {
        Map<Skill, Double> skills = new HashMap();

        for (Skill skill : Skill.values()) {
            skills.put(
                skill,
                skill.getMinValue() + (skill.getMaxValue() - skill.getMinValue()) * (skillsData.getDouble(skill.getName()) / 100)
            );
        }

        return skills;
    }

    /**
     * 
     */
    private void createMenu()
    {
        JMenu seekMenu = new JMenu("Seek behavior");

        JMenuItem initSeek = new JMenuItem("Init seek");
        initSeek.addActionListener(this);
        JMenuItem runSeek = new JMenuItem("Run seek");
        runSeek.addActionListener(this);
        JMenuItem stopSeek = new JMenuItem("Stop seek");
        stopSeek.addActionListener(this);

        seekMenu.add(initSeek);
        seekMenu.add(runSeek);
        seekMenu.add(stopSeek);

        JMenuBar bar = new JMenuBar();
        bar.add(seekMenu);

        setJMenuBar(bar);
    }

    public static void main(String[] args) throws JSONException, FileNotFoundException, InterruptedException
    {
        EngineFrame frame = new EngineFrame("Engine");
    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
        String menuString = e.getActionCommand();

        if (menuString.equalsIgnoreCase("init seek")) {
            Player player1 = getPlayers().get(0);
            Player player2 = getPlayers().get(1);

            player1.setPosition(new Point(0, 20));
            player1.setVelocity(new Vector(0, 0));
            player2.setPosition(new Point(0, 30));
            player2.setVelocity(new Vector(0, 0));

            repaint();
        }
        else if (menuString.equalsIgnoreCase("run seek")) {
            Timer t = new Timer(1, new ActionListener() {
                private final long start = System.currentTimeMillis();
                private long nextGameUpdate = start;
                private long sleepTime = 0;
                private int loops = DURATION * 1000 / SKIP_TICKS;

                @Override
                public void actionPerformed(ActionEvent e) {
                    Player player1 = getPlayers().get(0);
                    Player player2 = getPlayers().get(1);

                    //System.out.println("Position: " + player1.getPosition());
                    //System.out.println("Velocity: " + player1.getVelocity());
                    System.out.println();

                    player1.getSteering().seek(new Point(50, 20));
                    player2.getSteering().seek(new Point(50, 30));
                    player1.update();
                    player2.update();
                    repaint();

                    nextGameUpdate += SKIP_TICKS;
                    sleepTime = nextGameUpdate - System.currentTimeMillis();
                    //System.out.println(nextGameUpdate);
                    //System.out.println(sleepTime);
                    loops--;

                    if (sleepTime >= 0) {
                        try {
                            Thread.sleep(sleepTime);
                        } catch (InterruptedException ex) {
                            Logger.getLogger(EngineFrame.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }

                    if (loops <= 0) {
                        ((Timer)e.getSource()).stop();

                        long end = System.currentTimeMillis();
                        // should be 2000ms (equals to DURATION constant)
                        System.out.println("Duration: " + (end - start) + "ms");
                    }
                }
            });
            t.setInitialDelay(0);
            t.start();
        }
    }

    // version without swing timer (it works if called in the main method)
    private void runSeek() throws InterruptedException
    {
        Player player1 = getPlayers().get(0);
        Player player2 = getPlayers().get(1);

        player1.setPosition(new Point(0, 20));
        player2.setPosition(new Point(0, 30));

        // run
        long start = System.currentTimeMillis();
        long nextGameUpdate = start;
        long sleepTime = 0;
        int i = DURATION * 1000 / SKIP_TICKS;
        System.out.println("Loop executions: " + i);
        int steps = 0;
        String stepsCode = "[";
        String velocitiesCode = "[";
        String positionsCode = "[";

        while (i > 0) {
            stepsCode += steps + ", ";
            velocitiesCode += player1.getVelocity().len() + ", ";
            positionsCode += player1.getPosition().toVector().len() + ", ";

            System.out.println("Position: " + player1.getPosition());
            System.out.println("Velocity: " + player1.getVelocity());
            System.out.println();

            player1.getSteering().seek(new Point(50, 20));
            player2.getSteering().seek(new Point(50, 30));
            player1.update();
            player2.update();
            repaint();

            nextGameUpdate += SKIP_TICKS;
            sleepTime = nextGameUpdate - System.currentTimeMillis();
            steps += sleepTime;
            //System.out.println(sleepTime);

            if (sleepTime >= 0) {
                Thread.sleep(sleepTime);
            }

            i--;
        }

        stepsCode = stepsCode.substring(0, stepsCode.length() - 2) + "]";
        velocitiesCode = velocitiesCode.substring(0, velocitiesCode.length() - 2) + "]";
        positionsCode = positionsCode.substring(0, positionsCode.length() - 2) + "]";

        long end = System.currentTimeMillis();

        System.out.println("Duration: " + (end - start) + "ms");

        System.out.println("Steps:");
        System.out.println(stepsCode);
        System.out.println("Positions:");
        System.out.println(positionsCode);
        System.out.println("Velocities:");
        System.out.println(velocitiesCode);
    }
}

這是繪制實體的JPanel:

package engine.test;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.util.ArrayList;
import javax.swing.JPanel;

public class PlayersPanel extends JPanel
{
    private ArrayList<Player> players;

    public PlayersPanel(ArrayList<Player> players)
    {
        this.players = players;
    }

    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        for (Player player : players) {
            int x = (int) (player.getPosition().x() * EngineFrame.SCALE);
            int y = (int) (player.getPosition().y() * EngineFrame.SCALE);

            g2.setColor(Color.BLACK);
            g2.fillArc(x, y, 18, 18, 0, 360);
            g2.setColor(new Color(0x11539f));
            g2.fillArc(x + 2, y + 2, 14, 14, 0, 360);
        }
    }
}

這是一個好的解決方案嗎? 我可以在javax.swing.Timer內使用Thread.sleep(sleepTime)嗎?

不,永遠不要這樣做。 不必擔心更改延遲。 而是考慮要繪制的內容以及繪制時間。 您可以為要繪制的其他對象創建一個類,然后保持一個延遲狀態,該狀態將確定何時繪制它們。 如果要更改對象速度,請增加其移動的像素數。

這是一個您可能會發現有用的示例 ,它顯示了我保持延遲狀態的第一點。 您可以看到球在不同的時間被拋出。

在此處輸入圖片說明

除此之外,您還應該發布一些代碼,這些代碼可以准確顯示您要執行的操作。 您的問題有些含糊。

暫無
暫無

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

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