Java 移动一个长方形时,会出现令人难以置信的起伏
我创建了一个简单的程序,可以画一个矩形,它以恒定的速率从屏幕上落下。我首先运行Main.java:Java 移动一个长方形时,会出现令人难以置信的起伏,java,jframe,jpanel,Java,Jframe,Jpanel,我创建了一个简单的程序,可以画一个矩形,它以恒定的速率从屏幕上落下。我首先运行Main.java: package highst; public class Main { public static void main(String args[]){ new GameFrame(); } } 这将创建GameFrame.java的新实例: package highst; import javax.swing.JFrame; public class G
package highst;
public class Main {
public static void main(String args[]){
new GameFrame();
}
}
这将创建GameFrame.java的新实例:
package highst;
import javax.swing.JFrame;
public class GameFrame extends JFrame {
public GameFrame() {
super("Falling rectangle");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(800, 600);
GameLogic game = new GameLogic();
this.getContentPane().add(game);
this.setVisible(true);
game.run();
}
}
从而创建GameLogic.java的新实例:
package highst;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
public class GameLogic extends JPanel implements Runnable, KeyListener {
Marvin marvin;
private enum GameState{
Running, Dead
}
GameState state = GameState.Running;
public GameLogic(){
marvin = new Marvin(50, 50);
Thread thread = new Thread(this);
thread.start();
addKeyListener(this);
setFocusable(true);
this.setBackground(Color.black);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.white);
g.fillRect(marvin.getX(), marvin.getY(), 50, 50);
}
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_SPACE){
marvin.jump();
}
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void run() {
if(state == GameState.Running){
while(true){
marvin.update();
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
它最终利用了我的可玩角色Marvin.java,它现在是一个白色矩形:
package highst;
public class Marvin {
private int x, y;
public Marvin(int x, int y){
this.x = y;
this.y = y;
}
public void update(){
y -= -1;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void jump() {
x += 1;
}
}
它运行正常,但矩形在从页面上落下时绘制不平滑。它似乎一次跳几个像素。我认为让线程休眠17毫秒会使所有内容都平滑渲染。我做错了什么 要使动画平滑,您需要以恒定速率更新屏幕 在这里,您正在进行图形重新绘制,这可能需要任何时间,然后无论如何等待17毫秒。这会导致每帧占用不同的时间。第一帧可能在2ms内完成,下一帧可能需要5ms,然后是3ms,依此类推。。。您的帧将显示19ms然后22ms然后20ms 您需要的是一个专用线程,其唯一任务是等待适当的时间,然后向主线程发出重新绘制的信号。然后你的画框(只要画幅不超过17ms)每17ms就出来一次,完全按照提示 ,您应该会发现它是相关的。试试这些: 1> 减少线程的休眠时间以查看效果,并获得最佳的下降速度 2> 使用双缓冲(屏幕首先在内存中绘制,然后绘制到显示屏上的概念): 3> 简单建议:避免使用sleep()。取而代之的是使用计时器。它是线程非常有趣和强大的替代品。此外,它不会在游戏开发的后期阶段产生问题。请查看以下链接: 4> 查看以下有关Java动画的有趣教程:
有几件事不对
GameLogic
实例调用run
,并创建一个线程
,该线程将再次调用run
,设置为循环。这真是愚蠢的运气。这样做是调用marvin.update
两次…以及随机间隔,这意味着对象以不一致的速率移动game.run()
并包装newgameframe()代码>在EventQueue.invokeLater
调用的上下文中
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
GameFrame frame = new GameFrame();
}
});
}
就个人而言,我建议不要直接从JFrame
扩展,不要向类添加任何功能,只需在main
中创建一个实例,然后将GameLogic
面板添加到该实例中即可。这使得游戏在部署方面更加灵活,因为你没有将自己锁定在一个容器中
我还建议您不要使用KeyListener
,而是使用,因为它解决了与KeyListener
相关的焦点问题,您应该实现某种双缓冲以避免闪烁。你试过完全不睡觉吗?@NeplatnyUdaj Swing组件由default1进行双缓冲-我认为OP已经有一个经过训练的线程在指定的时间内等待。你是对的,他们没有考虑更新和重新绘制一个框架所需的时间,但是考虑到几乎不可能知道最后一个框架是什么时候在Swing中绘制的(并且知道我们谈论的是哪个框架),你最好希望知道更新需要多长时间……仅供参考,Swing组件由双缓冲default@MadProgrammer例如我不知道。但是在我正在进行的一个项目中,我不得不显式地使用双缓冲来解决闪烁和滞后的问题。@MadProgrammer:也许你是对的。我需要进一步研究一下。我已经实现了您的更改并删除了game.run()
,但它仍然不稳定。真的吗?真奇怪。我觉得可能是我的笔记本电脑在装傻。我什么也没做,只是费心在上面运行东西。你能把你的程序上传到某个地方,这样我就可以在我这边测试它吗?记住,Swing使用一个被动渲染引擎,所以当你调用repaint时,不能保证实际会发生绘制,只能保证在furpture中的某个时间会发生绘制