Java-графика мигает

Хорошо, я понимаю вашу потребность в SSCCE, поэтому я создал (мой первый).

Мне удалось реплицировать проблему до 200 строк кода. В моей системе эта демонстрация скомпилировалась и работала отлично (только мерцание было все еще там, конечно). Я раздели все, что не имеет к этому никакого отношения. Итак, в основном у нас есть два исходных файла: диспетчер экрана и менеджер игр.

Диспетчер экрана: http://pastebin.com/WeKpxEXW

Игровой менеджер: http://pastebin.com/p3C5m8UN

Вы можете скомпилировать этот код с этим make файлом (я использую портированную версию Linux для Windows):   CC = javac   BASE = nl/jorikoolstra/jLevel   CLASS_FILES = classes/$(BASE)/Game/GameMain.class classes/$(BASE)/Graphics/ScreenManager.class

jLevel: $(CLASS_FILES)
    @echo Done.

classes/%.class : src/%.java
    @echo Compiling src/$*.java to [email protected] [command: $(CC) src/$*.java ] ...
    @$(CC) -Xlint:unchecked -d classes -classpath src src/$*.java

Если исходные файлы помещаются в каталог /src и классы в каталоге /classes.

После компиляции в байт-код игра может быть запущена с использованием следующего .bat файла:

@set STARUP_CLASS=nl.jorikoolstra.jLevel.Game.GameMain
@set ARGUMENTS=1280 1024 32
@java -cp classes;resources %STARUP_CLASS% %ARGUMENTS%

Обратите внимание, что переменная ARGUMENT зависит от ваших собственных настроек экрана и что вы должны ее изменить, чтобы игра отображалась в правильном разрешении для вашего экрана.

Ответ 1

Я вижу, почему он мерцает ----

BufferStrategy выполняет отдельное задание на рисование с помощью метода Component paint(), и они, похоже, используют разные объекты Graphics, и они обновляются с другой скоростью -

когда paint() вызывается перед show(), это нормально. Но

когда paint() вызывается после show(), он перекрасит компонент в свой первоначальный пустой вид - так происходит мигание.


Очень легко устранить мерцание: переопределить paint() метод вашего JFrame (GameMain), поскольку вам не нужно ничего делать (BufferStrategy может дать вам более точный контроль над материалами для рисования)

@Override
public void paint (Graphics g) {}

Это все. (Я тестировал его, и он отлично работает, надеюсь, что это может помочь:))


===== Обновление =====

Вместо того, чтобы переопределять метод paint(), лучший способ - вызвать setIgnoreRepaint(true) для вашего JFrame (GameMain) - этот метод предназначен только для таких целей! ИСПОЛЬЗУЙТЕ ЭТО!

private GameMain(String ... args)
{
    setIgnoreRepaint(true);
    .....
}

Ответ 2

Это может сработать для вас, когда вы установите свой hwnd.createBufferStrategy(2) в свой собственный метод.

Ответ 3

Вот как я реализую двойную буферизацию, может помочь вам получить концепцию. Обратите внимание, что он реализован в JPanel, но я думаю, что он может быть реализован в других контейнерах:

TheJApplet.java:

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

public class TheJApplet extends JApplet
{
    private Image myImage;

    java.net.URL GameURL = CheckerGameJApplet.class.getResource("GameIMG");

    String GamePath = GameURL.getPath();

    @Override
    public void init()
    {
        String GraphPath = GamePath+"/";

        File myImage_File = new File(GraphPath+"myImage.jpg");

        try
        {
            myImage = ImageIO.read(myImage_File);
        }
        catch (IOException ex)
        {
            // Add how you like to catch the IOExeption
        }

        final TheJPanel myJPanel = new TheJPanel(myImage);

        add(myJPanel);
    }
}

TheJPanel.java:

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

public class TheJPanel extends JPanel
{
    private int screenWidth  = 500;
    private int screenHeight = 500;

    private BufferedImage BuffImg = new BufferedImage
                                         (screenWidth, 
                                          screenHeight,
                                          BufferedImage.TYPE_INT_RGB);

    private Graphics2D Graph = BuffImg.createGraphics();

    private Image myImage;

    public TheJPanel(Image myImage)
    {
        this.myImage = myImage;

        repaint();
    }

    @Override
    public void paintComponent(Graphics G)
    {
        Graphics2D Graph2D = (Graphics2D)G;

        super.paintComponent(Graph2D);

        if(BuffImg == null)
        {
            System.err.println("BuffImg is null");
        }

        Graph.drawImage(myImage, 0, 0, this);

        Graph2D.drawImage(BuffImg, 0, 0, this);
    }
}

Надеюсь, это поможет, удачи.

Ответ 4

У меня есть межплатформенная Java AWT-программа с анимацией. У него возникали проблемы, пока я строго не выполнил код примера в документации Java BufferStrategy. Однако я использую AWT Canvas, встроенный в иерархию Swing, а не полный экран, как вы. Вы можете видеть код здесь, если это интересно.

Еще одна вещь, которую следует отметить, заключается в том, что конвейер AWT использует примитивы OpenGL для хорошей производительности, а поддержка OpenGL нестабильна во многих видеодрайверах. Попробуйте установить последние версии драйверов для своей платформы.

Ответ 5

Возникла проблема с визуализацией Java прозрачным фоном GIF. Это может быть проблемой.

Ответ 6

Мне сложно ответить на ваш вопрос без SCCSE. Я также задаюсь вопросом, что делает RepaintManagerResetter.

Возможно, вы захотите установить свой цвет фона на некоторые причудливые цвета, такие как 0xFF00FF, чтобы узнать, удастся ли кто-нибудь "очистить" фон до начала розыгрыша. Если изображение мерцания фиолетовое, то это - если оно содержит мусор или старые изображения, возможно, это двойная буферизация.

В любом случае я постараюсь обеспечить, чтобы никто не ожидал себя. Во-первых, попробуйте запретить собственный код Windows рисовать фон окна. Установите это один раз:

/*
 * Set a Windows specific AWT property that prevents heavyweight components 
 * from erasing their background. 
 */
System.setProperty("sun.awt.noerasebackground", "true");

Кроме того, убедитесь, что вы переопределили это в своем JFrame (если вы используете компоненты Swing)

@Override
public void paintComponent(Graphics G)
{
  // do not call super.pC() here
  ...
}

Если это не помогает, предоставьте рабочий пример вашего кода, чтобы люди могли воспроизвести проблему.