Я не могу найти способ получить плавное движение или анимацию чего-либо с помощью Java2d, когда конвейеры opengl и direct3d отключены (путем вызова виртуальной машины с параметрами -Dsun.java2d.d3d=false и -Dsun.java2d.opengl=false)
Быстрый и грязный код ниже демонстрирует мою проблему. Он рисует прямоугольник, который перемещается по экрану. Расположение ящика обновляется примерно 60 раз в секунду, а экран перерисовывается столько раз, сколько возможно. Он использует класс BufferStrategy для реализации двойной буферизации; переворот выполняется в "bs.show();"
Код (нажмите Escape, чтобы выйти):
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferStrategy;
public class FluidMovement {
private static volatile boolean running = true;
private static final int WIDTH = 500;
private static final int HEIGHT = 350;
public static void main(String[] args) {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
Frame frame = new Frame(gc);
frame.setIgnoreRepaint(true);
frame.setUndecorated(true);
frame.addKeyListener(new KeyAdapter() {
@Override public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
running = false;
}
}
});
frame.setSize(WIDTH, HEIGHT);
frame.setVisible(true);
frame.createBufferStrategy(2);
BufferStrategy bs = frame.getBufferStrategy();
long nextTick = System.nanoTime();
class Rect {
int dx = 2, dy = 1, x = 0, y = 0;
}
Rect rect = new Rect();
Graphics g;
while (running) {
if (System.nanoTime() > nextTick) {
rect.x = (rect.x + rect.dx) % WIDTH;
rect.y = (rect.y + rect.dy) % HEIGHT;
nextTick += 1000000000 / 60;
}
g = bs.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.WHITE);
g.fillRect(rect.x, rect.y, 10, 10);
g.dispose();
bs.show();
}
bs.dispose();
frame.dispose();
}
}
Когда я обычно выполняю этот код с помощью «java FluidMovement», он работает гладко, как шелк (не считая случайных разрывов), потому что jvm использует конвейер direct3d/directdraw. Когда я выполняю этот код с "java -Dsun.java2d.d3d=false -Dsun.java2d.opengl=false FluidMovement", он ужасно прерывистый.
Я не могу предположить, что используется конвейер direct3d или opengl. Конвейеры не работают с 2 из 3 машин, на которых я пробовал; это работало только на машине с выделенной графикой под управлением Windows 7. Могу ли я в любом случае заставить коробку двигаться плавно, или мне следует прибегнуть к использованию какой-либо библиотеки с низкоуровневым доступом, такой как JOGL?
Примечания:
- Частота кадров не при чем. В обоих случаях (конвейеры включены и отключены) приложение работает со скоростью более 300 кадров в секунду. Я принудительно отключил vsync, когда конвейеры включены.
- Я пробовал Toolkit.getDefaultToolkit().sync()
- Я пробовал много разных типов петель, но движение никогда не было по-настоящему плавным. Даже при фиксированной частоте кадров наблюдается такая же изменчивость.
- Я пробовал запускать фрейм в полноэкранном эксклюзивном режиме.
- Я пробовал использовать 3 или даже 4 буфера.