I'm trying to make a game with a youtube tutorial and I am currently attempting to create and fill a rectangle the size of the window. Instead of going black, it stays grey (my default colour).
Any ideas? Thanks in advance!
Code:
import javax.swing.*;
import java.awt.image.BufferStrategy;
import java.awt.*;
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = 1L;
public static int width = 300;
public static int height = width / 16 * 9;
public static int scale = 3;
private Thread thread;
private JFrame frame; // Creates a window
private boolean running = false; // Checks to see if the game is running
public Game() {
Dimension size = new Dimension(width * scale, height * scale); // The window size
setPreferredSize(size); // Choosing the size I want
frame = new JFrame(); // Calling the frame
}
public synchronized void start() {
running = true;
thread = new Thread(new Game(), "Display"); // Calling the class
thread.start(); // Starting the class
}
public synchronized void stop() { // Ending the game
running = false;
try {
thread.join();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
while(running) {
update();
render();
}
}
public void update() {
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if(bs == null) {
createBufferStrategy(3); // Triple buffering strategy (speeds up process)
return;
}
Graphics g = bs.getDrawGraphics(); // Create a link between buffer and drawing on screen
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
g.dispose();
bs.show();
}
public static void main(String[] args) {
Game game = new Game(); // Calling the class to be able to change things in it
game.frame.setResizable(true); // Stopping window changing in size (causes graphical errors)
game.frame.setTitle("Game Window");
game.frame.add(game); // Fills the window with the class (can be done because of 'Canvas')
game.frame.pack(); // Sets the size of the window based on what is in the component above.
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setLocationRelativeTo(null); // Centres the window in the screen
game.frame.setVisible(true);
game.start(); // Starts the game
}
}
Change thread = new Thread(new Game(), "Display"); to use this instead of new Game().
Related
My Java program won't display a black screen when I tell it to. I can just see a greyish window with 0 FPS.
Here is my code:
package com.none.rain;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = 1L;
public static int width = 300;
public static int height = width / 16 * 9;
public static int scale = 3;
private boolean running = false;
private JFrame frame;
private Thread thread;
public Game() {
Dimension size = new Dimension(width*scale, height*scale);
setPreferredSize(size);
frame = new JFrame();
}
public synchronized void start() {
running = true;
thread = new Thread(this, "Display");
thread.start();
}
public synchronized void stop() {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
while (running) {
}
}
public void update() {
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
g.dispose();
bs.show();
}
public static void main(String[] args) {
Game game = new Game();
game.frame.setResizable(false);
game.frame.setTitle("Rain");
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setLocationRelativeTo(null);
game.frame.setVisible(true);
game.start();
}
}
Making the display black is something you do in your render() method, but you never call it.
If I take your code and add a call to render() in the run() method I get a frame with a black background:
public void run() {
while (running) {
render();
}
}
I am making a java game and at it's heart, it consists of a JFrame that holds a a JLabel that holds the background image. Early in the project this was being displayed. However, after I implemented a Game render method that put healthbars and a character on screen, the background image no longer displays. Here is the Game's render() and main() methods.
public class Game extends Canvas implements Runnable{
private static final long serialVersionUID = 1L;
public static final int WIDTH = 1200, HEIGHT = 600, SCALE = 1;
public static boolean running = false;
public Thread gameThread;
private BufferedImage playerSpriteSheet;
private ImageManager im;
private static Player player;
private static HealthBar healthBars;
public void init(){
ImageLoader loader = new ImageLoader();
playerSpriteSheet = loader.load("/spriteSheet.png");
SpriteSheet pss = new SpriteSheet(playerSpriteSheet);
im = new ImageManager(pss);
player = new Player(0, 0, im);
healthBars = new HealthBar(200, 200);
this.addKeyListener(new KeyManager());
}
public synchronized void start() {
if(running)return;
running = true;
gameThread = new Thread(this);
gameThread.start();
}
public synchronized void stop() {
if(!running)return;
running = false;
try {
gameThread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void run() {
init();
long lastTime = System.nanoTime();
final double amountOfTicks = 60D;
double ns = 1_000_000_000/amountOfTicks;
double delta = 0;
long now = System.nanoTime();
while(running)
{
delta += (now - lastTime)/ns;
lastTime = now;
if(delta >= 1)
{
tick();
delta--;
}
render();
}
stop();
}
public void tick() {
player.tick();
}
public void render() {
BufferStrategy bs = this.getBufferStrategy();
if(bs == null)
{
createBufferStrategy(3); //Use 5 at most
return;
}
Graphics g = bs.getDrawGraphics();
//RENDER HERE
player.render(g);
healthBars.render(g);
//END RENDER
g.dispose();
bs.show();
}
public static void main(String[] args)
{
JLabel backgroundImage;
JLabel controlKeyPanel;
JLabel statusLabel;
Game game = new Game();
game.setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
game.setMaximumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
game.setMinimumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
JFrame frame = new JFrame("Java Game");
frame.setResizable(false);
frame.setSize(WIDTH * SCALE, HEIGHT * SCALE);
frame.setLayout(new BorderLayout());
backgroundImage = new JLabel(new ImageIcon("/background.png"));
String htmlButtonGuide = "<html>← - Move Left<br>→ - Move Right<br>A - Attack<br>S - Fire Gun<br>P - Position<br>esc - Exit</html>";
controlKeyPanel = new JLabel(htmlButtonGuide);
statusLabel = new JLabel("Game Status");
frame.add(backgroundImage, BorderLayout.CENTER); //This should be displaying the background image
frame.add(controlKeyPanel, BorderLayout.EAST);
frame.add(statusLabel, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(game);
frame.setVisible(true);
game.start();
}
public static Player getPlayer() {
return player;
}
}
Here is the catch, and where I think part of the issue is visible. Inside the render() method there are these 2 lines:
player.render(g);
healthBars.render(g);
If I put player.render(g) first, then both the player and health bars appear on the screen. However, if I put healthBars.render(g) before player.render(g), then the player doesn't appear. This really confuses me, because I would expect the one that renders second causes the first one to be hidden behind, but the opposite happens. Could anyone point me in the right direction?
BufferStrategy doesn't play well with Swing, as you've taken control of the painting process
Canvas can't be transparent, so it will hide anything beneath it...
When you use frame.add(game) you are replaceing what ever use to be at BorderLayout.CENTER
Instead of mixing lightweight (Swing) and heavy weight (AWT) components, paint the background image as part of your render process
public void render() {
BufferStrategy bs = this.getBufferStrategy();
if(bs == null)
{
createBufferStrategy(3); //Use 5 at most
return;
}
Graphics g = bs.getDrawGraphics();
//RENDER HERE
// Paint background here...
player.render(g);
healthBars.render(g);
//END RENDER
g.dispose();
bs.show();
}
I'm following a Java game programming series on youtube, and all have been going well until we add some code to the program. The code for the program is:
package com.fagyapong.rain;
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
public class Game extends Canvas implements Runnable{
private static final long serialVersionUID = -247215114548172830L;
public static int width = 300;
public static int height = width / 16 * 9;
public static int scale = 3;
private JFrame frame;
public Thread thread;
private boolean running = false;
public Game() {
// Setup Game window
Dimension size = new Dimension(width * scale, height * scale);
setPreferredSize(size);
frame = new JFrame();
}
public synchronized void start() {
running = true;
thread = new Thread(this, "Display");
thread.start();
}
public synchronized void stop() {
running = false;
try {
thread.join();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
while (running) {
update();
render();
}
}
public void update() {
}
public void render() {
// Get the canvas' BufferStragy object
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.GRAY);
g.fillRect(0, 0, getWidth(), getHeight());
g.dispose();
bs.show();
}
public static void main(String[] args) {
Game game = new Game();
game.frame.setResizable(false);
game.frame.setTitle("Rain");
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setLocationRelativeTo(null);
game.frame.setVisible(true);
game.start();
}
}
Below is code that causes the system freeze(it has been commented out in the above code)
Graphics g = bs.getDrawGraphics();
g.setColor(Color.GRAY);
g.fillRect(0, 0, getWidth(), getHeight());
g.dispose();
bs.show();
Okay, I figured out the problem a bit. I was having the same issue. The issue for me was the triple buffering. Instead, set the code to:
createBufferStrategy(2);
That way it's only double buffering. I don't have a fantastic computer, so I had to set it to 1 instead of 2. At that point, my guess is that it's not buffering at all. This is how I got it to work though.
I looked and the codes seems fine to me. Got an error but hopefully it's the source code, not something wrong with the cpu I have nor JDK.
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.*;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable {
public static int width = 300;
public static int height = width / 16*9;
public static int scale = 3;
private Thread thread;
private boolean running = false;
private JFrame frame;
public synchronized void start() {
running = true;
thread = new Thread(this, "Display");
thread.start();
}
public synchronized void stop() {
running = false;
try{
thread.join();
}catch(InterruptedException e){
e.printStackTrace();
}
}
public void run(){
while(running){
tick();
render();
}
}
public void tick() {
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if(bs==null){
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
bs.dispose();
bs.show();
}
public Game() {
Dimension size = new Dimension(width * scale, height * scale);
setPreferredSize(size);
frame = new JFrame();
}
public static void main(String[] args) {
Game game = new Game();
game.frame.setResizable(false);
game.frame.setTitle("Title");
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setLocationRelativeTo(null);
game.frame.setVisible(true);
game.start();
}
}
Then I got this error, even when I countlessly modified the source code I had.
Exception in thread "Display" java.lang.NullPointerException
at java.awt.Component$BltBufferStrategy.showSubRegion(Component.java:4307)
at java.awt.Component$BltBufferStrategy.show(Component.java:4255)
at com.thecherno.Rain.Game.render(Game.java:58)
at com.thecherno.Rain.Game.run(Game.java:39)
at java.lang.Thread.run(Thread.java:695)
Im starting to seem if it because of an outdated JDK. Current Version I have is JDK 6.
You state:
What Im trying to do is change color as seen in the render method. The background to be black.
Use Swing components such as a JComponent or JPanel.
Simply call setBackground(Color.BLACK) on the component will do.
You appear to be creating a game loop of some type. Consider using a Swing Timer for this.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Game2 extends JPanel {
private static final int PREF_W = 300;
private static final int PREF_H = PREF_W / 16 * 9;
private static final int SCALE = 3;
private static final Color BACKGROUND = Color.BLACK;
private static final int TIMER_DELAY = 20;
private Timer swingTimer;
public Game2() {
setBackground(BACKGROUND);
swingTimer = new Timer(TIMER_DELAY, new TimerListener());
swingTimer.start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// TODO: add any custom painting here
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W * SCALE, PREF_H * SCALE);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// TODO add code that gets called in game loop
}
}
private static void createAndShowGui() {
Game2 mainPanel = new Game2();
JFrame frame = new JFrame("Game2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Note that this code is based on your stated requirements and what I'm guessing are other requirements based on your code. If there are further requirements not mentioned, please elaborate them for us.
Try using g.dispose(); followed by bs.show(); and then
g = (Graphics2D)bs.getDrawGraphics();. I know it looks weird, but you are emptying the canvas and then refilling it using your strategy. You may also need to do an initial check for g being null and initialize it before the first display loop.
I'm trying to make a fairly basic 3D game in preparation for what's to come when I enter Ludum Dare 23, an annual game competition.
I'm using Java and I'm using Swing and AWT. (I'm using JFrame to create my window (obviously? idk))
The problem I'm having is occurring when I'm attempting to draw pixels on the screen. I get a number of exceptions regarding BufferStrategy and what's apparently a Thread issue.
The following is what the console box in Eclipse is throwing me.
Exception in thread "Thread-2" java.lang.IllegalStateException: Component must have a valid peer
at java.awt.Component$FlipBufferStrategy.createBuffers(Component.java:3982)
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.ottdev.tale.TaleOfDwarvesComponent.render(TaleOfDwarvesComponent.java:66)
at com.ottdev.tale.TaleOfDwarvesComponent.run(TaleOfDwarvesComponent.java:55)
at java.lang.Thread.run(Thread.java:722)
Any ideas on how I could solve this issue? It's doing my head in and is preventing me from advancing. All help is highly appreciated!
PS: I can put up my source code if need be, but for now, I'd rather know how to fix it so I can know what to do if I encounter this situation in the future, but with different code.
EDIT: My main class -
TaleOfDwarvesComponent:
package com.ottdev.tale;
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
import com.ottdev.tale.gui.*;
public class TaleOfDwarvesComponent extends Canvas implements Runnable {
public static final int WIDTH = 800;
public static final int HEIGHT = 600;
public static final int SCALE = 2;
public static final String TITLE = "Tale Of Dwarves!";
private boolean running = false;
private BufferedImage img;
public int[] pixels;
private Thread thread;
private Game game;
private Screen screen;
public TaleOfDwarvesComponent() {
game = new Game();
screen = new Screen(WIDTH, HEIGHT);
img = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
}
public void start() {
if (running)
return;
running = true;
new Thread(this).start();
}
public void stop() {
if (!running)
return;
running = false;
try{
thread.join();
}catch(InterruptedException e){
e.printStackTrace();
}
}
public void run() {
while(running){
render();
}
}
public void tick(){
game.tick();
}
public void render(){
BufferStrategy bs = getBufferStrategy();
if(bs == null){
createBufferStrategy(3);
return;
}
screen.render(game);
for (int i = 0; i < WIDTH * HEIGHT; i++){
pixels[i] = screen.pixels[i];
}
Graphics g = bs.getDrawGraphics();
g.fillRect(0, 0, getWidth(), getHeight());
g.drawImage(img, 0, 0, WIDTH * SCALE, HEIGHT * SCALE, null);
g.dispose();
bs.show();
}
public static void main(String[] args) {
TaleOfDwarvesComponent game = new TaleOfDwarvesComponent();
JFrame frame = new JFrame();
frame.setSize(WIDTH, HEIGHT);
frame.setLocationRelativeTo(null);
frame.setTitle(TITLE);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
game.start();
}
}
I have a Bitmap class and a Screen class, but for now, I'll put this up in hope that the answer to my troubles can be obtained from this.
If you look at the javadocs http://docs.oracle.com/javase/7/docs/api/java/awt/Canvas.html#createBufferStrategy(int)
I believe it specifically addresses your problem, that is, that you are calling createBufferStrategy before the Canvas is displayed on the screen. So to solve your problem, you need to either add a ComponentListener to your Canvas and call createBufferStrategy on componentShown, or call this in your paint method