如何解决Java Swing Movement Stutter?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (1)
  • 关注 (0)
  • 查看 (62)

以下是我使用的代码:

MovementStutter.java

package movementstutter;

import javax.swing.JFrame;

public class MovementStutter {

public static void main(String[] args) {
    JFrame win = new JFrame("Stutter Demo");
    win.getContentPane().add(new GamePanel());
    win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    win.setResizable(false);
    win.pack();
    win.setVisible(true);
}

}

GamePanel.java

package movementstutter;

import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;

public class GamePanel extends JPanel implements Runnable {

private boolean running;
private Thread thread;
private double x;
private double y;
private double movementFactor;

public GamePanel() {
    setPreferredSize(new Dimension(640, 480));
    setFocusable(true);
    grabFocus();
    movementFactor = 1;
    running = true;
}

@Override
public void addNotify() {
    super.addNotify();
    if (thread == null) {
        thread = new Thread(this);
        thread.start();
    }
}

@Override
public void run() {
    long time = System.currentTimeMillis();
    while (running) {
        update();
        repaint();
        long sleep = 16 - (System.currentTimeMillis() - time);
        time += 16;
        if (sleep < 0) {
            sleep = 16;
        }
        try {
            Thread.sleep(sleep);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

private void update() {
    if (x < 0) {
        movementFactor = 1;
    } else if (x > 608) {
        movementFactor = -1;
    }
    x += movementFactor * 200 * 0.016;
}

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.fillRect((int) x, (int) y, 32, 32);
}

}
提问于
用户回答回答于

正在更新不属于事件派发线程的线程中的swing组件,不应该这样做,要执行定时操作,可以使用javax.swing.Timer

public void actionPerformed(ActionEvent e) {
    update();
    repaint();
}

然后,在面板的构造函数中,可以创建一个Timer。A javax.swing.Timer确保在事件分派循环中执行操作,它还简化了时序管理:

public GamePanel() {
    setPreferredSize(new Dimension(640, 480));
    setFocusable(true);
    grabFocus();
    movementFactor = 1;
    running = true;
    new Timer(16,this).start();
}

如果需要在任何时候停止计时器,那么应该将它分配给一个字段,比如说

Timer blockTimer = new Timer(16,this);

blockTimer.start();

在你的构造函数中,可以有一个其动作包含的按钮

blockTimer.stop();

所属标签

可能回答问题的人

  • 华讯云

    0 粉丝0 提问7 回答
  • gulu丶咕噜

    0 粉丝1 提问5 回答
  • 卓脑域名

    0 粉丝0 提问3 回答
  • 女淘日记

    杭州吱吱吱科技 · 站长 (已认证)

    1 粉丝1 提问3 回答

扫码关注云+社区

领取腾讯云代金券