Canvas fillRect () не заполняет определенный холст

Я расширяю Canvas и добавляю его к JFrame. Я понимаю, что AWT и Swing не следует смешивать, и предпочтительнее рисовать на JPanel, но я пытаюсь следовать учебному пособию по игровому движку, и я хотел бы придерживаться его, поскольку до сих пор он работал. Canvas имеет minimumSize, maximumSize и prefferedSize размеры, равные 550, 400. Когда я делаю вызов отрисовки graphics.draw(0,0,550,400), он не заполняет весь экран, как должен. Я изменил вызов отрисовки на graphics.draw(0,0,560,410), добавив к нему 10 пикселей, и он заполнил весь экран. Что случилось?

Кстати: graphics.draw(10,10,550,400 точно рисует прямоугольник, начинающийся с угла, поэтому я не думаю, что проблема в JFrame.

Основной вызов внутри класса Launcher

    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();
        }
    });
}

Вызов отрисовки, Launcher.HEIGHT и WIDTH равны 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);
}

Расширенный класс Canvas

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
    }
}
}

Запрошено 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();
        }
    }

}

Что касается учебника по игре Java 2D, я следую за тем, что это веб-серия. Тем не менее, ссылка следующая: нажмите здесь. Я довольно много изменил код.

Модифицировано для 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) {
            }
        }
    }

}

person synjunked    schedule 05.02.2013    source источник
comment
Можете ли вы опубликовать код, который у вас есть?   -  person Nihathrael    schedule 05.02.2013
comment
Можете ли вы показать код? Установка только minimumSize, maximumSize и prefferedSize недостаточна без менеджера компоновки - чтобы установить фактический размер, используйте setSize()   -  person Andreas Fester    schedule 05.02.2013
comment
Ваш LayoutManager, вероятно, все равно меняет размер холста. Опубликуйте свой код, который создает графический интерфейс.   -  person Dariusz    schedule 05.02.2013
comment
Код опубликован, спасибо за все ответы!   -  person synjunked    schedule 05.02.2013
comment
Чтобы быстрее получить помощь, опубликуйте SSCCE.   -  person Andrew Thompson    schedule 05.02.2013
comment
Я пытаюсь следовать руководству по игровому движку Ссылка на него.   -  person Andrew Thompson    schedule 05.02.2013
comment
Добавлена ​​дополнительная информация по запросу.   -  person synjunked    schedule 05.02.2013
comment
Опубликованный рабочий пример работает нормально. Остерегайтесь магических чисел, используйте вместо них getWidth и getHeight. Убедитесь, что вы создаете свою буферную стратегию с Canvas, а не с фрейма.   -  person MadProgrammer    schedule 05.02.2013
comment
MadProgrammer, да прямоугольник заполняет но не весь экран. Если вы используете 560, 410 вместо 550, 400, вы заметите разницу. Другим ярким примером может быть сдвиг x, y в вызове отрисовки на 10 пикселей. С getWidth и getHeight он заполнит весь экран. Если я не ошибаюсь, getWidth и getHeight не должны быть 550, 400?   -  person synjunked    schedule 05.02.2013
comment
getWidth/height даст вам больше гибкости, если форма изменится или если ОС решит, что размер окна не будет таким же, как запрошенный Canvas. И что значит не на весь экран? Ваш пример заполняет окно   -  person MadProgrammer    schedule 05.02.2013
comment
В моем примере это не так, значение, которое я получил от getWidth(), было 560, а значение WIDTH содержало 550. Таким образом, он не мог заполнить весь экран, кроме того, если вы внимательно посмотрите и сравните, вы увидите, что часть правой и нижней стороны не заполнена. Я понимаю, почему getWidth/Height следует использовать для обеспечения гибкости, но установка setResizable(false) не отменяет этого? Кроме того, что я могу сделать, чтобы getWidth/Height вернул мне 550/400? Что касается предоставленной информации, то я очень благодарен.   -  person synjunked    schedule 05.02.2013
comment
Убедитесь, что вы используете значения из холста, а не кадра. Рамка, как правило, будет больше, чтобы разместить границу рамки. Фиксация размера кажется хорошей идеей, но я бы не стал использовать статические значения, так как это приводит к плохому дизайну - ИМХО. Когда вы решите изменить размер игровой области, ваш код может внезапно сломаться (особенно когда он станет более сложным). Использование getWidth/Height с холста означает, что у вас есть более надежный источник информации - ИМХО   -  person MadProgrammer    schedule 05.02.2013


Ответы (1)


Пример, который вы предоставили, отлично работает. Я немного изменил его, чтобы продемонстрировать использование getWidth/height

введите здесь описание изображения

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) {
        }
    }
}
person MadProgrammer    schedule 05.02.2013
comment
Я отредактировал свой вопрос, пожалуйста, скомпилируйте его, чтобы понять, что я имею в виду. Я не понимаю, почему getWidth дает мне значение на 10 пикселей выше, чем WIDTH, которое я использовал для размеров, границ и размера холста. Я также установил для JFrame неизменяемый размер. Я понимаю, что getWidth даст мне более точные размеры, но в конечном итоге я хочу, чтобы WIDTH и getWidth имели одинаковое значение. - person synjunked; 05.02.2013
comment
КАДР ВСЕГДА будет больше холста. Рамка имеет границу. Таким образом, важно убедиться, что вы создаете стратегию буфера из Canvas, а не из фрейма. - person MadProgrammer; 05.02.2013
comment
правильно, но я устанавливаю Canvas на эти размеры, а не на рамку. Рамка не имеет размеров и просто растягивается, чтобы соответствовать холсту. - person synjunked; 05.02.2013
comment
@synjunked Из вашего обновленного примера у меня все еще нет проблем. Убедитесь, что когда вы вызываете getWidth/Height на Canvas, а не на кадр. - person MadProgrammer; 05.02.2013
comment
Ааа, я думаю, это прекрасный пример использования getWidth поверх статической ширины. Разные ОС - разные функции. Спасибо за примеры! - person synjunked; 05.02.2013