Почему при создании createBufferStrategy(3) возникает нелегальное исключение invalidArgumentException?
Я начинаю создавать игру с использованием Java. В моем методе render() у меня есть буферная стратегия с тремя буферами. Однако, когда я запускаю его, я получаю эту ошибку.
Exception in thread "Thread-1" java.lang.IllegalArgumentException: Width (0) and height (0) cannot be <= 0
at java.awt.image.DirectColorModel.createCompatibleWritableRaster(DirectColorModel.java:1016)
at sun.java2d.opengl.CGLGraphicsConfig.createCompatibleImage(CGLGraphicsConfig.java:200)
at java.awt.GraphicsConfiguration.createCompatibleImage(GraphicsConfiguration.java:178)
at sun.awt.image.SunVolatileImage.getBackupImage(SunVolatileImage.java:236)
at sun.awt.image.VolatileSurfaceManager.getBackupSurface(VolatileSurfaceManager.java:263)
at sun.awt.image.VolatileSurfaceManager.initialize(VolatileSurfaceManager.java:126)
at sun.awt.image.SunVolatileImage.<init>(SunVolatileImage.java:88)
at sun.awt.image.SunVolatileImage.<init>(SunVolatileImage.java:98)
at sun.awt.image.SunVolatileImage.<init>(SunVolatileImage.java:109)
at sun.java2d.opengl.CGLGraphicsConfig.createBackBufferImage(CGLGraphicsConfig.java:356)
at sun.lwawt.LWCanvasPeer.createBuffers(LWCanvasPeer.java:62)
at java.awt.Component$FlipBufferStrategy.createBuffers(Component.java:4016)
at java.awt.Component$FlipBufferStrategy.<init>(Component.java:3956)
at java.awt.Component$FlipSubRegionBufferStrategy.<init>(Component.java:4479)
at java.awt.Component.createBufferStrategy(Component.java:3833)
at java.awt.Canvas.createBufferStrategy(Canvas.java:194)
at java.awt.Component.createBufferStrategy(Component.java:3756)
at java.awt.Canvas.createBufferStrategy(Canvas.java:169)
at com.game.framework.Game.render(Game.java:79)
at com.game.framework.Game.run(Game.java:58)
at java.lang.Thread.run(Thread.java:744)
Вот полный класс с методом render():
package com.game.framework;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = 2956560507546666478L;
private Thread thread;
private boolean running = false;
public static final int WIDTH = 640, HEIGHT = WIDTH / 12 * 9;
public Game() {
new Window(WIDTH, HEIGHT, "UNKNOWN", this);
}
public synchronized void start() {
thread = new Thread(this);
thread.start();
running = true;
}
public synchronized void stop() {
try {
thread.join();
running = false;
} catch (Exception e) {
e.printStackTrace();
}
}
public void run() {
long lastTime = System.nanoTime();
long timer = System.currentTimeMillis();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
int frames = 0;
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1) {
tick();
delta--;
}
if (running)
render();
frames++;
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println("FPS: " + frames);
frames = 0;
}
}
stop();
}
private void tick() { }
private void render() {
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
}
public static void main(String args[]) {
new Game();
}
}
Вот другой класс в моей игре:
package com.game.framework;
import java.awt.Canvas;
import java.awt.Dimension;
import javax.swing.JFrame;
public class Window extends Canvas {
private static final long serialVersionUID = 70937078350109973L;
public Window (int width, int height, String title, Game game) {
JFrame frame = new JFrame(title);
frame.setPreferredSize(new Dimension(width, height));
frame.setMaximumSize(new Dimension(width, height));
frame.setMinimumSize(new Dimension(width, height));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
frame.add(game);
game.start();
}
}
Я не уверен, в чем проблема, но это довольно неприятно, и я не могу продолжать, пока проблема не будет решена. Спасибо за вашу помощь!
1 ответ
После некоторых исследований я нашел возможную причину, по которой ваш код работает для меня, но не для вас. Я использую Direct 3D для рендеринга, а вы используете OpenGL.
Классы D3D также используют этот код для создания BufferStrategy
:
public VolatileImage createBackBuffer(WComponentPeer peer) {
Component target = (Component)peer.getTarget();
// it is possible for the component to have size 0x0, adjust it to
// be at least 1x1 to avoid IAE
int w = Math.max(1, target.getWidth());
int h = Math.max(1, target.getHeight());
return new SunVolatileImage(target, w, h, Boolean.TRUE);
}
Как видите, он устанавливает ширину и высоту как минимум 1
чтобы избежать IllegalArgumentException
,
Версия OpenGL этого класса не:
@Override
public VolatileImage createBackBufferImage(Component target,
long backBuffer) {
return new SunVolatileImage(target,
target.getWidth(), target.getHeight(),
Boolean.TRUE);
}
Так что если вы все еще хотите использовать OpenGl, вам нужно обойти короткое время, когда размер холста еще не установлен ** (т.е. ширина и высота 0
) самостоятельно:
private void render() {
if (getWidth() == 0 || getHeight() == 0) {
return;
}
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
}
** Кажется, что очень короткое время, когда Game
холст не "имеет" его правильный размер. Это размер 0x0
есть, но позже будет обновлен до 634x449
(после примерно 3 итераций вашего игрового цикла).