New to game programming

Hello,
today I wrote a short programm, to play around with canvas and a little with the MouseListener.
For the Graphic part I used ra4kings given code or rather the one from http://ra4king.is-a-geek.net/javadocs/java/awt/image/BufferStrategy.html.
My Programm works fine, as long as I have a while(true) loop to refresh my frame contents. Buf if I remove the loop and add render() (rander is the method that redraws my canvas, it’s also the one with the while(true) loop from before) tags, in exchange, to the methods that modify my graphicoutput, then I only see my “image” for a split second and then I only see gray until I do something that activates the render method again.

Hope you can help me with the short Explanation I gave you, if it’s not enough tell me and I’ll add the code

biro

Edit:
It’s me again. I got my Programm so far, that it shows me the correct screen after I drag my mouse. But before I do that (in between the time after my startup and before the first mouseDragged() method starts) I only see a gray screen, except for a short “blinking” in which I believe to see the correct screen.
Here the important parts of the code:

public synchronized void render() {		
	  // Prepare for rendering the next frame
    // ...
    // Render single frame
		BufferedImage g = null; //Green Image for a green background
		BufferedImage s = null; //Black Image for a black background
		try {
			g = ImageIO.read(new File("green.png"));
			s = ImageIO.read(new File("schwarz.png"));
		} catch (IOException ie) {
			ie.printStackTrace();
			System.exit(0);
		}
		
		do {
			// The following loop ensures that the contents of the drawing buffer
			// are consistent in case the underlying surface was recreated
			do {
				// Get a new graphics context every time through the loop
				// to make sure the strategy is validated
				Graphics graphics = strategy.getDrawGraphics();

				// Render to graphics
				// ...
				for (int x = 0; x < xMax(); x++) {
					for (int y = 0; y < yMax(); y++) {
						BufferedImage draw = null;
						int drawx = this.activetilex+x;
						int drawy = this.activetiley+y;
						if (drawx >= this.tilesx || drawy >= this.tilesy || drawx < 0 || drawy < 0) { //Außerhalb des Arrays
							draw = s;
						} else {
							switch (feld[drawx][drawy].getTyp()) {
							  case 1: //Grün
								  draw = g;
								  break;
							  default:
								  draw = s;
							}
						}
						if (x == 0 && y == 0) {
							BufferedImage newdraw = draw.getSubimage(this.activex, this.activey, this.tilewidth-this.activex, this.tileheigth-this.activey);
							graphics.drawImage(newdraw, 0, 0, null);
						} else if (x == 0) {
							BufferedImage newdraw = draw.getSubimage(this.activex, 0, this.tilewidth-this.activex, this.tileheigth);
							graphics.drawImage(newdraw, 0, y*this.tileheigth-this.activey, null);
						} else if (y == 0) {
							BufferedImage newdraw = draw.getSubimage(0, this.activey, this.tilewidth, this.tileheigth-this.activey);
							graphics.drawImage(newdraw, x*this.tilewidth-this.activex, 0, null);
						} else {
							graphics.drawImage(draw, x*this.tilewidth-this.activex, y*this.tileheigth-this.activey, null);
						}
					}
				}
				// Dispose the graphics
				graphics.dispose();

				// Repeat the rendering if the drawing buffer contents
				// were restored
			} while (strategy.contentsRestored());

			// Display the buffer
			strategy.show();

			// Repeat the rendering if the drawing buffer was lost
		} while (strategy.contentsLost());			
	}

This is my render method.

	private Canvas board;
	private BufferStrategy strategy;
	private MapMover mouselistener;
	private GuiListener listener;
	
	private int tilewidth = 50; //Breite eines Felds in Pixeln / Width of one field in pixels
	private int tileheigth = 50; //Höhe eines Felds in Pixeln / Heigth of one field in pixels
	private int showwidth = 800; //Fensterbreite /Windowwidth
	private int showheigth = 600;//Fensterhöhe  /Windowheigth
	private int activetilex = 0; //Welches Tile sehen wir gerade /Which tile on the x axis do we see
	private int activetiley = 0; //dito /Same as above for the y axis
	private int activex = 0; //Verschiebung des Tiles noch links / adjustment of the tile to the left 
	private int activey = 0; //Verschiebung des tiles nach oben /adjustment of the tile to top
	private int tilesx = 25; //Anzahl an Tiles auf der x-Achse insgesammt /Sum of tiles on the x-axis
	private int tilesy = 15; //Anzahl an Tiles auf der y-Achse insgesammt /Sum of tiles on the y-axis

Here the class attributes, these also have getter and setter methods!

	
                public Gui() {
		super();
		initField();
		listener = new GuiListener(this);
		initGUI();
		board.createBufferStrategy(2);
		this.strategy = board.getBufferStrategy();		
		mouselistener = new MapMover(this);
		board.addMouseListener(mouselistener);
		board.addMouseMotionListener(mouselistener);
		this.setVisible(true);
		render();
	}

And here my startup routine

Like I said the render method link in the startup method fabricates a short correct screenblink and than the screen get’s gray agains.
Because the MouseListener and MouseMotionListener is doing it’s job correct I won’t post it now, if you ant it pls tell me.

Many thanks for your help
biro

@ReBirth
I think that Canvas has a setPreferredSize() method as well so if you wanted you could probably cut out the JPanel there. Unless of course there are other things you need the JPanel for.

You need to start a new thread where the run method has the game loop. So change render() to run(), implement Runnable, and start a new thread at the end of the constructor.

Hello,
thanks for your answer.
But how does it help to implement a new Thread for the drawing? because I don’t want an endless loop to redraw my graphic content, because it eats to many ressources (with the endlessloop before which is like a new thread, one of my cores was 100% used). Hope you can explain that to me, why I should implement a thread there^^

biro

You need a constant FPS, which will not use the CPU much. That’s what all games use, an endless game loop with a constant refresh rate and it updates the game logic and graphics.

you make it sound so simple… been reading a lot of tutorials and that line kind of made everything come together and make sense… the idea of a video game seems really simple now

Hello,
thanks for your answers, but in my case I don’t need a constants update loop. I only want to update the screen, when it’s need, which is after you drag the screen or you resize the frame and after you start the programm. So why should I use a thread, which burns so many many resources, and when I need a thread, how much should I reduce the the framerate (I believe I should do it with the sleep() command, so how many millisecs. should I let the thread sleep?).

Thanks a lot for your answers
biro

If you want something that is not a still image, you need an update loop. You’re just drawing pictures fast, so it looks like things move. If you don’t update you have a picture without any animation.

Hello,
my problem is not the animation, at the moment I have no real animation, I only need to update the field, when a user gives a command, that changes the world in some aspects. Then should the world be refreshed. And for that I don’t need a loop if I’m not wrong, the problem is, that if I don’t use a loop and draw the pictures on the screen I see them for a few milliseconds after these few milliseconds I see a gray window again, and I want to know why.
I know that when I want to add animations I need a constant loop, that refreshs my screen, but at the moment that is not needed :wink:
But let’s look a bit in the future, to a time when I add animations or some other feature that needs a graphic refresh loop, than how should I drossel it, so that it won’t eat 100% of my CPU power? My guess is that I should use sleep() for that, but how do I calculate the right amount of milliseconds my thread should sleep, so that my cpu doesn’t need to create such a high output and on the other hand, that my “animation” is still fluid?
Please don’t forget to answer the question about doing it at first without a loop and why the correct screen is only shown for a split second.

Greetings
biro

use double buffering.

Hello,

Please take a look at my code, if you do you’ll see that I use the double buffer from canvas, so that is definitivly not the reason!

biro

That call to render only happens once. If you want it to redraw the screen based on an input event, like a mouse or key, then you just need to call render() in your listeners.

hello,
like I said, I do that in my Listeners, each time someone draggs the screen, the render method is called, and this part works, the problem is the render tag after the startup in my construktor Gui() (see my posted code), this render invoking shows for a few milliseconds the desired screen, after these few milliseconds it get’s gray agai, until I invoke the render() method throug my listener. Any Ideas?

Oh then that sounds like something is refreshing your screen? Try calling “setIgnoreRepaint(true)” in your constructor so a system call to repaint() would be ignored.

hello,
I will try that tomorrow!
One more question: if you add a render loop, how high do you set the framerate or fps, and how do you ensure, that the framerate is being kept.

Many Greetings biro

60 FPS is the norm these days as almost all monitors these days refresh at that rate.

@biro
I have created a kind of game that has no animation and only update on click, sudoku :smiley: Use JPanel instead canvas like I did. On my sudoku (it’s working well):


public class yourClass extends JPanel{
     public void paint(Graphics g){
          super.paint(g);
          Graphics2D g2d=(Graphics2D)g.create();
          //use g2d to draw everything
	  Toolkit.getDefaultToolkit().sync();
	  g2d.dispose();
     }
}

I use something like this before know about canvas.

@Rebirth
No Canvas is always better to draw on than JPanel. Plus JComponent is more fit for painting than JPanel.
Also, you should never override the paint() method of any Swing component. paintComponent() is there for your painting needs instead.

Hello,
@ReBirth: isn’t it better to use only the normal swing components for a sudoku-game? In the past weeks I wrote one too as a gift for a family member and as practice, I only used JPanels for the blocks and JLabels and JTextFields for the single numbers. If they were given I use a JLabel and if not a JTextField with a validater behind it.

biro

Edit:
@ra4king: don’t you mean setIgnoreRepaint(true)? because false is the standart value… So it would be meaningles to set it false…
Should I setIgnoreRepaint on the canvas as well or only on the JFrame?

Hehe my bad, I didn’t notice that typo. Yes it is supposed to be “true”. And setting it on the JFrame will set it globally.