Canvas or Jcomponent????

Hi all, just wanted to ask about which one is better to use and there main differences…

I’m just starting out has an game developer I have done some tutorials and all that but all of them used JFrame has the drawing canvas and well Ra4king told me about Jcomponent and I’m trying it out right now
but looking at a code from notch’s minicraft I saw that he used has he’s drawing object a Canvas, so I wanted to ask your opinions on this guys.

If put it rough, I’ll say Canvas. Both of them can be used pretty well, just Canvas has BufferStrategy inside which can you grab.

Canvas is an AWT component. It does not do double buffering out-of-the-box, but you can fairly easy write code to make it double buffered. Search this forum for discussions about it (or look at Notch’s code and whatever other examples you find that use it).

JComponent is a Swing component. Swing was built on top of AWT, and added many features, one of which was that its components are double buffered out-of-the-box. This means that you can paint onto a JComponent and not have to write your own double-buffering code like you do with Canvas.

One of the main reasons people often recommend using Canvas/BufferStrategy for games is that Swing simply isn’t needed for most games. You don’t need any of the benefits Swing gives you, since they’re GUI-specific and not really game-centric (a configurable set of standard components, etc.). The double-buffering would be the only benefit, and you can get that from Canvas with a small amount of code. Canvas/BufferStrategy is a “lowest-common denominator,” in a manner of speaking.

The thing you need to understand is that there are 2 kinds of ways to make game loops and render.

The first one is called passive rendering. This involves having a loop that runs until the game is closed and this loop updates the game and then calls repaint(). This is called passive rendering because repaint() actually just notifies the Event Dispatching Thread (which is a separate thread from your game loop) to repaint the game. Since your logic and rendering are on separate threads, things could get out of sync or data could be modified while the screen is being redrawn.

The second one is called active rendering. This involves the same game loop but with 1 difference: the rendering code is included as part of the loop. Logic and rendering are in 1 thread. This makes your code thread safe and things will always be in sync.

Of course, the best method here is active rendering. With JComponent, you have to call repaint() in your loop so that is passive rendering. With Canvas, you could also extend it and call repaint(), but it is best used for active rendering. What you do is you create a Canvas object (don’t subclass it), create a BufferStrategy, and use the BufferStrategy to render.

EDIT: For more in-depth code that includes FPS and sleeping method, refer to http://www.java-gaming.org/index.php/topic,26222.msg229028.html#msg229028

Example code:


public class MyGame implements Runnable {
    public static void main(String[] args) {
        new Thread(new MyGame()).start();
    }

    private final int WIDTH = 800, HEIGHT = 600;
    
    public void run() {
        JFrame frame = new JFrame("My game");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.setIgnoreRepaint(true); //IMPORTANT, MUST INCLUDE!
        
        Canvas canvas = new Canvas();
        canvas.setPreferredSize(new Dimension(WIDTH,HEIGHT));
        canvas.setIgnoreRepaint(true); //IMPORTANT, MUST ALSO INCLUDE!
        frame.add(canvas);
        
        frame.pack():
        frame.setVisible(true);
        
        canvas.createBufferStrategy(2);
        
        BufferStrategy strategy = canvas.getBufferStrategy();
        
        while(isRunning) {
            update();
            
            //Must setup these do-while loops like this
            do{
                do{
                    Graphics2D g = (Graphics2D)strategy.getDrawGraphics();
                    
                    render(g);
                    
                    g.dispose();
                }while(strategy.contentsRestored());
                
                strategy.show();
            }while(strategy.contentsLost());

            //sleep
        }
    }
    
    public void update() {
        //update logic
    }
    
    public void render(Graphics2D g) {
        //render your game
    }
}

Ill have to try the canvas later on when i have learned more for mi I think it’s still a little bit complicated but thanks a lot for all your answers

Actually, you can implement active rendering in Swing components, very similarly to what you do with Canvas. And there’s no need to worry about synchronizing Threads if you keep your logic on the EDT via javax.swing.Timer.



import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;

public class test extends JFrame {

	public test() {
		AnimatedPanel cp = new AnimatedPanel();
		cp.start();
		setContentPane(cp);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		pack();
		setLocationRelativeTo(null);
	}

	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				new test().setVisible(true);
			}
		});
	}

	public class AnimatedPanel extends JPanel implements ActionListener {

		private Random random;

		public AnimatedPanel() {
			setPreferredSize(new Dimension(300, 300));
			random = new Random();
			setIgnoreRepaint(true);
		}

		public void actionPerformed(ActionEvent e) {
			int r = random.nextInt(256);
			int g = random.nextInt(256);
			int b = random.nextInt(256);
			Graphics gfx = getGraphics();
			gfx.setColor(new Color(r, g, b));
			gfx.fillRect(0, 0, getWidth(), getHeight());
		}
		
		public void start() {
			new javax.swing.Timer(20, this).start();
		}

	}
}

Example code:


public class MyGame implements Runnable {
    public static void main(String[] args) {
        new Thread(new MyGame()).start();
    }

    private final int WIDTH = 800, HEIGHT = 600;
    
    public void run() {
        JFrame frame = new JFrame("My game");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(WIDTH,HEIGHT);
        frame.setResizable(false);
        frame.setIgnoreRepaint(true); //IMPORTANT, MUST INCLUDE!
        
        Canvas canvas = new Canvas();
        canvas.setIgnoreRepaint(true); //IMPORTANT, MUST ALSO INCLUDE!
        frame.add(canvas);
        
        frame.setVisible(true);
        
        canvas.createBufferStrategy(2);
        
        BufferStrategy strategy = canvas.getBufferStrategy();
        
        while(isRunning) {
            update();
            
            //Must setup these do-while loops like this
            do{
                do{
                    Graphics2D g = (Graphics2D)strategy.getDrawGraphics();
                    
                    render(g);
                    
                    g.dispose();
                }while(strategy.contentsRestored());
                
                strategy.show();
            }while(strategy.contentsLost());

            //sleep
        }
    }
    
    public void update() {
        //update logic
    }
    
    public void render(Graphics2D g) {
        //render your game
    }
}

[/quote]
Thanks, was just thinking it would be good to have a canvas skeleton to keep, I really need to build up a templates folder. Maby a thread with canvas, jFrame, Slick - basicGame, ETC examples would be an idea. Ill pen something :slight_smile: