java таймер качания отлично работает при отладке, но не во время выполнения - PullRequest
1 голос
/ 18 марта 2020

Я пытаюсь работать с этим часами уже сейчас, и я в растерянности. Я хочу запустить свою игру со скоростью 30 кадров в секунду. Задержка таймера поворота установлена ​​на 1000/30. Даже если я замедляю его до 1000 или 2000, это ничего не меняет. В пошаговой отладке все работает как задумано. Метод updateALL () вызывается в следующий раз, когда таймер refre sh. Но во время выполнения updateAll никогда не вызывается, даже один раз (sysout никогда не печатает). Я урезал код ниже, чтобы показать основные части. Он должен скомпилироваться.

Это мой класс слушателя:

public class Observer implements ActionListener {

    private int timerFrame;
    private int fps;
    private boolean frameComplete;

    public Observer() {
        this.frameComplete = true;
        this.timerFrame = 0;
    }

    @Override
    public void actionPerformed(ActionEvent aEvent) {
            nextTimerFrame();
    }

    public void frameCompleted() {
        frameComplete = true;
        System.out.println("Fcompleted");
    }

    public int getTimerFrame() {
        return timerFrame;
    }

    public void setFps(int fps) {
        this.fps = fps;
    }

    private void nextTimerFrame() {
        System.out.println(timerFrame);
        if(frameComplete) {
            if(timerFrame == fps) {
                timerFrame = 1;
            } else {
                ++timerFrame;
            }
            frameComplete = false;
        }
    } 
}

Вот код моего класса GameClock:

public class GameClock {
    private Timer timer;
    private Observer observer;
    private GameEngine gameEngine;
    private View view;
    private boolean paused;
    private boolean quit;
    private int clockFrame;

    public GameClock() {}
    public GameClock(GameEngine gameEngine) {
        this.gameEngine = gameEngine;
        this.paused = false;
        this.quit = false;
        setupTimer();
        this.clockFrame = 0;
        run();
    }

    public void updateAll() {
            readInputs();
            updateGameEngine();
            updateCanvas2D();
            updateCanvas3D();
            clockFrame = clockFrame == 30? 1:clockFrame+1;  
            observer.frameCompleted(); // puts frameComplete at "true" in Observer
            System.out.println("update" + clockFrame);
    }

    public void run() {
        while(!quit) {
            int timerFrame = observer.getRefreshFrame();
            if(!paused && (clockFrame < timerFrame || (clockFrame == 30 && timerFrame == 1))) {
                updateAll();
                //System.out.println("update");
            }
        }
    }

    private void setupTimer() {
        int fps = Config.getFps();
        int delay = Math.round(1000/fps); 
        observer.setFps(fps);
        this.timer = new Timer(delay, observer);
        timer.start();
    }   
    private void readInputs() {

    }

    private void updateGameEngine() {
    }

    private void updateCanvas2D() {
    }

    private void updateCanvas3D() {
    }
}

Обновление:

какое-то странное наблюдение:

, если я помещу 2 sysout в оператор "if" моего while l oop, они никогда не будут напечатаны. Это не дает распечатки:

public void run() {
    while(!quit) {
        int clockFrame = observer.getRefreshFrame();
        //System.out.println("clock" + clockFrame);
        //System.out.println("frame" + refreshFrame);
        if(!paused && (refreshFrame < clockFrame || (refreshFrame == 30 && clockFrame == 1))) {
            System.out.println("clock" + clockFrame);
            System.out.println("frame" + refreshFrame);
            updateAll();
            //System.out.println("update");
        }
    }
}

Если я добавлю предыдущий sysout в комментарии и уберу // из 2 вне оператора "if", например:

public void run() {
    while(!quit) {
        int clockFrame = observer.getRefreshFrame();
        System.out.println("clock" + clockFrame);
        System.out.println("frame" + refreshFrame);
        if(!paused && (refreshFrame < clockFrame || (refreshFrame == 30 && clockFrame == 1))) {
            //System.out.println("clock" + clockFrame);
            //System.out.println("frame" + refreshFrame);
            updateAll();
            //System.out.println("update");
        }
    }
}

я вижу этот refreshFrame всегда увеличивается с помощью clockFrame. Это не имеет никакого смысла. Если updateAll никогда не вызывается refreshFrame, кричать не следует.

ОБНОВЛЕНИЕ 2 - некоторые объяснения:

  • Таймеру колебания требуется прослушиватель, который генерирует событие actionPerformed (), когда оно тикает. Вот почему мне нужен наблюдатель.
  • Я не могу сделать вызов таймера "updateAll ()" напрямую, потому что таймер находится в своем собственном потоке. Если я это сделаю, таймер может вызвать «updateAll ()», в то время как предыдущее обновление не полностью завершено.
  • Способ, которым он «должен» работать: пока цикл повторяется, ничего не делая, пока не увидит, что таймер установлен, (clockFrame ниже, чем timerFrame). Затем обновите все (). TimerFrame не может быть увеличен, пока последнее updateAll () не будет полностью завершено (frameComplete имеет значение true в конце updateAll). Как только обновление будет завершено, следующий тик таймера будет увеличивать значение timerFrame, создавая новое обновление.
  • Теоретически и при пошаговой отладке оно работает, но не во время выполнения.

1 Ответ

1 голос
/ 19 марта 2020

Ниже приведен один файл mre (скопируйте и вставьте весь код в GameClock.java), демонстрирующий использование свинга Timer для обновления свинга View при 30 кадрах в секунду:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.Timer;

public class GameClock {

    private final Observer observer;
    private final View view;

    public GameClock() {
        view = new View();
        observer = new Observer(view);
        setupTimer();
    }

    private void setupTimer() {
        int fps = 30;
        int delay = Math.round(1000/fps);
        observer.setFps(fps);
        Timer timer = new Timer(delay, observer);
        timer.setInitialDelay(0);
        timer.start();
    }

    public static void main(String[] args) {
        new GameClock();
    }
}

class View {

    private JLabel counter;

    View(){
        createAndShowGui();
    }

    void createAndShowGui(){
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        counter = new JLabel("0", SwingConstants.CENTER);
        f.add(counter);
        f.pack();
        f.setVisible(true);
    }

    void setCounter(int i){
        counter.setText(String.valueOf(i));
    }
}

class Observer implements ActionListener {

    private int timerFrame;
    private int fps;
    private final boolean paused;
    private final View view;

    public Observer(View view) {
        this.view = view;
        paused = false;
        timerFrame = 0;
    }

    @Override
    public void actionPerformed(ActionEvent aEvent) {
        if (! paused) {
            updateAll();
        }
    }

    public int getTimerFrame() {
        return timerFrame;
    }

    public void setFps(int fps) {
        this.fps = fps;
    }

    private void nextTimerFrame() {
        timerFrame = timerFrame >= fps ?    0 : timerFrame + 1;
    }

    public void updateAll() {
        nextTimerFrame();
        view.setCounter(timerFrame);
    }
}
...