Проблемы с createImage (int width, int height)
-
20-09-2019 - |
Вопрос
У меня есть следующий код, который запускается каждые 10 мс как часть игры:
private void gameRender()
{
if(dbImage == null)
{
//createImage() returns null if GraphicsEnvironment.isHeadless()
//returns true. (java.awt.GraphicsEnvironment)
dbImage = createImage(PWIDTH, PHEIGHT);
if(dbImage == null)
{
System.out.println("dbImage is null"); //Error recieved
return;
}
else
dbg = dbImage.getGraphics();
}
//clear the background
dbg.setColor(Color.white);
dbg.fillRect(0, 0, PWIDTH, PHEIGHT);
//draw game elements...
if(gameOver)
{
gameOverMessage(dbg);
}
}
Проблема в том, что он вводит оператор if, который проверяет, является ли изображение нулевым, даже после того, как я пытаюсь определить изображение.Я огляделся, и кажется, что createImage() вернет null, если GraphicsEnvironment.isHeadless() возвращает true.
Я не совсем понимаю, какова цель метода isHeadless(), но я подумал, что это может быть как-то связано с компилятором или IDE, поэтому я попробовал два, оба из которых выдают одинаковую ошибку (Eclipse и BlueJ).У кого-нибудь есть какие-либо идеи, в чем источник ошибки и как я мог бы это исправить?
Заранее благодарю
Джонатан
...................................................................
Редактировать:Я использую java.awt.Component.createImage(int width, int height).Цель этого метода - обеспечить создание и редактирование изображения, которое будет содержать изображение игрока в игре, которое позже будет выведено на экран с помощью JPanel.Вот еще немного кода, если это вообще поможет:
public class Sim2D extends JPanel implements Runnable
{
private static final int PWIDTH = 500;
private static final int PHEIGHT = 400;
private volatile boolean running = true;
private volatile boolean gameOver = false;
private Thread animator;
//gameRender()
private Graphics dbg;
private Image dbImage = null;
public Sim2D()
{
setBackground(Color.white);
setPreferredSize(new Dimension(PWIDTH, PHEIGHT));
setFocusable(true);
requestFocus(); //Sim2D now recieves key events
readyForTermination();
addMouseListener( new MouseAdapter() {
public void mousePressed(MouseEvent e)
{ testPress(e.getX(), e.getY()); }
});
} //end of constructor
private void testPress(int x, int y)
{
if(!gameOver)
{
gameOver = true; //end game at mousepress
}
} //end of testPress()
private void readyForTermination()
{
addKeyListener( new KeyAdapter() {
public void keyPressed(KeyEvent e)
{ int keyCode = e.getKeyCode();
if((keyCode == KeyEvent.VK_ESCAPE) ||
(keyCode == KeyEvent.VK_Q) ||
(keyCode == KeyEvent.VK_END) ||
((keyCode == KeyEvent.VK_C) && e.isControlDown()) )
{
running = false; //end process on above list of keypresses
}
}
});
} //end of readyForTermination()
public void addNotify()
{
super.addNotify(); //creates the peer
startGame(); //start the thread
} //end of addNotify()
public void startGame()
{
if(animator == null || !running)
{
animator = new Thread(this);
animator.start();
}
} //end of startGame()
//run method for world
public void run()
{
while(running)
{
long beforeTime, timeDiff, sleepTime;
beforeTime = System.nanoTime();
gameUpdate(); //updates objects in game (step event in game)
gameRender(); //renders image
paintScreen(); //paints rendered image to screen
timeDiff = (System.nanoTime() - beforeTime) / 1000000;
sleepTime = 10 - timeDiff;
if(sleepTime <= 0) //if took longer than 10ms
{
sleepTime = 5; //sleep a bit anyways
}
try{
Thread.sleep(sleepTime); //sleep by allotted time (attempts to keep this loop to about 10ms)
}
catch(InterruptedException ex){}
beforeTime = System.nanoTime();
}
System.exit(0);
} //end of run()
private void gameRender()
{
if(dbImage == null)
{
dbImage = createImage(PWIDTH, PHEIGHT);
if(dbImage == null)
{
System.out.println("dbImage is null");
return;
}
else
dbg = dbImage.getGraphics();
}
//clear the background
dbg.setColor(Color.white);
dbg.fillRect(0, 0, PWIDTH, PHEIGHT);
//draw game elements...
if(gameOver)
{
gameOverMessage(dbg);
}
} //end of gameRender()
} //end of class Sim2D
Надеюсь, это поможет немного прояснить ситуацию, Джонатан
Решение
Вместо createImage(...) я обычно использую BufferedImage.
Другие советы
У меня возникла точно такая же проблема после того, как я попытался реализовать двойную буферизацию для генератора фракталов.Мое решение:Я взял пример из книги, но изменил его (не зная последствий) так, как я запускал createImage ВНУТРИ конструктора.Это привело к появлению nullpointer.Затем я положил это
if (_dbImage == null) {
_dbImage = createImage(getSize().width, getSize().height);
_dbGraphics = (Graphics2D)_dbImage.getGraphics();
}
внутри метода обновления, и это сработало!!Потому что update вызывается ПОСЛЕ того, как объект был создан.
Согласно документам для java.awt.Component , createImage также может возвращать null, если компонент недоступен для отображения, что, скорее всего, и происходит.
Для того, что вы пытаетесь сделать, вам следует взглянуть на класс BufferedImage, поскольку он не привязан к компоненту.
Попробуйте переопределить метод addNotify() в JPanel, который вы расширяете.Это хорошее место для "запуска" вашей анимации, а не конструктор, например.Обязательно включите строку super.addNotify();
public аннулирует addNotify() { super.addNotify();Начальная игра ();}
Желаю удачи
Похоже, что поток запускается раньше, чем компонент фактически отображается на экране.Чтобы убедиться, что этого не произойдет, вы можете переопределить метод paint(Graphics g) JPanel и поместить код в метод run() потока внутри метода paint.В методах run() вашего потока просто вызовите repaint() .
например,:
public void paint(Graphics g){
**gameUpdate(); //updates objects in game (step event in game)
gameRender(); //renders image
paintScreen(); //paints rendered image to screen**
}
и в вашем методе run():
public void run(){
while(running)
{
long beforeTime, timeDiff, sleepTime;
beforeTime = System.nanoTime();
**repaint();**
timeDiff = (System.nanoTime() - beforeTime) / 1000000;
sleepTime = 10 - timeDiff;
if(sleepTime <= 0) //if took longer than 10ms
{
sleepTime = 5; //sleep a bit anyways
}
try{
Thread.sleep(sleepTime); //sleep by allotted time (attempts to keep this loop to about 10ms)
}
catch(InterruptedException ex){}
beforeTime = System.nanoTime();
}
}
isHeadless вернет значение true только в том случае, если вы работаете в среде, отличной от GUI (например, внутри сервера или контейнера сервлетов).
Я полагаю, что ваша проблема кроется в самом вашем методе createImage.Не могли бы вы дать нам больше информации о контексте?Какой метод createImage вызывается и какова его реализация?
package javagame;
import java.awt.BorderLayout;
import javax.swing.JFrame;
/**
*
* @author stuart
*/
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
JFrame frame= new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(100, 100, 500, 400);
frame.add(new GamePanel(), BorderLayout.CENTER);
frame.setVisible(true);
}
}