4
\$\begingroup\$

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());
 renderManager = new RenderManager(gameManager);
 running = true;
 }
 public void run() {
 // game loop
 while (running) {
 gameManager.update();
 KeyInput.getKeyInputInstance().update();
 MouseInput.getMouseInputInstance().update();
 repaint();
 try {
 Thread.sleep(15);
 } catch (Exception e) {
 e.printStackTrace();
 }
 }
 }
 @Override
 public void update(Graphics graphic) {
 super.update(graphic);
 }
 @Override
 protected void paintComponent(Graphics graphic) {
 super.paintComponent(graphic);
 graphic2D = image.createGraphics();
 image.setAccelerationPriority(1);
 // to best visualization of the shapes and all graphics components
 graphic2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
 graphic2D.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
 graphic2D.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
 graphic2D.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
 graphic2D.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
 graphic2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
 graphic2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
 graphic2D.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
 renderManager.setRenderState(graphic2D);
 // draw the graphic of the setRender into the panel image
 graphic.drawImage(image, 0, 0, this);
 // clear graphics resources after use them
 graphic2D.dispose();
 image.flush();
 }

GameManager is a class that controls logic update.

RenderManager is a class that controls the type of objects to be displayed in correlation with the GameManager, for example only the main function.

After creating renderManager on GamePanel class, I call this function inside paintComponent():

public void setRenderState(Graphics2D graphic) {
 for (int i = 0; i < states.size(); i++) {
 if (gameManager.getCurrentState() == States.LOADING.getValue()) {
 if (states.get(i) instanceof Loading) {
 // draw until the state is the current,if i' m going to
 // change the state i stop drawing the current state
 if (states.get(i).getTimeUntilChangeLevel() == -1) {
 renderLoading = new RenderLoading(states.get(i));
 renderLoading.showRender(graphic);
 break;
 } else {
 break;
 }
 }
 }

Inside this function, if the current state is loading i'll create a new instance of RenderLoading, this is the class that displays the graphics of the currentState:

public class RenderLoading implements Render {
 private GameState gameState;
 public RenderLoading(GameState gameState) {
 this.gameState = gameState;
 }
 public void showRender(Graphics2D graphic) {
 graphic.drawImage(ImageProvider.LOADING, 0, 0, null);
 // draw loading string
 graphic.setColor(Color.BLACK);
 graphic.setFont(ImageProvider.loadingFont);
 graphic.drawString("Loading...", 25, 800);
 graphic.setStroke(ImageProvider.STROKE_2);
 // draw loading bar
 graphic.setColor(Color.BLACK);
 graphic.fillRect(20, 820, gameState.getLoadStatus(), 4);
 }
}

ImageProvider is a class that I use to load texture to my game:

public final class ImageProvider {
 public static BufferedImage LOADING;
 // best visualization of shapes
 public static BasicStroke STROKE_2 = new BasicStroke(2);
 public static BufferedImage loadImages(String string) {
 BufferedImage image = null;
 try {
 image = ImageIO.read(ImageProvider.class.getResourceAsStream(string));
 } catch (Exception e) {
 e.printStackTrace();
 }
 return image;
 }
 //this function is called before the renderManager
 //this load the images
 public static void loadImages() {
 ImageProvider.LOADING = ImageProvider.loadImages("/images/loading.jpg");
 }
 public static BasicStroke getSTROKE_2() {
 return STROKE_2;
 }
}

GameManager Class it manage every aspect of game,select the current state and other stuff.

public class GameManager {
 // game's states
 private Game game;
 private Menu menu;
 private SelectPath path;
 private Loading loading;
 private Editor editor;
 private WorldManager worldManager;
 private int currentState = 0;
 public GameManager(int state) {
 this(state, null);
 }
 public GameManager(int state, WorldManager worldManager) {
 this.currentState = state;
 this.worldManager = worldManager;
 }
 public void loadCurrentState(int state) {
 if (state == States.LOADING.getValue()) {
 loading = new Loading(this);
 loading.init();
 } else if (state == States.EDITOR.getValue()) {
 editor = new Editor(this, worldManager);
 editor.init();
 } else if (state == States.MENU.getValue()) {
 menu = new Menu(this, worldManager);
 menu.init();
 } else if (state == States.PATHSELECT.getValue()) {
 path = new SelectPath(this, worldManager);
 path.init();
 } else if (state == States.GAME.getValue()) {
 game = new Game(this, worldManager);
 game.init();
 }
 }
 public void setState(int state) {
 currentState = state;
 loadCurrentState(currentState);
 }
 public void update() {
 if (currentState == States.LOADING.getValue())
 loading.update();
 else if (currentState == States.EDITOR.getValue())
 editor.update();
 else if (currentState == States.MENU.getValue())
 menu.update();
 else if (currentState == States.GAME.getValue())
 game.update();
 else if (currentState == States.PATHSELECT.getValue())
 path.update();
 }
 public int getCurrentState() {
 return currentState;
 }
 public WorldManager getWorldManager() {
 return worldManager;
 }
 public void setWorldManager(WorldManager worldManager) {
 this.worldManager = worldManager;
 }
}

GameState is an abstract class that is extended in each gamestate,it is to imagine how each gamestate is implemented

 public abstract class GameState {
 // gameManager
 protected GameManager gameManager;
 // worldManager
 protected WorldManager worldManager;
 public GameState(GameManager gameManager) {
 this(gameManager, null);
 }
 public GameState(GameManager gameManager, WorldManager worldManager) {
 this.gameManager = gameManager;
 this.worldManager = worldManager;
 }
 public abstract void init();
 public abstract void update();
 public abstract void controllerUserInput();
 public abstract void changingState();
 }

My game works fine, but with this code, my objects on the screen visibly lag.

Can I get a performance review of my code?

asked Jun 3, 2014 at 9:31
\$\endgroup\$
2
  • \$\begingroup\$ Do you think it's possible to show us a video on youtube or another platform on what exactly is happening \$\endgroup\$ Commented Jun 3, 2014 at 9:50
  • \$\begingroup\$ @BenVlodgi i posted the gameState class that is extended on each game state,see update. \$\endgroup\$ Commented Jun 3, 2014 at 17:16

1 Answer 1

4
\$\begingroup\$

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.

answered Jun 3, 2014 at 14:58
\$\endgroup\$
1
  • \$\begingroup\$ can you provide me a little example with your advices on my code above? \$\endgroup\$ Commented Jun 3, 2014 at 15:25

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.