Таймер качания - время колеблется - PullRequest
3 голосов
/ 13 октября 2011

Я использую Swing Timer в своей игре, но когда игра запущена, у нее, кажется, есть моменты, когда она работает гладко, и моменты, когда она замедляется.

Почему время колеблется?

А как мне это исправить?

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

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

public class Main extends JFrame {

public Main() {
    super("JFrame");

    // you can set the content pane of the frame
    // to your custom class.

    setContentPane(new ImagePanel());

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    setSize(800, 400);
    setResizable(false);
    setVisible(true);

}

public static void main(String[] args) {
    // TODO Auto-generated method stub
    new Main();

}

class ImagePanel extends JPanel {

    Timer movementtimer;

    int x, y;

    public ImagePanel() {

        x = 0;
        y = 0;

        movementtimer = new Timer(12, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                long timstarted = System.currentTimeMillis();
                moveImage();
                repaint();
                long timefinished = System.currentTimeMillis() - timstarted;
                System.out.println(timefinished + " to run");
            };

        });

        movementtimer.start();

    }

    public void moveImage() {

        x++;
        y++;

        if (x > 800) {
            x = 0;
        }
        if (y > 400) {
            y = 0;
        }

    }

    public void paintComponent(Graphics g) {

        super.paintComponent(g);
        g.setColor(Color.RED);
        g.fillRect(0, 0, 800, 400);
        g.setColor(Color.BLUE);
        g.fillRect(x, y, 50, 50);

    }

}

}

Вот пример моего кода.В моей настоящей программе я рисую изображения, а не просто прямоугольник.Также происходит много обнаружений столкновений и других небольших вычислений.

Кроме того, здесь есть ссылка на файл Jar для игры, чтобы вы могли запустить его и (надеюсь) поняли, что я имею в виду.http://dl.dropbox.com/u/8724803/Get%20To%20The%20Chopper%201.3.jar

Спасибо

Том

Ответы [ 3 ]

3 голосов
/ 13 октября 2011

Поскольку рендеринг тривиален, я нахожу этот вариант вашего примера очень плавным.Время рендеринга значительно меньше половины миллисекунды, поэтому 12-миллисекундный период (~ 83 Гц) - это много времени для завершения кадра, обычно занимающего менее 10% одного ядра.По мере роста времени рендеринга поток таймера становится насыщенным, а события объединяются.Эффект усиливается на одном ядре, поскольку рендеринг конкурирует с требованиями сборки мусора и внешней обработки.Java не является системой реального времени, и не все планировщики созданы равными.

Вы, безусловно, захотите профилировать свой фактический код, как предложено здесь , чтобы увидеть любую корреляцию с колебаниямиспектакль.Один из альтернативных подходов - удлинить период (уменьшить частоту), чтобы уложиться в срок рендеринга, и использовать большее увеличение в moveImage(), чтобы получить ту же скорость.

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Main extends JFrame {

    private static final int W = 800;
    private static final int H = 400;

    public Main() {
        super("JFrame");
        this.add(new ImagePanel());
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.pack();
        setSize(W, H);
        this.setLocationRelativeTo(null);
        setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new Main();
            }
        });
    }

    class ImagePanel extends JPanel {

        Timer movementTimer;
        int x, y;

        public ImagePanel() {
            x = 0;
            y = 0;
            movementTimer = new Timer(12, new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    moveImage();
                    repaint();
                }
            });
            movementTimer.start();
        }

        public void moveImage() {
            x++;
            y++;
            if (x > W) {
                x = 0;
            }
            if (y > H) {
                y = 0;
            }
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            long start = System.nanoTime();
            g.setColor(Color.RED);
            g.fillRect(0, 0, W, H);
            g.setColor(Color.BLUE);
            g.fillRect(x, y, 50, 50);
            double delta = (System.nanoTime() - start) / 1000000d;
            g.drawString(String.format("%1$5.3f", delta), 5, 15);
        }
    }
}
3 голосов
/ 13 октября 2011

Качели Timer печально известны своей неточностью. Вместо этого используйте что-нибудь другое.


По подсказкам я решил удалить этот пост. OTOH большая часть дополнительной информации, которую стоит восстановить, приходит из trashgod, поэтому я просто процитирую / перефразирую их комментарии.

Я бы сказал, что это достаточно точно, но легко насытить.

И trashgod продолжает добавлять в отдельный комментарий, что:

(I) может цитировать Качество часов . javax.swing.Timer не очень точный, но он имеет очень точное разрешение на современных платформах.

2 голосов
/ 13 октября 2011

В панели конструктора выполните:

setBackground(Color.RED);

Тогда вам не нужно стирать фон, так как вы вызываете super.paintComponent.

В общем случае вычисляйте позиции по фактическому прошедшему времени (System.nanoTime ()) и не полагайтесь на кадры таймера. Существует несколько игровых платформ, поэтому, возможно, стоит взглянуть на их решение. Мне понравился образец.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...