使用Graphics2D和双缓冲区的抖动运动

时间:2013-11-17 18:58:07

标签: java graphics graphics2d

我正在开发一款小游戏时遇到一些问题。虽然我使用双缓冲并且能够摆脱闪烁,但运动仍然看起来有点紧张而且不流畅。 我知道这可能是由于增加了大步和/或低帧速率的运动造成的,但我仍然使用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正在被处理,以便它不会正确然后向下 - 例如 - 当它应该是对角线时。我不认为这是问题,因为即使在直线上也会出现问题。

1 个答案:

答案 0 :(得分:0)

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

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

这有助于确保您的线程每50毫秒(或任何sleepTimeBetweenRefresh)发射。假设你想要它发射50ms,你的绘图需要10ms。在代码运行一次之后没有上面的代码,你实际上会在最后一次绘制后绘制60ms,因为你画了10并且睡了50个。通过减去绘制组件所花费的时间,你可以保持你的FPS稳定。