Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (107)
games submitted by our members
Games in WIP (535)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  FPS is 60 when running through Netbeans IDE, But drops to 30 when running jar  (Read 1174 times)
0 Members and 1 Guest are viewing this topic.
Offline Teedo

Senior Newbie





« Posted 2013-08-26 12:29:22 »

Hey guys,
I am making a 2D game using SWING/paintComponent and have run in to an FPS problem. My FPS is fine at runs at 60 when I run it through Netbeans, though if I run a jar file then it will drop to 30. Would I be better off using AWT/Canvas?
I have cross-posted this problem. The original thread is http://www.java-forums.org/new-java/81086-fps-dropping-exactly-half-when-running-game-through-jar-file.html , but I have been advised to seek help from java-gaming instead.
Thanks for any help Smiley

- It only happens in fullscreen exclusive mode, and does not happen when windowed.
- Double buffering has no affect on it.
- Turning VYsnc off in my NVIDIA control panel will fix the problem and it will run at over 320fps.

If I run this exact code through Netbeans, it does exactly what I need....
- It takes 15ms from the time repaint() gets called, till paintComponent has finished.
- paintComponent takes 8ms of that 15ms time.
- Paintcomponent will be called 60 times per second.

If I run this exact code from a jar file, the FPS drops by half
- It takes 30ms from the time repaint() gets called, till paintComponent has finished.
- paintComponent takes 15ms of that 30ms time.
- Paintcomponent will be called 30times per second.


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
public void gameLoop(){
    double startMS;
    double currentMS;
    while (true){
        startMS = System.currentTimeMillis();
        currentMS = System.currentTimeMillis() - startMS ;
        while (currentMS < 1000){ // Display FPS after 1 second has passed
           if (gameScreen.getIsPainting() == false){
                render();
            }
            try {
                Thread.sleep(1);
            } catch (InterruptedException ex) {
                Logger.getLogger(GameEngine.class.getName()).log(Level.SEVERE, null, ex);
            }
            currentMS = System.currentTimeMillis() - startMS ;
        }
        if (SHOW_FPS == true){
            SwingUtilities.invokeLater(new Runnable(){
                @Override
                public void run(){
                    gameScreen.getTfFPS().setText(String.valueOf(GameScreen.paintingAmount));
                    gameScreen.revalidate();
                    GameScreen.paintingAmount = 0; // Reset painting counter to get amount of times painting every second
               }
            });
        }
         
    }
}
 
public void render(){
    gameScreen.setIsPainting(true);
    gameScreen.repaint();
}


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
private void init(){
    frame.setUndecorated(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setResizable(false);
    gameScreen = new GameScreen(this);
    gameEngine.init();
    input = new Input();
    input.initInput();
    frame.add(input);
    frame.add(gameScreen);
    frame.setVisible(true);
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice gd = ge.getDefaultScreenDevice();
    DisplayMode dm = new DisplayMode(640,480,32,60);
    gd.setFullScreenWindow(frame);
    gd.setDisplayMode(dm);
}
Offline gouessej
« Reply #1 - Posted 2013-08-26 12:31:46 »

If you want consistent performance, rather use LibGDX. You can go on using Java2D with Swing and/or AWT until you really understand the basic concepts and then give a try to third party libraries.

Offline Teedo

Senior Newbie





« Reply #2 - Posted 2013-08-26 12:34:40 »

I will definitely be using LibGDX in the future, but for now while I am still learning (and have an exam coming up) I want to stick with Java2D so I don't confuse anything in the exam Smiley
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline opiop65

JGO Kernel


Medals: 153
Projects: 7
Exp: 3 years


JumpButton Studios


« Reply #3 - Posted 2013-08-26 12:46:29 »

Are you required to use that sleep call? Generally,
1  
Thread.Sleep (1)
is a terrible way to keep the fps down because that function will actually run faster or slower depending on the computer.

Offline Teedo

Senior Newbie





« Reply #4 - Posted 2013-08-26 17:04:15 »

This is a cut down version of my game loop. In the full version, I compare the current system time to the last frame and play one frame every 15ms. Though I had to put a check if it was currently painting because I was getting screen tearing from moving objects while it was painting..... So I don't think it should matter because it should get limited to my monitors refresh rate of 60?
Offline Abuse

JGO Coder


Medals: 11


falling into the abyss of reality


« Reply #5 - Posted 2013-08-26 18:19:22 »

While I suspect it's an issue with the way that you're regulating your animation loop (or calculating your fps), I can't be sure from code snippets.

Strip down your code to the simplest example that still exhibits the problem & post it in its entirety.

Make Elite IV:Dangerous happen! Pledge your backing at KICKSTARTER here! https://dl.dropbox.com/u/54785909/EliteIVsmaller.png
Offline lcass
« Reply #6 - Posted 2013-08-26 18:44:06 »

Im going to reccomend that one, you dont compare as much info, adding another boolean check every time you run through the loop wastes processing power and its doing that thousands of times a second,  Note this is either a calculation error you are getting OR something is up with your threads, try multithreading if it continues. Such as setting the renderer in one thread then setting everything else in the other.
Offline opiop65

JGO Kernel


Medals: 153
Projects: 7
Exp: 3 years


JumpButton Studios


« Reply #7 - Posted 2013-08-26 19:16:30 »

Never multithread a game loop. Ever.

Offline Teedo

Senior Newbie





« Reply #8 - Posted 2013-08-27 08:15:21 »

Okay so I have recreated it with as little code as possible. Running this in Netbeans will result in a constant 60fps, while creating a jar file and running it will result in a constant 30fps. It looks like the jar file seems to think my monitors refresh rate is just 30 and not 60.

The reason I am checking to see if it is currently painting was because the repainting is done on the EDT with SWING and I would get tearing from moving game objects while it was trying to paint. I have never used Canvas before, and I think that I could make it render without using the EDT...am I right about that? I think I should be switching to Canvas instead of JPanel, but it would be good to know why this code will half the refresh rate in a jar file compared to the IDE. If I turn VSync off in the NVIDIA control panel on my desktop, then it will run at 900+fps.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
import java.awt.Color;
import java.awt.DisplayMode;
import java.awt.Graphics;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class Testing extends JPanel {
   
    boolean isPainting;
    int currentFPS;
    JTextField tfFPS;
    JPanel panel;
   
    public Testing(){
        super(true);
        tfFPS = new JTextField();
        JFrame frame = new JFrame();
        this.setIgnoreRepaint(true);
        frame.setUndecorated(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice gd = ge.getDefaultScreenDevice();
        DisplayMode dm = new DisplayMode(640,480,32,60);
        gd.setFullScreenWindow(frame);
        gd.setDisplayMode(dm);
        frame.add(this);
        this.add(tfFPS);
        this.setVisible(true);
        frame.setVisible(true);
        panel = this;
    }
   
    private void gameLoop(){
        double startMS;
        double currentMS;
        while (true){
            startMS = System.currentTimeMillis();
            currentMS = System.currentTimeMillis() - startMS;
            while (currentMS < 1000){ // while under 1 second, add 1 to fps and display FPS rate after 1 second
               if (isPainting == false){ // Loop one gameLoop only if it is currently not repainting
                   isPainting = true;
                    repaint();
                    currentFPS++;
                }
                try {
                    Thread.sleep(1);
                } catch (InterruptedException ex) {
                    System.out.println(ex);
                }
                currentMS = System.currentTimeMillis() - startMS;
            }
            SwingUtilities.invokeLater(new Runnable(){
                @Override
                public void run(){
                    tfFPS.setVisible(true);
                    tfFPS.setText(String.valueOf(currentFPS));
                    currentFPS = 0;
                    panel.revalidate();
                }
            });
        }
    }
   
    @Override
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        isPainting = false;
    }
   
    public static void main(String args[]){
        Testing t = new Testing();
        t.gameLoop();
    }
}
Online SHC
« Reply #9 - Posted 2013-08-27 08:44:18 »

Try active rendering from JFrame class.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
import javax.swing.JFrame;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;

/**
 * Base code for active rendering
 */

public class Game extends JFrame implements Runnable
{

    private BufferStrategy buffer;
    private boolean running = true;

    public Game()
    {
        super("My Game");
        setSize(640, 480);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setVisible(true);
        // Create 2 buffers
       createBufferStrategy(2);
        buffer = getBufferStrategy();

        // Run game loop
       new Thread(this).run();
    }

    /**
     * The Game Loop
     */

    public void run()
    {
        long now = getCurrentTime();
        long gameTime = getCurrentTime();

        long frames = 0;
        long fps = 0;

        long lastFpsCount = getCurrentTime();

        long updateRate = 1000 / 60; // Update 60 times per second

        while (running)
        {
            now = getCurrentTime();

            while (now + updateRate > gameTime)
            {
                // update your logic here
               update();
                gameTime += updateRate;
             
                // render
               do
                {
                    do
                    {
                        Graphics g = buffer.getDrawGraphics();
                        render(g);
                        g.dispose();
                     
                        frames++;
                        if (now - lastFpsCount > 1000)
                        {
                            fps = frames;
                            frames = 0;
                            lastFpsCount = getCurrentTime();
                            setTitle("FPS: " + fps);
                        }
                    }
                    while (buffer.contentsRestored());

                    buffer.show();
                }
                while (buffer.contentsLost());
            }
        }
    }
 
    /**
     * Update the game
     */

    public void update()
    {
        System.out.println("updated");
    }
 
    /**
     * Render the game
     */

    public void render(Graphics g)
    {
        System.out.println("rendered");
    }

    /**
     * Returns the current time in milliseconds
     */

    public long getCurrentTime()
    {
        return System.nanoTime() / 1000000;
    }

    public static void main(String[] args)
    {
        new Game();
    }
}

It's giving me 64 fps. You can also separate the rendering from update logic.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Teedo

Senior Newbie





« Reply #10 - Posted 2013-08-27 11:45:16 »

Thanks, I didn't know I could do that with a JFrame Smiley
Why would people use a Canvas instead of doing this when you can't add components like textfields to a Canvas?
How would I go about adding a JTextField to this? I can't seem to get it to show
Online SHC
« Reply #11 - Posted 2013-08-27 15:49:25 »

The methods
createBufferStrategy(int)
and
getBufferStrategy()
belongs to the
Window
interface and
JFrame
does just implement them.
Canvas
is another implementation of that interface and is used my most people since it can be added as a component on both an applet as well.

For adding components when in active rendering mode, I don't know how to do it but I recommend Chapter 3 (UI) of Developing Games In Java which explains a way to do it.

Offline Teedo

Senior Newbie





« Reply #12 - Posted 2013-08-29 23:06:13 »

Ah i see....According to this http://docs.oracle.com/javase/7/docs/api/java/awt/Canvas.html - Canvas isn't a subclass of Window, but it does have it's own buffer strategy methods.
To paint a JTextField, i needed to call the paint method on the textfield itself Smiley
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

E.R. Fleming (20 views)
2014-07-29 03:07:13

E.R. Fleming (7 views)
2014-07-29 03:06:25

pw (39 views)
2014-07-24 01:59:36

Riven (39 views)
2014-07-23 21:16:32

Riven (26 views)
2014-07-23 21:07:15

Riven (28 views)
2014-07-23 20:56:16

ctomni231 (59 views)
2014-07-18 06:55:21

Zero Volt (50 views)
2014-07-17 23:47:54

danieldean (42 views)
2014-07-17 23:41:23

MustardPeter (45 views)
2014-07-16 23:30:00
HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54

HotSpot Options
by Roquen
2014-05-06 15:03:10

Escape Analysis
by Roquen
2014-04-29 22:16:43

Experimental Toys
by Roquen
2014-04-28 13:24:22
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!