使用图形2D和双缓冲区的抖动



我正在开发的小游戏遇到了一些问题。 虽然我使用的是双缓冲区并且能够摆脱闪烁,但运动看起来仍然有些抖动,不流畅。我知道这可能是由于以大步长和/或低帧率增加运动引起的,但我在使用 1 和 50+ fps 的增量时仍然遇到同样的问题。这有点难以解释,但精灵的移动很奇怪(正确,但不是流畅的运动)

如果有人能指出我正确的方向,我将不胜感激。

public class Gameplay extends javax.swing.JPanel {
GUI gui;
Canvas canvas = new Canvas();
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
BufferedImage bi;
BufferStrategy buffer;
public Gameplay(GUI gui) {
    this.gui = gui;
    initComponents();
}
// Used to start the gameplay. Called by GUI
public void start() {
    new RefreshScreen().start();
}
// ==============================================================================================
// DOUBLE BUFFER AND PAINTING ===================================================================
// ==============================================================================================
Date date = new Date(); // time
int lastSecond = 0; // seconds controll - for FPS calculation
int fpsCount = 0; // Count frames rendered
int showFps = 0; // The total FPS text that will appear on screen
int MAX_FPS = 30; // targeted Max FPS
int MIN_FPS = 24; // targeted Min FPS
int sleepTimeBetweenRefresh = 20; // Delay before new refresh
Color fpsColor = Color.yellow; // color of the FPS information on screen
String fpsInfo = ""; // Aditional info on FPS (increasing, decreasing, etc)
class RefreshScreen extends Thread {
    public void run() {
        Graphics graphics = null;
        Graphics2D bufferGraphics = null;
        add(canvas, BorderLayout.CENTER);
        canvas.setIgnoreRepaint(true);
        canvas.setVisible(true);
        canvas.setSize(gui.getWidth(), gui.getHeight());
        canvas.createBufferStrategy(2);
        buffer = canvas.getBufferStrategy();
        bi = gc.createCompatibleImage(gui.getWidth(), gui.getHeight());
        bufferGraphics = bi.createGraphics();
        while (true) {
            try {
                //FrameRate count
                date = null;
                date = new Date();
                if (lastSecond != date.getSeconds()) {
                    lastSecond = date.getSeconds();
                    showFps = fpsCount;
                    fpsCount = 0;
                    if (showFps > MAX_FPS) {
                        sleepTimeBetweenRefresh++;
                        fpsInfo = "(--)";
                        fpsColor = Color.blue;
                    }
                    if ((showFps < MIN_FPS) && (sleepTimeBetweenRefresh > 5)) {
                        sleepTimeBetweenRefresh--;
                        fpsInfo = "(++)";
                    }
                    if (showFps < MIN_FPS) {
                        fpsColor = Color.red;
                    }
                    if ((showFps > MIN_FPS) && (showFps <= MAX_FPS)) {
                        fpsColor = Color.green;
                        fpsInfo = "(ok)";
                    }
                }
                fpsCount++;
                //Clear canvas =============================
                bufferGraphics.setColor(Color.black);
                bufferGraphics.clearRect(0, 0, gui.getWidth(), gui.getHeight());
                //FPS =============================
                bufferGraphics.setColor(fpsColor);
                bufferGraphics.drawString("FPS: " + showFps, 3, 15);
                bufferGraphics.setColor(Color.black);
                //SPRITES =============================
                try {
                    for (int count = 0; count < Sprites.getSprites().size(); count++) {
                        bufferGraphics.drawImage(Sprites.getSprite(count).getImage(), Sprites.getSprite(count).getX(), Sprites.getSprite(count).getY(), null);
                    }
                } catch (Exception e) {  }
                //HERO =============================
                try {
                    bufferGraphics.drawImage(Sprites.getHero().getImage(), Sprites.getHero().getX(), Sprites.getHero().getY(), null);
                } catch (Exception e) {  }
                // PAINT BUFFER =================================
                try {
                    graphics = buffer.getDrawGraphics();
                    graphics.drawImage(bi, 0, 0, null);
                    if (!buffer.contentsLost()) {
                        buffer.show();
                    }
                } catch (Exception e) {  }
                // SLEEP  =================================
                sleep(sleepTimeBetweenRefresh);
            } catch (Exception e) {  }
        }//while
    }//run
}//inner class

我还想指出,精灵的 X 和 Y 正在处理中,以便它不会向右然后向下 - 例如 - 当它应该对角线时。无论如何,我不认为这是问题所在,因为问题甚至发生在直线上。

您可以尝试计算绘制所有内容所需的时间,然后从睡眠时间中减去它。

long beforeTime = System.currentTimeMillis();
// do all drawing
sleepTimeBetweenRefresh -= System.currentTimeMillis() - beforeTime;
if(sleepTimeBetweenRefresh < 0) sleepTimeBetweenRefresh = 0;

这有助于确保您的线程每 50 毫秒触发一次(或任何 sleepTimeBetweenRefresh 是什么)。假设您希望它每 50 毫秒触发一次,您的绘图需要 10 毫秒。在代码运行一次后,如果没有上面的代码,你实际上会在最后一次绘画后 60 毫秒内绘画,因为你画了 10 个,睡了 50 个。通过减去为组件喷漆所花费的时间,您可以保持 FPS 稳定。

相关内容

  • 没有找到相关文章

最新更新