This discussion is archived
6 Replies Latest reply: Jun 7, 2010 10:52 AM by gimbal2 RSS

How do I fix the FPS in my platform game?

843853 Newbie
Currently Being Moderated
Hi everyone! As part of a course in Gamemaking in school, my team created a platformer with a colission-map instead of tiles. This has worked out well for the most part.

My problem is that we have a loop that updates and draws everything to the screen ( this is in windowed mode by the way ) . The game runs and the gameplay is ok.

But it runs with different speed depending on the hardware. On my computer everything is slow, but on new computers the objects race back and forth like mad. Furthermore sometimes as the player dies and the level restarts, the player dies on the spot!

From what I have read this is due to the fact that we haven´t fixed the FPS. But Im at a loss as to how im supposed to fix it. One sollution tells me to use a timer and then place logic inside actionPerforemed, but since I am using a loop inside run() this cant work.

The program is divided into several classes, but the main logic residen in the class main,java

public Main(){
          super("Mimic");
          setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);          

          setVisible(true);
          this.enableEvents(KeyEvent.KEY_PRESSED | MouseEvent.MOUSE_DRAGGED);     
          setSize(1280, 720);
          setResizable(false);
          setLocationRelativeTo(null);
          
          requestFocusInWindow();
          
          AudioPlayer.loadClip("transform", "sound/transform2.wav");
          AudioPlayer.loadClip("gameover", "sound/gameover.wav");
          AudioPlayer.loadClip("ambient", "sound/test.wav");
          AudioPlayer.loadClip("jump", "sound/jump.wav");

          //Cursor - 1x1px
          Toolkit toolkit = Toolkit.getDefaultToolkit();
          Image transparent = toolkit.getImage("images/empty_pixel.gif");
          Point hotSpot = new Point(0,0);
          Cursor game = toolkit.createCustomCursor(transparent, hotSpot, "transparent");
          setCursor(game);
          
          createBufferStrategy(3);

          transformationTimer = new Timer(1000, this);
          transformationTimer.setInitialDelay(0);

geyserTimer = new javax.swing.Timer(1000, new ClockListenerGeyser());
geyserTimer.start();
          
          mimicTimerBarBackground = new ImageIcon("images/mimic-bar-bgr.png").getImage();
          mimicTimerBar = new ImageIcon("images/mimic-bar.png").getImage();          
          start();
     
     }//public

public void start(){
          (new Thread(this)).start();
     }//start
     
     //
     public void run(){
          avatar = new Avatar();
     //Ambient sound
     //AudioPlayer.play("ambient", true); Musiken avstängd...
     
     loadLevel(Map.Levelname.LevelOne);
          //loadLevel(Map.Levelname.LevelTwo);
     
          long start = System.nanoTime();
          long delta = 0;
          long sleep;
          while(gameOn){ // game loop
               tick(delta);
               draw();                    
               delta = System.nanoTime() - start;
               sleep = DELAY - delta;
               // detta är en test för att kolla om loopen fortfarande har tid kvar att göra saker, om den har det, sov och ge den en//
          
               start = System.nanoTime();
               //tick(delta);
               //draw();               
          }//while
          System.exit(0);
}//run

//i den här metoden ligger allt motor, kollision, styrning och scrollning m.m
     public void tick(long tid) {
          float timeScale = tid/100000000f;
               
               avatar.update(tid); //animationen uppdateras
               currentMap.tick(tid);
               // update mimics

// lots of codes for Keys, colissionmap and more here.



//
     public void draw(){
          Graphics g = getBufferStrategy().getDrawGraphics();
          g.translate(-cameraX,-cameraY);          
          g.drawImage(currentMap.collisionMap, 0, 0, null);
     for(Background b: currentMap.getBackgrounds()){
          if(b.isVisible())
               g.drawImage(b.getImage(),(int)b.getX(), (int)b.getY(), null);
     }//for
     for(MapItems mi: currentMap.getItemList()){
          g.drawImage(mi.getImage(),(int)mi.getX(), (int)mi.getY(), null);           
     }//for
     
     for(Mimics m: currentMap.getList()){
          if(m.getVisas()){
               g.drawImage(m.getImage(), (int)m.getX(), (int)m.getY(), null);
          }//if
     }//for

     g.drawImage(avatar.getImage(), (int)avatar.getX(), (int)avatar.getY(), null);
     if (currentMap.levelname == Map.Levelname.LevelTwo){
          g.drawImage(grass, 0, 623, null);
     }
     
     g.drawImage(key, cameraX+1000, cameraY+72, null);
     g.drawImage(sekLevel, 800, 580, null);
          //Visar timern om den är aktiv
          if (transformationTimer.isRunning()) {
               g.drawImage(mimicTimerBarBackground, cameraX+509, cameraY+72, null);
               g.drawImage(mimicTimerBar, cameraX+514, cameraY+77, (int)(cameraX+514+(200/20)*transformationTime), cameraY+77+30, 0, 0, (int)(200/20)*transformationTime, 30, null);
               
          }
          g.setColor(Color.red);      
          g.dispose();
     getBufferStrategy().show();
     }//void

I figure I got to put a timer to fix the FPS somewhere in here, but where?

Any help is greatly appreciated!

Regard,

Gabriel
  • 1. Re: How do I fix the FPS in my platform game?
    gimbal2 Guru
    Currently Being Moderated
    Speed should be 'tick' based. The way I do it, with silky smooth results, is to lock the game to a framerate. That part is quite easy, all you do is calculate at what interval you want to update. Say you want 60FPS, it becomes:

    interval = 1000 / 60 (interval = 17ms).

    So if you want 60FPS, you have to update and draw every 17 milliseconds. That sounds like a short time, but for computers it really is not.

    Okay, so you have your game loop. while(true) { update(); render(); }. The body of this loop should execute every 17ms (it won't be that precise, but it will be good enough). It goes a little something like this:
    while(running){
     long measure1 = currentTimeInMillis();
     update();
     render();
     long measure2 = currentTimeInMillis();
    
     long diff = measure2 - measure1;
     Thread.sleep(17-diff); // sleep until next tick
    }
    This will have the game ticking at 58-61 FPS, depending on the timing precision of the OS - you'll find that on Linux OSes the framerate is far more steady than on Windows environments for example, in Java at least. Its just the sleep call that is far from precise.

    Now you will want to make movement based on the framerate - the way I do that is to work with float measurements. For movement speed I say 'every tick, move X.X pixels', where I keep the units in increments of 0.5 pixels. This means that moving game entities can go as slow as 0.5 pixels each tick in my games, which is slow enough for most of them. In the end when determining the actual pixel locations, the floats are rounded down to ints.

    I hope that makes some sense.
  • 2. Re: How do I fix the FPS in my platform game?
    843853 Newbie
    Currently Being Moderated
    Thanks for the speedy reply!

    Well it makes some sense, though Im still unsure where I whould put this : interval = 1000 / 60 (interval = 17ms).

    Most examples ive seen uses some kind of timer, but this is read by the loop then?

    As for the movement of the objects I think I got that, at present they move by integer speeds, so I´ll have to change that.



    Could you please clarify what you ment by interval = 1000 / 60 (interval = 17ms)?
  • 3. Re: How do I fix the FPS in my platform game?
    796262 Newbie
    Currently Being Moderated
    arch111Swede wrote:
    Well it makes some sense, though Im still unsure where I whould put this : interval = 1000 / 60 (interval = 17ms).
    You don't actually need that equation in the code anywhere, he was just telling you where he got the 17 ms value.
    Most examples ive seen uses some kind of timer,
    Okay, then use a timer that fires every 17 ms instead, if you're more comfortable with that.
    but this is read by the loop then?
    No idea what this means.
    As for the movement of the objects I think I got that, at present they move by integer speeds, so I´ll have to change that.
    What? Why?
    Could you please clarify what you ment by interval = 1000 / 60 (interval = 17ms)?
    He was just explaining to you what that 17 ms actually meant. 1 second = 1000 ms, so if you want something to happen 60 times per 1000 ms, you just use basic division to figure out the time between each event. The answer comes out to just about 17 ms. Understand?
  • 4. Re: How do I fix the FPS in my platform game?
    843853 Newbie
    Currently Being Moderated
    3 comments for you:

    1 - get out of the habbit of putting everything or even a significant portion of your logic in your "main" method. Your main method is an entry point for the compiler to link, use it as such:
    public static void main(String[] args){
      new MyProjectClass().mycontroller();  //gets you out of the static context.
    }
    2 - If you use Swing, then use a javax.swing.Timer object to controll you game loop. Don't use sleep.

    3 - anytime you use Toolkit to load an image, you should use a MediaTracker to be sure the image loaded before your program needs it, or better yet, just use ImageIO.
  • 5. Re: How do I fix the FPS in my platform game?
    843853 Newbie
    Currently Being Moderated
    Thank you for the comments. I´m a lot more clear about what needs to be done now, and yes I see the point of not haveing to much logic in the class dealing with the main-method.

    It now resides in a menu-class from where the game is launched, however the loop is in the file main.java.

    Wont use sleep from now on then.

    Ill keep looking into getting the framreate fixed by changing what you have written here.

    Thank you all for your help!

    Regards,
    Gabriel
  • 6. Re: How do I fix the FPS in my platform game?
    gimbal2 Guru
    Currently Being Moderated
    well when you get as far as making it work, there is always more fun to be had. For example: taking care of the situation where your game CANNOT deliver a steady FPS. Then nasty topics like interpolation will come into play.

    I wouldn't worry too much about that for 2D games, you'll have to do some very bad programming to drop under the 60FPS.