1

I am extending a Canvas and adding it to a JFrame. I understand that AWT and Swing should not be mixed and that drawing on JPanel is preferred but i'm trying to follow a game engine tutorial and i'd like to stick to it since I got it working so far. The Canvas has minimumSize, maximumSize, and prefferedSize set to the dimensions of 550, 400. When I do a draw call graphics.draw(0,0,550,400) it doesn't fill the entire screen as it should. I changed the draw call to graphics.draw(0,0,560,410) essentially adding 10px to it and it filled the entire screen. Whats wrong?

BTW: graphics.draw(10,10,550,400 draws the rectangle starting at the corner exactly so I don't think the JFrame is the issue.

The main call inside Launcher class

    public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            game.setMinimumSize(DIMENSIONS);
            game.setMaximumSize(DIMENSIONS);
            game.setPreferredSize(DIMENSIONS);

            game.frame = new JFrame(NAME);
            game.frame.setLayout(new BorderLayout());
            game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            game.frame.add(game, BorderLayout.CENTER);
            game.frame.pack();

            game.frame.setResizable(false);
            game.frame.setLocationRelativeTo(null);
            game.frame.setVisible(true);

            Logger.log(TAG, "Game starting");
            game.start();
        }
    });
}

The draw call, Launcher.HEIGHT and WIDTH are 550,400

    public void draw(float deltaTime, Graphics2D graphics) {
    graphics.setColor(Color.BLACK);
    graphics.fillRect(0, 0, 550, 400);
    graphics.setColor(Color.DARK_GRAY);
    graphics.fillRect(0, 0, 150, 40);
    graphics.fillRect(0, Launcher.HEIGHT - 100, Launcher.WIDTH, 100);
    graphics.setColor(Color.LIGHT_GRAY);
    graphics.fillRect(125, Launcher.HEIGHT - 100, 100, 350);
}

The extended Canvas class

public abstract class Game extends Canvas implements Runnable {
private static final String TAG = "Game";

public JFrame frame;
public JPanel panel;
public boolean isApplet = false;

private boolean gameRunning = false;

BufferStrategy bufferStrategy;

private Screen screen;
private Thread renderThread;

public synchronized void start() {
    // Canvas
    setBounds(0, 0, 550, 400);
    setIgnoreRepaint(true);
    createBufferStrategy(2);
    bufferStrategy = getBufferStrategy();

    // Screen, Handlers, ETC
    screen = getStartScreen();

    // Threads
    renderThread = new Thread(this, Launcher.NAME + "_main");
    renderThread.start();
    gameRunning = true;
}

@Override
public void run() {
    long startTime = System.nanoTime();

    while (gameRunning) {
        float deltaTime = (System.nanoTime() - startTime) / 1000000000.0f;
        startTime = System.nanoTime();

        screen.update(deltaTime);

        Graphics2D graphics = (Graphics2D) bufferStrategy.getDrawGraphics();

        screen.draw(deltaTime, graphics);

        graphics.dispose();
        bufferStrategy.show();

        // FPS Counter

        // FPS Capper
    }
}
}

Reqested SSCCE

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferStrategy;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

@SuppressWarnings("serial")
public class Game extends Canvas implements Runnable {

    public static final int WIDTH = 550;
    public static final int HEIGHT = 400;
    public static final Dimension DIMENSIONS = new Dimension(WIDTH, HEIGHT);

    public static final String NAME = "SSCCE";

    public boolean gameRunning = false;

    public JFrame frame;
    public BufferStrategy bufferStrategy;

    public static void main (String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                Game game = new Game();
                game.setMinimumSize(DIMENSIONS);
                game.setMaximumSize(DIMENSIONS);
                game.setPreferredSize(DIMENSIONS);

                game.frame = new JFrame(NAME);
                game.frame.setLayout(new BorderLayout());
                game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                game.frame.add(game, BorderLayout.CENTER);
                game.frame.pack();

                game.frame.setResizable(false);
                game.frame.setLocationRelativeTo(null);
                game.frame.setVisible(true);

                System.out.println("Game started");
                game.start();
            }
        });
    }

    public synchronized void start() {
        setSize(550, 400);
        setBounds(0, 0, 550, 400);
        setIgnoreRepaint(true);
        createBufferStrategy(2);
        bufferStrategy = getBufferStrategy();

        // Threads
        Thread renderThread = new Thread(this, NAME + "_main");
        renderThread.start();
        gameRunning = true;
    }

    @Override
    public void run() {
        while (gameRunning) {
            Graphics2D graphics = (Graphics2D) bufferStrategy.getDrawGraphics();

            graphics.setColor(Color.BLACK);
            graphics.fillRect(0, 0, WIDTH, HEIGHT);

            graphics.dispose();
            bufferStrategy.show();
        }
    }

}

As for the Java 2D game tutorial I am following it is a web series. Nevertheless, the link is the following click here. I modified the code quite a lot.

Modified for MadProgrammer

    import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferStrategy;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

@SuppressWarnings("serial")
public class Game extends Canvas implements Runnable {

    public static final int WIDTH = 550;
    public static final int HEIGHT = 400;
    public static final Dimension DIMENSIONS = new Dimension(WIDTH, HEIGHT);

    public static final String NAME = "SSCCE";

    public boolean gameRunning = false;

    public JFrame frame;
    public BufferStrategy bufferStrategy;

    public static void main (String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                Game game = new Game();
                game.setMinimumSize(DIMENSIONS);
                game.setMaximumSize(DIMENSIONS);
                game.setPreferredSize(DIMENSIONS);

                game.frame = new JFrame(NAME);
                game.frame.setLayout(new BorderLayout());
                game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                game.frame.add(game, BorderLayout.CENTER);
                game.frame.pack();

                game.frame.setResizable(false);
                game.frame.setLocationRelativeTo(null);
                game.frame.setVisible(true);

                System.out.println("Game started");
                game.start();
            }
        });
    }

    public synchronized void start() {
        setSize(550, 400);
        setBounds(0, 0, 550, 400);
        setIgnoreRepaint(true);
        createBufferStrategy(2);
        bufferStrategy = getBufferStrategy();

        // Threads
        Thread renderThread = new Thread(this, NAME + "_main");
        renderThread.start();
        gameRunning = true;
    }

    @Override
    public void run() {
        while (gameRunning) {
            Graphics2D graphics = (Graphics2D) bufferStrategy.getDrawGraphics();

            graphics.setColor(Color.RED);
            // Using getWidth()
            graphics.fillRect(0, 0, getWidth(), getHeight());
            graphics.setColor(Color.GREEN);
            // Using WIDTH which was used to set the size of the canvas
            graphics.fillRect(5, 5, WIDTH, HEIGHT);

            graphics.dispose();
            bufferStrategy.show();

            try {
                Thread.sleep(60);
            } catch (InterruptedException ex) {
            }
        }
    }

}
synjunked
  • 35
  • 1
  • 6
  • Can you post some code that you have so far? – Nihathrael Feb 05 '13 at 08:25
  • Can you show some code? Setting `minimumSize`, `maximumSize`, and `prefferedSize` alone is not sufficient without a layout manager - to set the actual size, use `setSize()` – Andreas Fester Feb 05 '13 at 08:25
  • Your LayoutManager probably changes the Canvas' size anyway. Post your code that buildsthe gui. – Dariusz Feb 05 '13 at 08:26
  • Code posted, thanks for all of the replies! – synjunked Feb 05 '13 at 08:29
  • For better help sooner, post an [SSCCE](http://sscce.org/). – Andrew Thompson Feb 05 '13 at 08:54
  • *"i'm trying to follow a game engine tutorial"* Link to it. – Andrew Thompson Feb 05 '13 at 08:56
  • Added additional information as requested. – synjunked Feb 05 '13 at 09:07
  • The posted working example, works fine. Beware of magic numbers, use `getWidth` and `getHeight` instead. Make sure you are creating your buffer strategy off the `Canvas` and not the frame – MadProgrammer Feb 05 '13 at 09:21
  • MadProgrammer, yes the rectangle fills but not the entire screen. If you use `560, 410` instead of `550, 400` you would notice the difference. Another clear example would be to shift the `x, y` in the draw call up 10px. With `getWidth` and `getHeight` it would fill the entire screen. If i'm not mistaken shouldn't `getWidth` and `getHeight` be `550, 400`? – synjunked Feb 05 '13 at 09:26
  • getWidth/height will give you more flexibility if the shape changes or if an OS decides that the size of the window won't be the same as the requested by the Canvas. And what do you mean by "not the entire screen"? You example fills the window – MadProgrammer Feb 05 '13 at 09:36
  • My example does not, the value I got from `getWidth()` was `560` and the `WIDTH` value held `550`. So it couldn't have possibly have filled the entire screen, additionally if you look closely and compare you would see that part of the right and bottom side arn't filled. I understand why getWidth/Height should be used as for flexibility but doesn't setting `setResizable(false)` negate that? Also, what can I do to have getWidth/Height return to me the `550/400`? As for the information given, I greatly appreciate it. – synjunked Feb 05 '13 at 09:42
  • Make sure that you are using the values from the canvas and not the frame. The frame will generally by larger, in order to accommodate the frame border. Fixing the size seems like a good idea, but I would avoid it using static values as it leads to bad design - IMHO. When you decide to change the size of the playable area, suddenly you code could break (especially when it becomes more complex). Using the `getWidth/Height` from the canvas means you have a more reliable source of information - IMHO – MadProgrammer Feb 05 '13 at 09:51

1 Answers1

3

The example you've provide works fine. I modified it a little to demonstrate the use of getWidth/height

enter image description here

public void run() {
    while (gameRunning) {
        Graphics2D graphics = (Graphics2D) bufferStrategy.getDrawGraphics();

        graphics.setColor(Color.RED);
        graphics.fillRect(0, 0, getWidth(), getHeight());
        graphics.setColor(Color.GREEN);
        int width = getWidth() - 50;
        int height = getHeight() - 50;
        graphics.fillRect(25, 25, width, height);
        graphics.setColor(Color.BLACK);
        FontMetrics fm = graphics.getFontMetrics();
        graphics.drawString("Frame Size: " + frame.getWidth() + "x" + frame.getHeight(), 0, fm.getAscent());
        graphics.drawString("Canvas Size: " + getWidth() + "x" + getHeight(), 0, fm.getAscent() + fm.getHeight());

        graphics.dispose();
        bufferStrategy.show();
        try {
            Thread.sleep(60);
        } catch (InterruptedException ex) {
        }
    }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • I edited my question, please compile it to see what I mean. I don't understand why `getWidth` would give me a value that is 10px high than `WIDTH` which I used for the Canvas dimensions, bounds, and size. I also set the JFrame to un-resizeable. I understand that `getWidth` would give me more accurate dimensions but ultimately what I want done is for `WIDTH` and `getWidth` to share the similar value. – synjunked Feb 05 '13 at 09:58
  • The FRAME is ALWAYS going to be bigger then the canvas. The frame has a border. This is way it's important to make sure you are creating the buffer strategy from the `Canvas` and not the frame. – MadProgrammer Feb 05 '13 at 10:01
  • right, but I am setting the `Canvas` to those dimensions and not the frame. The frame has no dimensions and is simply stretching to fit the Canvas. – synjunked Feb 05 '13 at 10:03
  • @synjunked From your updated example, I still have no issue. Make sure when you call `getWidth/Height` on the `Canvas` and not the frame. – MadProgrammer Feb 05 '13 at 10:06
  • Ahh, I guess this is a perfect example of using `getWidth` over static width. Different OS so different functions. Thanks for the examples! – synjunked Feb 05 '13 at 10:07