Overclock.net › Forums › Software, Programming and Coding › Coding and Programming › Weird Problem with Java.
New Posts  All Forums:Forum Nav:

Weird Problem with Java.

post #1 of 7
Thread Starter 
In a game I am creating, I am getting a higher CPU usage than I should. It turns out that paintComponent(Graphics g) (part of Swing), is getting called about 500 times a second. The method should only be called when repaint() is called, or when changes are made to the Component. Even when the game is idle, the method is called over 500 times a second. I am pretty sure this is why my game is using so much CPU. I have even removed all calls to repaint(), but I still get the same problem. There is a lot of code in the game, and I am not sure what to post. But any help would be great.

Thanks.
post #2 of 7
Quote:
Originally Posted by Jtvd78 View Post
In a game I am creating, I am getting a higher CPU usage than I should. It turns out that paintComponent(Graphics g) (part of Swing), is getting called about 500 times a second. The method should only be called when repaint() is called, or when changes are made to the Component. Even when the game is idle, the method is called over 500 times a second. I am pretty sure this is why my game is using so much CPU. I have even removed all calls to repaint(), but I still get the same problem. There is a lot of code in the game, and I am not sure what to post. But any help would be great.

Thanks.
1st: It's impossible to help you in anyway without code; seriously...how can I tell what you're even trying to do?

2nd: Why java? Java is awful for game development, go use C++.

Post some code.

All I can say right now is look at each function individually, and determine how long each should take to run using complexity analysis (Big-O notation). Then run some test cases on the longer functions and see if there is a specific function that is causing the bottleneck. (And something being called 500 times a second isn't nessisarily alot, though for rendering it is).
Edited by CovertCover - 6/4/11 at 11:03am
My System
(13 items)
 
  
CPUMotherboardGraphicsRAM
Core i7-930 D0 3.8Ghz ASUS P6T SE PowerColor HD5870 1GB 6GB Corsair Dominator XMS3 8-8-8-20 1200Mhz 
Hard DriveOSMonitorPower
1TB Wester Digital Windows 7 Home 64bit Acer 23" XFX 850w Black Edtion 
Case
HAF 932 
  hide details  
Reply
My System
(13 items)
 
  
CPUMotherboardGraphicsRAM
Core i7-930 D0 3.8Ghz ASUS P6T SE PowerColor HD5870 1GB 6GB Corsair Dominator XMS3 8-8-8-20 1200Mhz 
Hard DriveOSMonitorPower
1TB Wester Digital Windows 7 Home 64bit Acer 23" XFX 850w Black Edtion 
Case
HAF 932 
  hide details  
Reply
post #3 of 7
Getting called more than once per frame makes me think that something within the paintComponent method is requesting a redraw. If you didn't write that function yourself I'd decouple that particular component from all others, and re-enable connections one at a time until you find out which is triggering the redraws.
It goes to eleven
(13 items)
 
  
CPUMotherboardGraphicsRAM
E6300 DS3 EVGA 8600GTS 2GB XMS2 DDR2-800 
Hard DriveOSMonitorKeyboard
1.294 TB Arch Linux/XP Samsung 226bw Eclipse II 
PowerCaseMouse
Corsair 520HX Lian-Li v1000B Plus G7 
  hide details  
Reply
It goes to eleven
(13 items)
 
  
CPUMotherboardGraphicsRAM
E6300 DS3 EVGA 8600GTS 2GB XMS2 DDR2-800 
Hard DriveOSMonitorKeyboard
1.294 TB Arch Linux/XP Samsung 226bw Eclipse II 
PowerCaseMouse
Corsair 520HX Lian-Li v1000B Plus G7 
  hide details  
Reply
post #4 of 7
I'm not a Java programmer, but I think paintComponent is a method in the base class. You are overriding it, and probably adding custom code. There are a few things to look for:

1. Is your application doing something which requires the window to redraw itself too often? Maybe you're moving a control around the window way too much as part of your game.

2. Do you have custom code in the paintComponent method which should be conditional, but is getting called everytime the window needs to redraw? This could cause performance issues.

3. Is your performance issue caused by lack of double-buffering? This is an infamous occurrence in 2D games. The point is to paint your objects in memory, and then paint the entire in-memory image onto the window at one time. This contrasts with painting one thing onto a graphics image, and then another, and then another, etc. each time paintComponent is called.
Main System
(13 items)
 
  
CPUMotherboardGraphicsRAM
Phenom II X6 1090T MSI 890FXA-GD70 XFX Radeon 5850 16 GB Corsair XMS3 DDR3 1333 
Hard DriveOSMonitorPower
3 X 7200 RPM / 1 TB Win 7 Ultimate 64 2 x ASUS 23" VH232H 1080P SeaSonic X-650 
Case
Corsair 600T 
  hide details  
Reply
Main System
(13 items)
 
  
CPUMotherboardGraphicsRAM
Phenom II X6 1090T MSI 890FXA-GD70 XFX Radeon 5850 16 GB Corsair XMS3 DDR3 1333 
Hard DriveOSMonitorPower
3 X 7200 RPM / 1 TB Win 7 Ultimate 64 2 x ASUS 23" VH232H 1080P SeaSonic X-650 
Case
Corsair 600T 
  hide details  
Reply
post #5 of 7
Thread Starter 
Here is the class with the core game processing in it.
Code:
import game.GameHelper;

public class GameArea extends JComponent implements MouseMotionListener,MouseListener,ActionListener {
private static final long serialVersionUID = 1L;

JFrame frame;  

private static Point mouse = new Point();

Image blue = GameHelper.loadImage("/blue.png");
Image fire =  GameHelper.loadImage("/fire.png");
Image red =   GameHelper.loadImage("/red.png");
Image GridSpace =  GameHelper.loadImage("/EmptyGrid.png");
Image FirePosImage =  GameHelper.loadImage("/FirePos.png");

static Grid playerGrid = new Grid(12,12);
static Grid enemyGrid = new Grid(12,12);
AIPlayer enemy = new AIPlayer(enemyGrid);

boolean playerVictory = false;
boolean enemyVictory = false;
boolean allowInput = true;

int turns = 0;
int playerShipsDestroyed = 0;
int enemyShipsDestroyed = 0;
int calls = 0;

public void run(){
GameHelper.loadGameData();
addMouseMotionListener(this);
addMouseListener(this);

playerGrid.populateGrid(5,true);
}

public void updateGame(){
repaint();

if(playerShipsDestroyed == 5){
enemyVictory = true;
playAgain(false);
}else if(enemyShipsDestroyed == 5){
playerVictory = true;
playAgain(true);
}
}

private void playAgain(boolean outcome){
String s;
if(outcome){
s = "You Won! Would you like to play again?";
}else{
s = "You lost. Would you like to play again?";
}

JPanel panel = new JPanel(new FlowLayout());
panel.setPreferredSize(new Dimension(250,70));
JTextArea text = new JTextArea(s);
text.setEditable(false);
panel.add(text);

JButton yes = new JButton("Yes");
yes.setActionCommand("yes");
yes.addActionListener(this);
panel.add(yes);

JButton no = new JButton("No");
no.setActionCommand("no");
no.addActionListener(this);
panel.add(no);

frame = new JFrame("Play Again?");
frame.add(panel);
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
}

public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("yes")){
resetGame();
frame.dispose();
}else{
System.exit(0);
}
}

public void resetGame(){
playerGrid = new Grid(12,12);
enemyGrid = new Grid(12,12);
enemy = new AIPlayer(enemyGrid);

playerGrid.populateGrid(5,true);

playerVictory = false;
enemyVictory = false;
allowInput = true;

turns = 0;
playerShipsDestroyed = 0;
enemyShipsDestroyed = 0;
}

public void paintComponent(Graphics g){
setFont(new Font("Arial", Font.PLAIN, 20));
g.setColor(Color.BLACK);
drawBoard(g);

calls++;
setFont(new Font("Arial", Font.PLAIN, 15));
g.drawString("Calls to Paint Component: " +Integer.toString(calls), 10,getHeight()-3);
}

public void drawBoard(Graphics g){

g.setColor(Color.BLACK);

for(int cx = 0; cx < enemyGrid.getXSpace(); cx++){
for(int cy = 0; cy < enemyGrid.getYSpace(); cy++){
g.drawImage(blue, (cx*50)+30,(cy*50)+30, null);

if(enemyGrid.getGridSpace(cx,cy) != null){
enemyGrid.getGridSpace(cx,cy).drawPos(g,cx,cy,false);
}

g.drawImage(GridSpace, (cx*50)+30,(cy*50)+30, null);
}
}

for(Ship ship : enemyGrid.getShipList()){
if(ship.isDestroyed()){
for(ShipPos pos : ship.getShipPosList()){
pos.setDrawFire(false);
pos.drawPos(g);
g.drawImage(fire, (pos.getX()*50)+30,(pos.getY()*50)+30, null);
}
}
}

for(int cx = 0; cx < playerGrid.getXSpace(); cx++){
for(int cy = 0; cy < playerGrid.getYSpace(); cy++){
g.drawImage(blue, (cx*50)+130+600,(cy*50)+30, null);

if(playerGrid.getGridSpace(cx, cy) != null){
playerGrid.getGridSpace(cx,cy).drawPos(g, cx, cy, true);
}

g.drawImage(GridSpace, (cx*50)+130+600,(cy*50)+30, null);
}
}
}

private Point getMouseGridPos(){
return new Point((( mouse.x - 30 ) /50),(( mouse.y - 30 ) /50));
}

public void mouseDragged(MouseEvent e) {
mouseMoved(e);
}

public void mouseMoved(MouseEvent e) {
mouse.x = e.getX();
mouse.y = e.getY();
}


//unused inhereted methods.
public void mouseClicked(MouseEvent arg0) {}
public void mouseEntered(MouseEvent arg0) {}
public void mouseExited(MouseEvent arg0) {}
public void mouseReleased(MouseEvent arg0) {}



public void mousePressed(MouseEvent arg0) {
int yPos = getMouseGridPos().x;
int xPos = getMouseGridPos().y;
int delay = (int) (Math.random() * GameHelper.getAttackDelayTime());

Timer timer = new Timer();

if(xPos < 12 && yPos < 12 && allowInput){
if(enemyGrid.getGridSpace(yPos,xPos) == null){
enemyGrid.addFirePos(yPos, xPos);

if(GameHelper.getAttackDelay()){
enemy.attack(delay);
timer.schedule(new Task(), delay);
}else{
enemy.attack(0);
}
turns++;

}else if(enemyGrid.containsShip(yPos, xPos) && !enemyGrid.getShipSate(yPos,xPos)){
enemyGrid.setShipState(yPos,xPos);
if(enemyGrid.getShip(((ShipPos) enemyGrid.getGridSpace(yPos,xPos)).getShipNumber()).isDestroyed()){
enemyShipsDestroyed++;
}
if(GameHelper.getAttackDelay()){
enemy.attack(delay);
timer.schedule(new Task(), delay);
}else{
enemy.attack(0);
}
turns++;
}
}
updateGame();
}

public class Task extends TimerTask{
public Task(){
allowInput = false;
}

public void run(){
allowInput = true;
}
}
}
I have removed some methods that I am 99.99% sure aren't the problem. The ones that I removed have nothing to do with this problem.

Here is the class that calls the GameArea class
Code:

package game;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Window extends JFrame  implements ActionListener {
private static final long serialVersionUID = 1L;

GameArea ga = new GameArea();
JButton b = new JButton("Settings");
Container c = getContentPane();
Dimension d = new Dimension(1350,680);
JPanel p = new JPanel();
SettingsPanel settingsPanel = new SettingsPanel();

public Window(){
setTitle("Battleship");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setResizable(false);
setLayout(new BorderLayout());

p.setLayout(new FlowLayout());
b.addActionListener(this);
b.setMnemonic(KeyEvent.VK_S);
b.setActionCommand("Settings");
    p.add(b);
    p.setVisible(true);
    p.setBackground(Color.WHITE);
    c.add(p,BorderLayout.PAGE_END);
    
c.add(ga);
    c.setBackground(Color.WHITE);
    c.setPreferredSize(d);
    pack();
    
    ga.run();
}

@Override
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("Settings")){
settingsPanel.setVisible(true);
}
}
}
The only important thing the main method does is make an instance of the window class.

And yes, I know it is a wall of code, but at least I put it in code tags
Edited by Jtvd78 - 6/4/11 at 6:35pm
post #6 of 7
Yes, you need to double-buffer
Main System
(13 items)
 
  
CPUMotherboardGraphicsRAM
Phenom II X6 1090T MSI 890FXA-GD70 XFX Radeon 5850 16 GB Corsair XMS3 DDR3 1333 
Hard DriveOSMonitorPower
3 X 7200 RPM / 1 TB Win 7 Ultimate 64 2 x ASUS 23" VH232H 1080P SeaSonic X-650 
Case
Corsair 600T 
  hide details  
Reply
Main System
(13 items)
 
  
CPUMotherboardGraphicsRAM
Phenom II X6 1090T MSI 890FXA-GD70 XFX Radeon 5850 16 GB Corsair XMS3 DDR3 1333 
Hard DriveOSMonitorPower
3 X 7200 RPM / 1 TB Win 7 Ultimate 64 2 x ASUS 23" VH232H 1080P SeaSonic X-650 
Case
Corsair 600T 
  hide details  
Reply
post #7 of 7
Thread Starter 
Quote:
Originally Posted by tand1 View Post
Yes, you need to double-buffer
There is no flickering at all, and I can't find any double buffer methods that work.
New Posts  All Forums:Forum Nav:
  Return Home
  Back to Forum: Coding and Programming
Overclock.net › Forums › Software, Programming and Coding › Coding and Programming › Weird Problem with Java.