When I am trying to figure out how to use bufferstrategies, and overall just improving how I write my code and cleaning things up. When I run the following code, I get an error when I "createBufferStrategy(3)"
package Game1Test;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.io.IOException;
import javax.swing.*;
public class Base extends Canvas implements Runnable{
private static final long serialVersionUID = 1L;
private boolean running = false;
int ticks = 0;
public Base(JFrame f) {
setSize(f.getWidth(),f.getHeight());
start();
}
public void start(){
running = true;
new Thread(this).start();
}
public void stop(){
}
public void run(){
while(running){
ticks++;
System.out.println(ticks);
render();
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void render(){
BufferStrategy bs = getBufferStrategy();
Graphics g;
if(bs == null){
createBufferStrategy(3);
requestFocus();
return;
}
bs.show();
}
}
The Base is then added with:
package Game1Test;
import java.awt.*;
import javax.swing.JFrame;
public class Screen extends JFrame{
public final int GAME_WIDTH = 400;
public final int GAME_HEIGHT = 400;
public Dimension gameDim = new Dimension(GAME_WIDTH,GAME_HEIGHT);
final String gameName = "Test";
public Screen(){
setSize(gameDim);
setTitle(gameName);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setLayout(new GridLayout());
setVisible(true);
setLocationRelativeTo(null);
}
public static void main(String[] args){
Screen s = new Screen();
s.add(new Base(s));
}
}
I get the following error:
Exception in thread "Thread-2" java.lang.IllegalStateException: Component must have a valid peer
at java.awt.Component$FlipBufferStrategy.createBuffers(Unknown Source)
at java.awt.Component$FlipBufferStrategy.<init>(Unknown Source)
at java.awt.Component$FlipSubRegionBufferStrategy.<init>(Unknown Source)
at java.awt.Component.createBufferStrategy(Unknown Source)
at java.awt.Canvas.createBufferStrategy(Unknown Source)
at java.awt.Component.createBufferStrategy(Unknown Source)
at java.awt.Canvas.createBufferStrategy(Unknown Source)
at Game1Test.Base.render(Base.java:46)
at Game1Test.Base.run(Base.java:33)
at java.lang.Thread.run(Unknown Source)
Can someone please tell me why this is happening? and maybe a solution to this problem?
Thanks
Taking a look at the API, this exception is thrown if the component is not displayable. In this case, that's when Canvas.peer is null. Taking a look at the peer field reveals that
The peer is set when the Component is added to a
container that also is a peer
Since you are starting the update thread from your component's constructor, render could be called before your component is ever added to another container which would mean the peer is null, and then an IllegalStateException would be thrown.
In my experience with this error and with the code you writing you missing a frame function.
Add where your frames are (ex: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);) and add the function frame.add(game);
In this example, mine is Display game = new Display(); but depending on what your variable for the new display is, it might vary.
I had exactly the same exception, but i found out that it was because my JFrame visibility was accidentally set to false.
so puting in setVisible(true); fixed it.
Related
I am trying to create a 2D platform game, by following this tutorial. I have created an Images()-class which looks like this:
package Resources;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Objects;
public class Images {
public static BufferedImage[] tileBlocks;
public Images(){
tileBlocks = new BufferedImage[1];
try{
tileBlocks[0] = ImageIO.read(
// TODO: Fix the error caused by this try/catch
(Objects.requireNonNull(getClass().getResourceAsStream("TileBlocks/block_brick.png")))
);
} catch (IOException e) { e.printStackTrace(); }
}
}
And I created an instantation of it in my GamePanel()-class, which looks like this
package Main;
import GameState.GameStateManager;
import Resources.Images;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.Serial;
#SuppressWarnings("BusyWait")
public class GamePanel extends JPanel implements Runnable, KeyListener {
#Serial
private static final long serialVersionUID = 1L;
// Game thread
private boolean isRunning = false;
int FPS = 60; // Frames per second
long targetTime = 1000 / FPS; // Set target time
// Set the dimension of the game-window
public static final int WIDTH = 800;
public static final int HEIGHT = 600;
private GameStateManager gsm = new GameStateManager(); // Game state manager object
public GamePanel(){
setPreferredSize(new Dimension(WIDTH, HEIGHT));
addKeyListener(this);
setFocusable(true);
// TODO: Fix error (Reports instantiation of utility classes using the new keyword)
new Images();
start();
}
// Start the game (initialize)
private void start() {
isRunning = true;
Thread thread = new Thread(this); // Referring to Runnable
thread.start(); // Call to our game-loop
}
// Game-loop
public void run() {
long start, elapsed, wait; // Keep track of time
gsm = new GameStateManager(); // Initialize game state manager
while (isRunning) {
start = System.nanoTime(); // Start timer
update(); // Update the game-logic
repaint(); // Re-paint the board (built-in method from java.awt)
elapsed = System.nanoTime() - start;
// If everything runs in under the target time we wait (so it runs equally in all computers)
wait = targetTime - elapsed / 1000000; // Divide by 1 000 000 to get milli-seconds
if (wait <= 0) { wait = 5; } // Keep wait a positive value
try {
Thread.sleep(wait);
} catch (Exception e) { e.printStackTrace(); }
}
}
// Updating all game-logic
public void update() { gsm.update(); }// Call methods from game state manager in the game panel class
// Where we draw the graphics
public void paintComponent(Graphics g){
super.paintComponent(g); // Built-in method from java.awt
g.clearRect(0,0,WIDTH,HEIGHT); // Clear the screen before drawing
gsm.draw(g); // Call method from game state manager in the game panel class
}
public void keyPressed(KeyEvent e) {
gsm.keyPressed(e.getKeyCode()); // getKeyCode() turns KeyEvent into an integer
}
public void keyReleased(KeyEvent e) {
gsm.keyReleased(e.getKeyCode()); // getKeyCode() turns KeyEvent into an integer
}
public void keyTyped(KeyEvent e) { }
}
I get an error saying
Instantiation of utility class 'Images'
Inspection info: Reports instantiation of utility classes using the new keyword.
In utility classes, all fields and methods are static.
Instantiation of such classes is most likely unnecessary and indicates a mistake.
And when I try to run the game it doesn't launch, I only get a NullPointerException
Exception in thread "main" java.lang.NullPointerException
at java.base/java.util.Objects.requireNonNull(Objects.java:208)
at inf112.skeleton.app/Resources.Images.<init>(Images.java:17)
at inf112.skeleton.app/Main.GamePanel.<init>(GamePanel.java:35)
at inf112.skeleton.app/Main.Game.game(Game.java:10)
at inf112.skeleton.app/Main.Game.main(Game.java:20)
But if I remove the the instantation, the game launches, but then it crashes with even more errors
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException:
Cannot load from object array because "Resources.Images.tileBlocks" is null
etc...
If I remove the Objects.requireNonNull from
tileBlocks[0] = ImageIO.read((getClass().getResourceAsStream("TileBlocks/block_brick.png"))
The game launches, but it crashes and I get another error saying
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException:
Cannot load from object array because "Resources.Images.tileBlocks" is null
What am I doing wrong here? Why is my list of tileBlocks null? How can I read the image and display it on the tileBlocks?
Put file "block_brick.png" in directory "TileBlocks" in classpath.
UPDATE : As Dmich has noted, because I am doing my drawing outside of my panel class, this is leading to recursive calls to the initialization of my MyPanel and Animation class. So how can I still accomplish drawing on MyPanel, in Animation class, but without this problem.
I am having a very specific problem with my code and I don't know how to describe what is happening, but I will try my best. I tried searching stackOverFLow, but the problem is I dont even know what to search.
Here I go:
In an effort to organize this as best as possible, I will first write all the classes I am dealing with.
public class MyPanel extends JPanel implements Runnable{
private Animation anim = new Animation();
}
public class Animation extends ??? implements KeyListener{}
So I have a class called MyPanel which extends JPanel. I haved added this class to my JFrame using
add(new MyPanel())
I am using a Thread in MyPanel which calls
#Overrid public void paintComponent(Graphics g)
paintComponent calls a method in Animation which is where I draw an image to the screen g2d.drawImage(image, int, int, ImageObserver). The problem is to use this method I need an ImageObserver, which I can get if Animation extends JPanel. But if I extend JPanel, nothing is drawn onto my JFrame because this is a new jPanel which is not added to the JFrame.
But if I extend MyPanel, (which is added to my JFrame) I get a whole bunch of errors.
Eclipse errors:
Exception in thread "main" java.lang.StackOverflowError
at java.awt.Component.setBackground(Unknown Source)
at javax.swing.JComponent.setBackground(Unknown Source)
at javax.swing.LookAndFeel.installColors(Unknown Source)
at javax.swing.LookAndFeel.installColorsAndFont(Unknown Source)
at javax.swing.plaf.basic.BasicPanelUI.installDefaults(Unknown Source)
at javax.swing.plaf.basic.BasicPanelUI.installUI(Unknown Source)
at javax.swing.JComponent.setUI(Unknown Source)
at javax.swing.JPanel.setUI(Unknown Source)
at javax.swing.JPanel.updateUI(Unknown Source)
at javax.swing.JPanel.<init>(Unknown Source)
at javax.swing.JPanel.<init>(Unknown Source)
at javax.swing.JPanel.<init>(Unknown Source)
Under this error message, these 2 lines go on until terminated by eclipse.
at MyPanel.<init>(MyPanel.java:9)
at Animation.<init>(Animation.java:9)
Any help would be greatly appreciated.
UPDATE 2 Adding code sample as suggested:
import javax.swing.JFrame;
public class Simulation extends JFrame {
private MyPanel panel = new MyPanel();
public Simulation() {
initUI();
}
private void initUI() {
add(panel);
setResizable(false);
pack();
setTitle("Simulation");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null); // centers
}
public static void main(String[] args) {
Simulation ex = new Simulation();
ex.setVisible(true);
}
}
import javax.swing.*;
import java.awt.*;
public class MyPanel extends JPanel implements Runnable {
private Animation anim;
public MyPanel() {
anim = new Animation();
initPanel();
}
private void initPanel() {
//other customizables
}
#Override
public void run() {
//Thread that calls repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
anim.step(g2D, this);
}
}
import java.awt.Graphics2D;
public class Animation {
private Sprite player;
private KeyBinder kB;
public Animation() {
player = new Sprite();
kB = new KeyBinder(player);
}
public void step(Graphics2D g2d, JPanel p) {
player.move();
drawSprite(g2d, p);
}
private void drawSprite(Graphics2D g2d, JPanel p) {
g2d.drawImage(player.getImage(), player.getX(), player.getY(), p);
}
}
import java.awt.Image;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
public class Sprite {
private final String PLAYER_IMAGE_FILE = "Image location";
private Image image;
private int width, height;
private int x, y, dx, dy;
public Sprite() {
x = 0;
y = 0;
loadImage();
}
private void loadImage() {
ImageIcon ii = new ImageIcon(PLAYER_IMAGE_FILE);
image = ii.getImage();
width = image.getWidth(null);
height = image.getHeight(null);
}
public void move() {
x += dx;
y += dy;
}
public void keyPressed(KeyEvent e) {
//assings meaning to keypressed
}
public void keyReleased(KeyEvent e) {
//assings meaning to keyReleased
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getW() {
return width;
}
public int getH() {
return height;
}
public Image getImage() {
return image;
}
}
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class KeyBinder extends MyPanel implements KeyListener {
Sprite p;
public KeyBinder(Sprite player) {
p = player;
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
#Override
public void keyPressed(KeyEvent e) {
p.keyPressed(e);
}
#Override
public void keyReleased(KeyEvent e) {
p.keyReleased(e);
}
#Override
public void keyTyped(KeyEvent e) {
}
}
By trying to trouble shoot the code I made changes to my code, mainly by trying to pass the JPanel to the Animation.step method and also making a separate class for key listening.
The new error list is mostly the same:
Exception in thread "main" java.lang.StackOverflowError
at java.awt.Component.setBackground(Unknown Source)
at javax.swing.JComponent.setBackground(Unknown Source)
at javax.swing.LookAndFeel.installColors(Unknown Source)
at javax.swing.LookAndFeel.installColorsAndFont(Unknown Source)
at javax.swing.plaf.basic.BasicPanelUI.installDefaults(Unknown Source)
at javax.swing.plaf.basic.BasicPanelUI.installUI(Unknown Source)
at javax.swing.JComponent.setUI(Unknown Source)
at javax.swing.JPanel.setUI(Unknown Source)
at javax.swing.JPanel.updateUI(Unknown Source)
at javax.swing.JPanel.<init>(Unknown Source)
at javax.swing.JPanel.<init>(Unknown Source)
at javax.swing.JPanel.<init>(Unknown Source)
Then an infinite loop until termination of the following three lines:
at MyPanel.<init>(MyPanel.java:10)
at KeyBinder.<init>(KeyBinder.java:6)
at Animation.<init>(Animation.java:11)
So I have a class called Panel which extends JPanel. I haved added this class to my JFrame using add(new Panel()) I am using a Thread in Panel which calls #Overrid public void paintComponent(Graphics g)
First, Swing is NOT thread safe, you should not be updating the UI from outside the context of the Event Dispatching Thread.
Second, there should NEVER be any situation where you would call paintComponent directly, nor is there ever any need for it to be public, as nothing else should be calling it.
See Concurrency in Swing for more details
paintComponent calls a method in Animation which is where I draw an image to the screen g2d.drawImage(image, int, int, ImageObserver). The problem is to use this method I need an ImageObserver, which I can get if Animation extends JPanel.
Why not make Animation "paintable", providing a method which requires the caller to pass the information you need in order to do your job?
public class Animation {
public void paint(Graphics2D g2d, ImageObserver observer) {
//...
}
}
You could also pass in other information which might be needed to the paint method, such as the model which is modelling the current state.
This is basically a delegation model - where you "delegate" responsibility for a specific task to another class
What about KeyListener?
I hear you ask.
Well, to start with, it's probably not Animation's responsibility to deal with it. Instead that the controller should be modifying the state, in response to the event, which is eventually painted by the renderer
Also, you should be using the Key bindings API instead, it will solve the unreliability issues associated with KeyListener
I wouldn't recommend making the class extend JPanel, but rather when instantiated take in a JPanel parameter:
public class Panel implements Runnable{
private JPanel panel;
public Panel(JPanel panel){
this.panel = panel;
}
}
In addition, I think it would be wise to make the Panel class you have Extend Component so that you have a seamless integration when adding it to your existing panel mentioned in the title:
public class Panel extends Component implements Runnable{
private JPanel panel;
public Panel(JPanel panel){
this.panel = panel;
}
}
Please let me know if this doesn't work or you have other questions regarding this!
This was another case of bad inheritance lads. I fixed it by implementing KeyListener in MYPanel class and passing MyPanel as an argument to the of Animation. It was bad practice for me to try and implement a keyListener to a JPanel but from a different class.
I am having somewhat of an issue getting an image from another class. I have never had this problem before. Can someone please point me in the right direction.
package main;
import java.awt.Color;
import java.awt.DisplayMode;
import java.awt.Graphics;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class Main extends JFrame {
public static Character character;
static GraphicsEnvironment graphicsEnvironment;
static GraphicsDevice graphicsDevice;
static DisplayMode displayMode;
private Image i;
public static void main(String[] args) {
displayMode = new DisplayMode(1280, 720, 16, DisplayMode.REFRESH_RATE_UNKNOWN);
graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
graphicsDevice = graphicsEnvironment.getDefaultScreenDevice();
Main m = new Main();
m.run();
}
public void run() {
setUndecorated(true);
setResizable(false);
graphicsDevice.setFullScreenWindow(this);
try {
graphicsDevice.setDisplayMode(displayMode);
} catch (Exception e) {
}
}
public void paint(Graphics g) {
g.setColor(Color.cyan);
g.fillRect(0, 0, displayMode.getWidth(), displayMode.getHeight());
i = character.getImage();
g.drawImage(i, 100, 100, this);
}
}
package main;
import java.awt.Image;
import javax.swing.ImageIcon;
public class Character {
private Image i;
public Image getImage() {
i = new ImageIcon(this.getClass().getResource("/raw/images/player1.png")).getImage();
return i;
}
}
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at main.Main.paint(Main.java:52)
It says that the error is i = character.getImage();
I have done this plenty of times when making applets, this if the first time I am trying a fullscreen game
Remember to think about what the compiler is telling you.
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
A NullPointerException means a reference variable hasn't been initialized (or is == null, for that matter). In your case, that means to debug it you'll have to check both i and character. If it was the image you were trying to return, the stacktrace would go one deeper.
Since you are initializing i, look back up at character. You never set character to anything, which means you can't use it in any declarations.
So, your solution is to do character = new Character(); in run() or main(String[] args),
or you can set getImage() to static, and say i = Character.getImage();.
Change the method declaration to
public static Image getImage(){/*your code here */}
And the statement to call that method make sure that the first letter is C in uppercase not c. as in Character.getImage()
When I override the paint method of my GamePanel class, then, when I try to open the MazeGUI Design Tab, I get this error:
Internal Error
WindowBuilder encountered unexpected internal error.
This could be caused by a WindowBuilder bug or by a misconfiguration issue, conflict, partial update, etc.
Stack trace:
java.lang.NullPointerException
at maze.gui.GamePanel.paint(GamePanel.java:25)
at javax.swing.JComponent.print(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.printChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.print(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.printChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
If I delete this line at GamePanel.java at paint override function
g.drawImage(maze.wall, 400, 400, null);
the design tab at MazeGUI already works. Very strange...
Anyway, if I run the java application, it displays the image without any errors.
Here I leave both classes java files:
GamePanel.java:
package maze.gui;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class GamePanel extends JPanel {
private int comprimento_sprites;
private MazeGUI maze;
/**
* Create the panel.
*/
public GamePanel(MazeGUI m) {
comprimento_sprites = 40;
maze = m;
setFocusable(true);
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawImage(maze.wall, 400, 400, null);
}
}
MazeGUI.java:
package maze.gui;
import java.awt.EventQueue;
import java.awt.Image;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import maze.logic.Jogo;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class MazeGUI {
private JFrame frmMazeGame;
//IMAGES
public BufferedImage wall;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MazeGUI window = new MazeGUI();
window.frmMazeGame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public MazeGUI() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
//faz load das imagens do jogo
loadImages();
frmMazeGame = new JFrame();
frmMazeGame.setTitle("Maze Game");
frmMazeGame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GamePanel tabuleiro = new GamePanel(this);
frmMazeGame.getContentPane().add(tabuleiro);
}
private void loadImages(){
try {
wall = ImageIO.read(new File("images/bloco.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
Ah, let me add this:
- I think all this problem is related to the loadImages function at MazeGUI, but I think I do it all alright. Already lost so many hours trying to fix this.
- Keep in mind: no error when I run the app (it even shows the image in the app) but I get the error above when I try to open the Design tab :/
You receive the error when loading the Design tab because of this line:
g.drawImage(maze.wall, 400, 400, null);
I don't have much experience with WindowBuilder, so I can't tell you how it works exactly, but it seems as though your MazeGUI object in the GamePanel is null when in Design mode. It's not a problem with your image loading, it's simply because of however WindowBuilder works.
To get the Design tab to load, you can simply throw a check for null in there:
if (maze != null && maze.wall != null) {
g.drawImage(maze.wall, 400, 400, null);
}
As far as getting the image to actually show in the Design tab, I'm afraid I can't help you.
I'm starting to learn to create Games in Java, and one of the methods I'm using includes BufferedImage. This is the error I get:
"Exception in thread "main" java.lang.NullPointerException
at tm.Game.init(Game.java:48)
at tm.Game.<init>(Game.java:54)"
From this code:
package tm;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class Game extends JPanel implements Runnable {
private Settings Settings;
private Thread t;
private BufferedImage offscreenImage;
private Graphics offscr;
public void run() {
while(true) {
repaint();
try {
Thread.sleep(1000/30);
} catch (InterruptedException e) { }
}
}
public void paint(Graphics g) {
offscr.setColor(Color.blue);
offscr.fillRect(0, 0, Settings.GAME_WIDTH, Settings.GAME_HEIGHT);
offscr.setColor(Color.white);
offscr.drawString("Lolz", 10, 10);
g.drawImage(offscreenImage, 0, 0, this);
}
public void update(Graphics g) {
paint(g);
}
public void init() {
t = new Thread(this);
t.start();
offscreenImage = (BufferedImage) createImage(Settings.GAME_WIDTH, Settings.GAME_HEIGHT);
offscr = offscreenImage.getGraphics();
}
public Game() {
Settings = new Settings();
init();
}
}
Settings Class:
package tm;
public class Settings {
public final int GAME_WIDTH = 500;
public final int GAME_HEIGHT = 500;
}
Screen Class:
package tm;
import javax.swing.JFrame;
public class Screen extends JFrame {
private static final long serialVersionUID = 1L;
private JFrame mainScreen;
private Game mainGame;
private Settings Settings;
public Screen() {
mainGame = new Game();
Settings = new Settings();
mainScreen = new JFrame();
mainScreen.add(mainGame);
mainScreen.setSize(Settings.GAME_WIDTH, Settings.GAME_HEIGHT);
mainScreen.setTitle("Lolz");
mainScreen.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainScreen.setResizable(false);
mainScreen.setVisible(true);
}
public static void main(String[] args) {
new Screen();
}
}
It is not getGraphics() that returns null but rather the previous function createImage(). From the Component documentation for createImage():
returns an off-screen drawable image, which can be used for double
buffering. The return value may be null if the component is not
displayable. This will always happen if
GraphicsEnvironment.isHeadless() returns true.
You then get a NullPointerException when calling getGraphics() on offscreenImage which is null.
The reason that throw NullPointer exception is that you initialized the offScreenImage and offScr in wrong place.
offscreenImage = (BufferedImage) createImage(Settings.GAME`WIDTH, Settings.GAME_HEIGHT);
offscr = offscreenImage.getGraphics();
This code should be in the function paint. To get the results the Game class should be defined like this. And another tip it is better to declare variables inn Settings class to public static final so that they can be accessed in static way. Make little change to your Game class as defined below. I think this should help you.
package tm;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import tm.Screen.Settings;
public class Game extends JPanel implements Runnable {
// private Setting Settings;
private Thread t;
private BufferedImage offscreenImage;
private Graphics offscr;
public void run() {
while (true) {
repaint();
try {
Thread.sleep(1000 / 30);
} catch (InterruptedException e) {
}
}
}
public void paint(Graphics g) {
if (offscreenImage == null) {
offscreenImage = (BufferedImage) createImage(Settings.GAME_WIDTH,
Settings.GAME_HEIGHT);
}
offscr = offscreenImage.getGraphics();
offscr.setColor(Color.black);
offscr.fillRect(0, 0, Settings.GAME_WIDTH, Settings.GAME_HEIGHT);
offscr.setColor(Color.white);
offscr.drawString("Lolz", 10, 10);
g.drawImage(offscreenImage, 0, 0, this);
}
public void update(Graphics g) {
paint(g);
}
public void init() {
t = new Thread(this);
t.start();
}
public Game() {
init();
}
}
Since createImage only works after the Component is "displayable" e.g. it is attached to a visible JFrame your current code wont work.
There are several ways you can deal with it.
Add JFrame as a parameter to the ctor and add the Game to the JFrame before calling create component - this should work as long as JFrame.add does not call any methods overridden by the partially initialized Game instance.
Game(JFrame jf){
jf.add(this);
...
}
JFrame mainFrame = new JFrame();
mainFrame.setVisible(true);
Game game = new Game(mainFrame);
Make an additional init method which is called after adding Game to the JFrame. This is ugly since the Game object is not really fully initialized until this method is called.
Game game = new Game();
JFrame mainFrame = new JFrame();
mainFrame.add(game);
mainFrame.setVisible(true);
game.init();
One way to find out when the component is displayable is to listen for a HierarchyEvent. You could modify the Listener shown in the answer to call createImage instead of printing "showing". (The class provided by that answer also needs a extends HierarchyListener to work)