Проблемы с createImage (int width, int height) - PullRequest
2 голосов
/ 09 октября 2009

У меня есть следующий код, который запускается каждые 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 () вернет ноль, если GraphicsEnvironment.isHeadless () вернет true.

Я не совсем понимаю, для чего предназначен метод isHeadless (), но я подумал, что это может иметь какое-то отношение к компилятору или IDE, поэтому я попробовал два, оба из которых получают одинаковую ошибку (Eclipse, BlueJ). Кто-нибудь знает, что является источником ошибки, и как я могу это исправить?

Заранее спасибо

Jonathan

............................................... ....................

EDIT: Я использую 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

Надеюсь, это поможет немного прояснить ситуацию, Jonathan

Ответы [ 7 ]

4 голосов
/ 09 октября 2009

Вместо createImage (...) я обычно использую BufferedImage.

3 голосов
/ 05 сентября 2010

У меня была точно такая же проблема после того, как я попытался реализовать Doublebuffering для фрактального генератора. Мое решение: Я взял пример из книги, но изменил его (не зная последствий) так, как я запускал createImage INSIDE конструктор. Это произвело нулевой указатель. Тогда я положил это

if (_dbImage == null) {
_dbImage = createImage(getSize().width, getSize().height);
_dbGraphics = (Graphics2D)_dbImage.getGraphics();
}

внутри update-метода, и это сработало !! Поскольку update называется AFTER, объект был создан.

2 голосов
/ 08 января 2011

Попробуйте переопределить метод addNotify () в расширяемой JPanel. Это хорошее место для запуска вашей анимации, а не конструктор, например. Обязательно включите строку super.addNotify ();

public void addNotify () { super.addNotify (); начать игру(); }

Удачи

2 голосов
/ 09 октября 2009

Согласно документации для java.awt.Component, createImage также может возвращать ноль, если компонент не отображается, что, скорее всего, и происходит.

Для того, что вы пытаетесь сделать, вы должны взглянуть на класс BufferedImage, так как он не привязан к компоненту.

1 голос
/ 09 октября 2009

Похоже, что поток запускается раньше, чем компонент фактически отображается на экране. Чтобы этого не произошло, вы можете переопределить метод 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();
    }
}
0 голосов
/ 04 января 2012
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);
    }

}
0 голосов
/ 09 октября 2009

isHeadless вернет true, только если вы работаете в среде без графического интерфейса пользователя (например, внутри контейнера сервера или сервлета).

Я считаю, что ваша проблема в самом вашем методе createImage. Можете ли вы дать нам больше контекста? Какой метод createImage вызывается и какова его реализация?

...