Problems with thread and bufferstrategy: IllegalStateException: Component must have a valid peer - java

Here is the code that I tried to execute, but failed:
public class Game extends Canvas implements Runnable,KeyListener {
private static final long serialVersionUID = 1L;
private static Thread thread ;
private int width = 240;
private int height = 120;
private int scale = 3;
private boolean isRunning = true;
private BufferedImage image;
public static Spritesheet spritesheet;
private Player player;
Game(){
Dimension dimension = new Dimension(width*scale,height*scale);
this.setPreferredSize(dimension);
image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
}
void initframe() {
JFrame f = new JFrame("Game");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setVisible(true);
f.setLocationRelativeTo(null);
f.setResizable(false);
}
public synchronized void start() {
thread = new Thread(this);
isRunning = true;
thread.start();
}
public synchronized void stop() {
isRunning = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Game game = new Game();
game.start();
}
void tick() {
}
void render() {
BufferStrategy bs = this.getBufferStrategy();
if(bs == null) {
this.createBufferStrategy(3);
return;
}
Graphics g = image.getGraphics();
g.setColor(Color.GREEN);
g.fillRect(0, 0, width, height);
g.dispose();
g = bs.getDrawGraphics();
g.drawImage(image, 0, 0, width*scale,height*scale,null);
bs.show();
}
public void run() {
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = (10^9)/amountOfTicks ;
int frames = 0;
double delta;
double timer = System.currentTimeMillis();
while(isRunning) {
long now = System.nanoTime();
delta = (now - lastTime)/ns ;
lastTime = now;
if(delta >= 1) {
tick();
render();
frames++;
delta--;
}
if(System.currentTimeMillis() - timer >= 1000) {
System.out.println(" A taxa de fps e: "+frames);
frames = 0;
timer+=1000;
}
}
stop();
}
And the error that appears to me is:
Exception in thread "Thread-0" java.lang.IllegalStateException: Component must have a valid peer
at java.desktop/java.awt.Component$FlipBufferStrategy.createBuffers(Component.java:4105)
at java.desktop/java.awt.Component$FlipBufferStrategy.<init>(Component.java:4079)
at java.desktop/java.awt.Component$FlipSubRegionBufferStrategy.<init>(Component.java:4611)
at java.desktop/java.awt.Component.createBufferStrategy(Component.java:3942)
at java.desktop/java.awt.Canvas.createBufferStrategy(Canvas.java:195)
at java.desktop/java.awt.Component.createBufferStrategy(Component.java:3866)
at java.desktop/java.awt.Canvas.createBufferStrategy(Canvas.java:170)
at com.main.Game.render(Game.java:83)
at com.main.Game.run(Game.java:115)
at java.base/java.lang.Thread.run(Thread.java:834)
I checked out every line of this code and I don't know why show that the problem is with thread or bufferStrategy, the method render or method run that I used.

Related

Why is this game loop implementation getting a lower framerate than one that does more calculations per iteration?

I attempted to create my own implementation of a "game loop" using javax.swing and java.awt, but when my target fps was 60, I only got 49-52 fps on my implementation, while another implementation got 59-61 fps. Why would my implementation get a lower framerate if it's doing fewer calculations?
My Implementation:
public class MainContainer implements Runnable {
public Thread thread;
private final String title = "Window";
private int width = 800, height = 600;
private float scale = 1f;
private GameWindow window;
private final int FPS = 60;
private final long NS_PER_UPDATE = (long)((1.0d/FPS) * 1000000000);
private int current_total = 0;
private boolean running;
public MainContainer(){
running = true;
start();
}
public void start(){
window = new GameWindow(this);
thread = new Thread(this);
thread.run();
}
public void stop(){
}
#Override
public void run() {
long old = System.nanoTime();
long counterOld = System.nanoTime();
long missedTime;
double frames = 0;
long current;
long delta;
long counterDelta;
while(running){
current = System.nanoTime();
delta = current - old;
counterDelta = current - counterOld;
if(counterDelta >= 1000000000){
System.out.println(frames / (counterDelta/1000000000.0));
frames = 0;
counterOld = System.nanoTime();
}
if(delta >= NS_PER_UPDATE){
render();
missedTime = delta - NS_PER_UPDATE;
old = System.nanoTime() - missedTime;
frames++;
}else{
try {
thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void render(){
window.update();
}
public static void main(String[] args) {
MainContainer main = new MainContainer();
}
public int getWidth(){
return width;
}
public int getHeight(){
return height;
}
public float getScale(){
return scale;
}
public void setScale(float s){
scale = s;
}
public String getTitle(){
return title;
}
public GameWindow getWindow(){
return window;
}
}
Other Implementation:
public class MainContainer implements Runnable {
public Thread thread;
private final String title = "Window";
private int width = 800, height = 600;
private float scale = 1f;
private final int FPS = 60;
private final long NS_PER_UPDATE = (long)((1.0d/FPS) * 1000000000);
private boolean running;
private GameWindow window;
public MainContainer(){
running = true;
start();
}
public void start(){
window = new GameWindow(this);
thread = new Thread(this);
thread.start();
}
public void stop(){
}
#Override
public void run() {
long unprocessedTime = 0;
long frameTime = 0;
double frames = 0;
boolean render = false;
long current;
long delta;
long old = System.nanoTime();
while(running){
current = System.nanoTime();
delta = current - old;
old = current;
unprocessedTime += delta;
frameTime += delta;
while(unprocessedTime >= NS_PER_UPDATE){
old = System.nanoTime();
unprocessedTime -= NS_PER_UPDATE;
render = true;
if(frameTime >= 1000000000){
System.out.println(frames / (frameTime/1000000000.0));
frameTime = 0;
frames = 0;
}
}
if(render){
render();
frames++;
render = false;
}else{
try {
thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void render(){
window.update();
}
public static void main(String[] args) {
MainContainer main = new MainContainer();
}
public int getWidth(){
return width;
}
public int getHeight(){
return height;
}
public float getScale(){
return scale;
}
public void setScale(float s){
scale = s;
}
public String getTitle(){
return title;
}
public GameWindow getWindow(){
return window;
}
}
GameWindow Class:
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
public class GameWindow {
private JFrame frame;
private BufferedImage image;
private Canvas canvas;
private BufferStrategy bs;
private Graphics g;
private boolean blue;
private MainContainer mc;
public GameWindow(MainContainer mc) {
this.mc = mc;
image = new BufferedImage(mc.getWidth(), mc.getHeight(), BufferedImage.TYPE_INT_RGB);
canvas = new Canvas();
Dimension s = new Dimension((int)(mc.getWidth() * mc.getScale()), (int)(mc.getHeight() * mc.getScale()));
canvas.setPreferredSize(s);
canvas.setMinimumSize(s);
canvas.setMaximumSize(s);
frame = new JFrame(mc.getTitle());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(canvas, BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
canvas.createBufferStrategy(2);
bs = canvas.getBufferStrategy();
g = bs.getDrawGraphics();
}
public void update(){
int[] p = ((DataBufferInt)(this.getImage().getRaster().getDataBuffer())).getData();
for(int i = 0; i < p.length; i++){
p[i] += i;
}
g.drawImage(image, 0, 0, canvas.getWidth(), canvas.getHeight(), null);
bs.show();
}
public BufferedImage getImage(){
return image;
}
}
Because in the "Other Implementation" its calculating the old time before the rendering process and in your implentation it is calculating it after the rendering process which make the value bigger because it is now also including the time it takes to render. So if you flip the code in your if statement around to look like this it will run at around 60 fps:
if(delta >= NS_PER_UPDATE){
missedTime = delta - NS_PER_UPDATE;
old = System.nanoTime() - missedTime;
render();
frames++;
}

Java Game: Mouse Control and border(rectangle) issue

The 20 x 20 box is not being displayed(including motion listener and no errors). Another class is the window which sets up the JFrame and game start(). Here is the code below(with a package called "javagame9" .
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = -2713820159854096116L;
public static final int WIDTH = 640, HEIGHT = 700;
private Thread thread;
private boolean running = false;
public static boolean paused = false;
public Game() {
this.addMouseMotionListener(new Mouse());
new Window(WIDTH, HEIGHT, "A Game", 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() {
this.requestFocus();
long LastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
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() {
}
public static void main(String args[]) {
new Game();
}
}
public class Mouse extends Canvas implements MouseMotionListener {
private static final long serialVersionUID = 7986961236445581989L;
private Image dbImage; //Mouse - class
private Graphics dbg;
int mx, my;
boolean mouseDragged;
public void paint(Graphics g) {
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
public void paintComponent(Graphics g) {
if (mouseDragged) {
g.setColor(Color.DARK_GRAY);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.LIGHT_GRAY);
g.fillRect(mx, my, 20, 20);
} else {
g.setColor(Color.LIGHT_GRAY);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.DARK_GRAY);
g.fillRect(mx, my, 20, 20);
}
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
mx = e.getX() - 10;
my = e.getY() - 10;
mouseDragged = true;
e.consume();
}
public void mouseMoved(MouseEvent e) {
mx = e.getX() - 10;
my = e.getY() - 10;
mouseDragged = false;
e.consume();
}
}
The problem is that you have 2 Canvas: Game and Mouse.
Assuming that the Window class is the following (found it here):
public class Window extends Canvas {
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(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.add(game);
frame.setVisible(true);
game.start();
}
}
we see that the Canvas being added to the JFrame is the Game one, so it will be the one visible.
But you are only painting on the Mouse canvas, therefore you are not going to see anything.
You could move the paint logic from Mouse to Game, and use Mouse only for the MouseMotionListener functionality.
Modified Game class (differences highlighted by comments):
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = -2713820159854096116L;
public static final int WIDTH = 640, HEIGHT = 700;
private Thread thread;
private boolean running = false;
public static boolean paused = false;
// fields previously in Mouse moved here:
private Image dbImage;
private Graphics dbg;
// mouse field so we can reuse it
private Mouse mouse;
public Game() {
// we create an instance of mouse and use it as MouseMotionListener
mouse = new Mouse();
this.addMouseMotionListener(mouse);
new Window(WIDTH, HEIGHT, "A Game", 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();
}
}
#Override
public void run() {
this.requestFocus();
long LastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
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() {
}
public static void main(String args[]) {
new Game();
}
// paint methods previously in Mouse moved here:
#Override
public void paint(Graphics g) {
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
public void paintComponent(Graphics g) {
if (mouse.mouseDragged) {
g.setColor(Color.DARK_GRAY);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.LIGHT_GRAY);
g.fillRect(mouse.mx, mouse.my, 20, 20);
}
else {
g.setColor(Color.LIGHT_GRAY);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.DARK_GRAY);
g.fillRect(mouse.mx, mouse.my, 20, 20);
}
repaint();
}
}
Now from the Mouse class you can remove all the methods/fields used for the painting, also it no longer extends Canvas:
public class Mouse implements MouseMotionListener {
private static final long serialVersionUID = 7986961236445581989L;
int mx, my;
boolean mouseDragged;
#Override
public void mouseDragged(MouseEvent e) {
mx = e.getX() - 10;
my = e.getY() - 10;
mouseDragged = true;
e.consume();
}
#Override
public void mouseMoved(MouseEvent e) {
mx = e.getX() - 10;
my = e.getY() - 10;
mouseDragged = false;
e.consume();
}
}
Using these classes you should now be able to see what you are painting.

Using a keylistener to output a pressed key

I am following a tutorial online which reads key presses. It is quite an old video so I'm not sure if the syntax has changed. I've also looked at other questions on here and can't seem to find a solution.
My issue is that it is not printing a pressed key to the console. No error is being thrown to me
Game.Java:
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.util.Random;
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = 240840600533728354L;
public static final int WIDTH = 640, HEIGHT = WIDTH / 12 * 9;
private Thread thread;
private boolean running = false;
private Random r;
private Handler handler;
public Game(){
handler = new Handler();
this.addKeyListener(new KeyInput());
new Window(WIDTH, HEIGHT, "The Game", this);
r = new Random();
handler.addObject(new Player(WIDTH/2-32,HEIGHT/2-32,ID.Player));
handler.addObject(new Player(WIDTH/2+64,HEIGHT/2-32,ID.Player2));
}
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();
double amountOfTicks = 60.0;
double ns = 10000000; //amount of ticks
double delta = 0;
long timer = System.currentTimeMillis();
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(){
handler.tick();
}
private void render(){
BufferStrategy bs = this.getBufferStrategy();
if(bs == null){
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.black);
g.fillRect(0, 0, WIDTH, HEIGHT);
handler.render(g);
g.dispose();
bs.show();
}
public static void main(String args[]){
new Game();
}
}
KeyInput.Java
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
public class KeyInput extends KeyAdapter {
private Handler handler;
//public KeyInput(Handler handler){
// this.handler = handler;
//}
public void keyPressed(KeyEvent e){
int key = e.getKeyCode();
System.out.println(key);
}
public void keyReleased(KeyEvent e){
int key = e.getKeyCode();
}
}
Your thread terminates immediately after you start it, because of this:
thread.start();
running = true;
this causes your thread to terminate because when it is started the variable is not yet set to true
public void run() {
...
while(running){ //here is the problem, this variable is stil false now
}
Therfore change the order of the two statements and it should work:
public synchronized void start() {
thread = new Thread(this);
running = true;
thread.start();
}
Edit: and be aware that you should do your rendering in the EventDispatchThread!
I tried adding focus and it worked, thanks to #user7291698
public Game(){
setFocusable(true);
requestFocus();
requestFocusInWindow();
handler = new Handler();
this.addKeyListener(new KeyInput());
new Window(WIDTH, HEIGHT, "The Game", this);
r = new Random();
handler.addObject(new Player(WIDTH/2-32,HEIGHT/2-32,ID.Player));
handler.addObject(new Player(WIDTH/2+64,HEIGHT/2-32,ID.Player2));
}

MouseEvent canceling

I am creating a MouseEvent and it seems to be cancelling a few ticks after it starts as I can sometimes get a small response before it stops responding. Does anyone see why?
Here is where I initialize in init()
public class Game implements Runnable {
private Display display;
private int width, height;
public String title;
private boolean running = false;
private Thread thread;
private BufferStrategy bs;
private Graphics g;
//Input
Mouse mouse;
//Handler
private Handler handler;
public Game(String title, int width, int height){
this.title = title;
this.width = width;
this.height = height;
mouse = new Mouse();
}
public synchronized void start(){
if(running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
public synchronized void stop(){
if(!running)
return;
running = false;
try {
thread.join();
}
catch (InterruptedException e){ e.printStackTrace(); }
}
public void run() {
init();
int fps = 60;
double timePerTick = 1000000000 / fps;
double delta = 0;
long now;
long lastTime = System.nanoTime();
long timer = 0;
int ticks = 0;
while(running){
now = System.nanoTime();
delta += (now - lastTime) / timePerTick;
timer += now - lastTime;
lastTime = now;
if(delta >= 1){
tick();
render();
ticks++;
delta--;
}
if(timer >= 1000000000){
ticks = 0;
timer = 0;
}
}
stop();
}
private void init() {
display = new Display(title, width, height);
display.getFrame().addMouseListener(mouse);
Assets.init();
handler = new Handler(this);
}
private void tick() {
Tile tile = new Tile();
tile.tick();
}
private void render() {
bs = display.getCanvas().getBufferStrategy();
if(bs == null){
display.getCanvas().createBufferStrategy(3);
return;
}
g = bs.getDrawGraphics();
g.clearRect(0, 0, width, height); //Clears the Screen
//Start of Drawing
ChessBoard cb = new ChessBoard(64);
cb.render(g);
cb.tick();
//End of Drawing
bs.show();
g.dispose();
}
}
And here is the MouseEvent
public class Mouse implements MouseListener {
public void mousePressed(MouseEvent e) {
System.out.println("1");
}
public void mouseReleased(MouseEvent e) {
System.out.println("2");
}
public void mouseEntered(MouseEvent e) {
System.out.println("3");
}
public void mouseExited(MouseEvent e) {
System.out.println("4");
}
public void mouseClicked(MouseEvent e) {
System.out.println("5");
}
}

My Java Picture won't show up correctly

I am trying to make a simple side-scrolling game and my background color won't work. It should fill the entire page, with an fps counter, but it only has a small line of color at the top of the pop up.
Here is my entire code so far (I had to copy and paste because I'm "not a level 10").
public static final int WIDTH = 640;
public static final int HIGHT = WIDTH / 4 * 3;
public static final String TITLE = "Sploocher's Epic Quest";
private static Game game = new Game();
private boolean running = false;
private Thread thread;
public void init(){
}
public void tick(){
}
public void renderBackground(Graphics g){
}
public void renderForeground(Graphics g){
}
public void render(){
BufferStrategy bs = this.getBufferStrategy();
if(bs == null) {
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillRect(0,0,WIDTH,HEIGHT);
//////////////////////////////////////////////////
renderBackground(g);
renderForeground(g);
g.dispose();
bs.show();
}
#Override
public void run() {
init();
long lastTime= System.nanoTime();
final double numTicks = 60.0;
double n = 1000000000 / numTicks;
double delta = 0;
int frames = 0;
int ticks = 0;
long timer = System.currentTimeMillis();
while(running){
long currentTime = System.nanoTime();
delta += (currentTime - lastTime) / n;
lastTime = currentTime;
if(delta >= 1){
tick();
ticks++;
delta--;
}
render();
frames++;
if(System.currentTimeMillis() - timer > 1000){
timer+=1000;
System.out.println(ticks + "Ticks, FPS: " + frames);
ticks = 0;
frames = 0;
}
}
stop();
}
public static void main(String args[]){
JFrame frame = new JFrame(TITLE);
frame.add(game);
frame.setSize(WIDTH, HIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setFocusable(true);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
frame.pack();
game.start();
}
private synchronized void start(){
if(running)
return;
else
running = true;
thread = new Thread(this);
thread.start();
}
private synchronized void stop(){
if(!running)
return;
else
running = false;
try {
thread.join();
} catch (InterruptedException e){
e.printStackTrace();
}
System.exit(1);
}
}
If anyone could help me figure out how to fix my code, I'd really appreciate it.

Categories

Resources