HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Avoid flickering on game screen

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
flickeringgamescreenavoid

Problem

This is the smallest SSCCE of my project. I get flickering on the screen with this code.

Main class (on which I start the application)

import javax.swing.JFrame;

    public class MainFrame {

        public static void main(String[] args) {
        final JFrame frame = new JFrame();
        final GamePanel gamePanel = new GamePanel();
        frame.add(gamePanel);
        gamePanel.startGame();
        frame.setUndecorated(true);
        frame.pack();
        frame.setVisible(true);

        }
    }


GamePanel class (start/running game loop)

```
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;

import javax.swing.JPanel;

@SuppressWarnings("serial")
public class GamePanel extends JPanel implements Runnable {

// game manager
private GameManager gameManager;
// renderManager
private RenderManager renderManager;
// image
private BufferedImage image;
Graphics2D graphic2D;

// game thread
private Thread thread;
private boolean running;

public GamePanel() {
setPreferredSize(new Dimension(GuiDimension.WIDTH.getValue(), GuiDimension.HEIGHT.getValue()));
setIgnoreRepaint(true);
setFocusable(true);
requestFocusInWindow();
}

public void startGame() {
init();
if (thread == null) {
this.addKeyListener(KeyInput.getKeyInputInstance());
this.addMouseListener(MouseInput.getMouseInputInstance());
this.addMouseMotionListener(MouseInput.getMouseInputInstance());
this.addMouseWheelListener(MouseInput.getMouseInputInstance());
thread = new Thread(this);
thread.start();
}
}

private void init() {
image = new BufferedImage(GuiDimension.WIDTH.getValue(), GuiDimension.HEIGHT.getValue(), BufferedImage.TYPE_INT_RGB);
gameManager = new GameManager(States.LOADING.getValue());
gameManager.loadCurrentState(States.LOADING.getValue());

Solution

Java

You tabbing, makes your code less readable, after every

bracket {
    you should be indenting the following lines 
}


break;
} else {
break;


looks like you're going to break either way, how bout doing this

}
break;


Structure

Instead of making ImageProvider a final class, like you have there, make it a class responsible for loading one image, then maintain a dictionary of all the resources you've loaded, this way your game will be much more scalable, and values wont be hardcoded.

You could even have a class called DefaultImages to directly point to some of these commonly needed images, who's names wont change. You would still load the images with ImageProvder, but would simply maintain a direct pointer to your desired images.

To prevent flickering, Double Buffer your rendering process.

Ensure that in your gameManager.update(); you aren't actually doing the logical calculations every time. I assume you are doing your calculations based on a delta based system, where your calculations used the elapsed time since your last .update() to determine how much (lets say) something has moved. So be sure you've implemented a system, where the gameManager calls update on all the items in the list of items, and each one of them determine if the time since they last updated their stuff, was long enough ago to warrant recalculating their position. (Each item class maintaining how often they need calculations)

If you want to see an example of this, check out the Source Engine's implementation.
https://github.com/ValveSoftware/source-sdk-2013/blob/master/sp/src/game/server/player.cpp

Here you will see after events happen in game, the programmer manually sets the next time the think() method will be ran, which is called update() for you

SetNextThink( gpGlobals->curtime + 0.1f );


You also see in here, that the programmer will specify when an item should start or stop thinking.

bool CBasePlayer::RemovePlayerItem( CBaseCombatWeapon *pItem )
{
    if (GetActiveWeapon() == pItem)
    {
        ResetAutoaim( );
        pItem->Holster( );
        pItem->SetNextThink( TICK_NEVER_THINK );; // crowbar may be trying to swing again, etc
        pItem->SetThink( NULL );
    }

    if ( m_hLastWeapon.Get() == pItem )
    {
        Weapon_SetLast( NULL );
    }

    return Weapon_Detach( pItem );
}


Separate your main-loop logic from your main menu rendering logic.

You should have a main-loop, which calls recalculate, and draw, then in your draw you should draw the appropriate menu, based on the games current state, the GamePanel logic should stay in its own class away from the main-loop.

Code Snippets

bracket {
    you should be indenting the following lines 
}
break;
} else {
break;
SetNextThink( gpGlobals->curtime + 0.1f );
bool CBasePlayer::RemovePlayerItem( CBaseCombatWeapon *pItem )
{
    if (GetActiveWeapon() == pItem)
    {
        ResetAutoaim( );
        pItem->Holster( );
        pItem->SetNextThink( TICK_NEVER_THINK );; // crowbar may be trying to swing again, etc
        pItem->SetThink( NULL );
    }

    if ( m_hLastWeapon.Get() == pItem )
    {
        Weapon_SetLast( NULL );
    }

    return Weapon_Detach( pItem );
}

Context

StackExchange Code Review Q#52341, answer score: 4

Revisions (0)

No revisions yet.