10

Okay, I understand your need for an SSCCE, so I created (my first) one.

I managed to replicate the problem with under 200 lines of code. On my system this demo compiled and ran perfectly (only the flickering was still there of course). I stripped everything that had nothing to do with it. So basically we have two source files now: the screen manager and the game manager.

The screen manager: http://pastebin.com/WeKpxEXW

The game manager: http://pastebin.com/p3C5m8UN

You can compile this code with this make file (I use a ported version of Linux' make for 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 $@ [command: $(CC) src/$*.java ] ...
    @$(CC) -Xlint:unchecked -d classes -classpath src src/$*.java

Where the source files are placed in the /src directory and the classes in the /classes directory.

After compilation to byte-code the game can be started using the following .bat file:

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

Note that the ARGUMENT variable depends on your own screen settings and that you have to change it so that the game is displayed in the right resolution for your screen.

Jori
  • 1,122
  • 2
  • 18
  • 36
  • I haven't read through the code, but have you tried restarting your computer? It often fixes flashing issues for me. – Zach Latta Jan 25 '13 at 10:11
  • Yes I did, did not help. – Jori Jan 25 '13 at 10:12
  • Do you still have the problem if you take it out of Fullscreen mode? Are you using hardware acceleration the same on Linux and Windows? You can try this: frame.getGraphicsConfiguration().getBufferCapabilities().isPageFlipping() to see if its hardware accelerated. Make sure its the same on both platforms before ruling it out. – chubbsondubs Jan 27 '13 at 18:03
  • Do you hace current drivers installed on the Windows machine? – BillRobertson42 Jan 27 '13 at 19:04
  • Will check this today and post back. – Jori Jan 28 '13 at 09:14
  • frame.getGraphicsConfiguration().getBufferCapabilities().isPageFlipping() returned `true`, also when I try to vut out the full screen mode the buffering strategy fails with: `Exception in thread "main" java.lang.IllegalStateException: Component must have a valid peer`. I'm pretty sure my drivers are up to date though. – Jori Jan 28 '13 at 17:59
  • I didn't see any draw stuffs with the BufferStrategy? – shuangwhywhy Feb 01 '13 at 10:24
  • No that is somewhere else in the code, I placed that in a rendering method that is called in the game loop. But the execution time of the drawing is small as I already mentioned. Do you want me to post that too? – Jori Feb 01 '13 at 12:18
  • We can help you if you provide a [Short, Self Contained, Correct (Compilable), Example](http://sscce.org/) – karlphillip Feb 01 '13 at 20:42
  • 1
    Does the original code from chapter 18 (linked above) run as expected on Windows? – siegi Feb 02 '13 at 10:02
  • it really would be useful to see where you actually paint/use your bufferstrategy. also, are you using awt or swing components? – Seismoid Feb 02 '13 at 15:51
  • You've a typo here: `if (hwnd == null) hwnd.dispose();`, although that could not cause the flickering. My advice is to go back to basics with a trivial application that creates a window with a buffer strategy and draws something simple to it. Make sure that works, then keep incorporating parts of the full game until it goes wrong. – Boann Feb 02 '13 at 18:54
  • Have you tried it on another Windows 7 based machine? If so, and it still happens, did they both use the same vendor graphics card? AMD (I don't know about nVidia) can restart the driver and that causes a kind of flash, but I'm not sure if it would be the same as you are describing. Other than that, are you sharing data between the rendering thread and the update thread, and if so, where are you locking in contrast to when you clear and flush the buffer? – Doug Moscrop Feb 02 '13 at 19:45
  • Please see the new example all! – Jori Feb 03 '13 at 12:58
  • Please try my solution, tell me if it is not what you want. – shuangwhywhy Feb 03 '13 at 14:39

6 Answers6

8

I see why it is flickering ----

BufferStrategy is doing a separate painting job from the Component's paint() method and they seem to use different Graphics objects and they are refreshing at a different rate --

when paint() is invoked before show(), it's fine. But

when paint() is invoked after show(), it will repaint the component to its initial blank look -- so flashing happens.


It's very easy to eliminate the flickering: override paint() method of your JFrame (GameMain) as you don't need it to do anything (BufferStrategy can give you more precise control on painting stuffs):

@Override
public void paint (Graphics g) {}

That's all. (I have tested it and it works fine, hope this may help :))


===== Update =====

Instead of overriding paint() method, a better way is to call setIgnoreRepaint(true) for your JFrame (GameMain) -- this method is just designed for such purposes! USE IT!

private GameMain(String ... args)
{
    setIgnoreRepaint(true);
    .....
}
Community
  • 1
  • 1
shuangwhywhy
  • 5,475
  • 2
  • 18
  • 28
1

It may work for you, when you set your hwnd.createBufferStrategy(2) in its own method.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Eveli
  • 498
  • 1
  • 6
  • 27
  • You mean in the `initializeGameEnvironment()` method? – Jori Feb 01 '13 at 12:19
  • should work, but better sth like this: `public void createStrategy() { createBufferStrategy(2); strategy = getBufferStrategy(); }` and call this, after your first screen is visible – Eveli Feb 01 '13 at 12:23
  • Unfortunately it does not work :(, I pasted the `createBufferStrategy(2)` after `screenManager.setFullScreen(displayMode, this);` and it still flickers very rapidly. Also I can't why this would work, after all hwnd is a reference to the JFrame and methods called on that reference are exactly the same as calling it from the inner class, right? Thanks for your help anyway, maybe you can find the real error. – Jori Feb 01 '13 at 17:09
1

This is how i implement double buffering, might help you get the concept. Note it's implemented in a JPanel, but i think it can be implemented in other containers:

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

Hope this helps, good luck.

Shikatsu
  • 197
  • 1
  • 1
  • 13
  • Calling super.paintComponent() in your JPanel might trigger a repaint of the background - I would skip that line. Also, double-buffering is supported natively in JComponent through setDoubleBuffered(true) – msteiger Feb 02 '13 at 18:55
  • I made a board game this way and works perfectly, what do you mean by "might trigger a repaint of the background", didn't made much sense to me, can you explain further?. I'll take a look at setDoubleBuffered(true) and check if it will reduce the number of lines in my code, though i kinda remember that i had tried it on my board game and didn't work, no harm in double checking, thanks for the tip and the remark. – Shikatsu Feb 02 '13 at 20:55
  • 1
    When you call the super method it will draw the default component look which you don't need if you draw the component's entire content yourself. This can also cause flickering. – msteiger Feb 03 '13 at 10:40
1

I have a cross-platform Java AWT-based program with animation. It had flashing problems until I strictly followed the example code at in the Java BufferStrategy documentation. However I'm using an AWT Canvas embedded in a Swing hierarchy, not full screen as you. You can see the code here if interested.

Another thing to note is that the AWT pipeline uses OpenGL primitives for good performance, and OpenGL support is buggy in many video drivers. Try installing latest versions of drivers for your platform.

Gene
  • 46,253
  • 4
  • 58
  • 96
1

There was a problem with Java rendering transparent background GIF images. That could be the problem.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
bill mee
  • 19
  • 2
0

I find it rather difficult to answer your question without an SCCSE. I also wonder what the RepaintManagerResetter does.

You might want to set your background color to some fancy colors like 0xFF00FF to find out if someone "clears" the background before the drawing happens. If the flicker image is purple, it's that - if it contains garbage or old images, it's probably the double-buffering.

In any case I would try to ensure that noone draws expect yourself. First, try to prevent native Windows code from drawing the window background. Set this once:

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

Also, make sure that you override this in your JFrame(if you are using Swing components)

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

If that doesn't help, please provide a working example of your code, so people can reproduce the problem.

msteiger
  • 2,024
  • 16
  • 22
  • System.setProperty("sun.awt.noerasebackground", "true"); did not do the job, also in the new example I do not use any JComponents. – Jori Feb 03 '13 at 13:02