Problem with smoothness of starfield and space shi

I am trying to make a very simple space shooter game. I am using GAGE timer.
I want to run the game at full speed (max fps possible). The starfield
runs fine if I remove the line

SystemTimer.sleep((lastLoopTime + 10) - SystemTimer.getTime());

But then the spaceship does not move well (well, even with the line above
the movement of the spaceship is crappy). What should I do to have
a smooth starfield and my player(the spaceship) movement?

Thanks for the help, below is part of my code.

Here is the game loop on the main class:


    private void gameLoop() {
        long lastLoopTime = SystemTimer.getTime();

        while (this.running) {
            long delta = SystemTimer.getTime() - lastLoopTime;
            lastLoopTime = SystemTimer.getTime();

            lastFpsTime += delta;
            fps++;

            if (lastFpsTime >= 1000) {
                frame.setTitle(" (FPS: " + fps + ")");
                lastFpsTime = 0;
                fps = 0;
            }

            Graphics2D g = (Graphics2D) this.strategy.getDrawGraphics();
            g.setColor(Color.black);
            g.fillRect(0, 0, 800, 600);

            g.setColor(Color.white);
            stars.render(g);
            stars.move();

            if (!this.waitingForKeyPress) {
                for (int i = 0; i < this.sprites.size(); i++) {
                    Sprite sprite = (Sprite) sprites.get(i);
                    sprite.move(delta);
                    sprite.draw(g);
                }
            }

            g.dispose();
            this.strategy.show();

            this.player.setDx(0);

            if ((this.leftPressed) && (!this.rightPressed)) {
                this.player.setDx(-100);
            } else if ((this.rightPressed) && (!this.leftPressed)) {
                this.player.setDx(100);
            }
            
          SystemTimer.sleep((lastLoopTime + 10) - SystemTimer.getTime());
        }
    }

Here is the code of the move method on the Sprite class:


    public void move(long pDelta) {
        this.x += ((pDelta * dx) / 1000);
        this.y += ((pDelta * dy) / 1000);
    }

Here is the starfield code:


public class StarField
{
    private static final int STAR_MAX = 50;
    private int screenWidth;
    private int screenHeight;
    private int x[];
    private int y[];
    private int speed[];

    public StarField(int pScreenWidth, int pScreenHeight)
    {
        this.screenWidth = pScreenWidth;
        this.screenHeight = pScreenHeight;
        this.x = new int[STAR_MAX];
        this.y = new int[STAR_MAX];
        this.speed = new int[STAR_MAX];
        for(int i=0; i < STAR_MAX; i++) {
            this.x[i] = (int)(this.screenWidth * Math.random());
            this.y[i] = (int)(this.screenHeight * Math.random());
            this.speed[i] = (int)(3 * Math.random()) + 1;
        }
    }
    
    public void render(Graphics2D g)
    {
        for(int i=0; i < STAR_MAX; i++) {
            g.drawLine(this.x[i], this.y[i], this.x[i], this.y[i]);
        }
    }


    public void move()
    {
        for(int i=0; i < STAR_MAX; i++) {
            this.y[i] += this.speed[i];
            if(this.y[i] > this.screenHeight)
                this.y[i] -= this.screenHeight;
        } 
    }

}


[quote]I am trying to make a very simple space shooter game. I am using GAGE timer.
I want to run the game at full speed (max fps possible). The starfield
runs fine if I remove the line

SystemTimer.sleep((lastLoopTime + 10) - SystemTimer.getTime());

[/quote]
What’s this “SystemTimer” thing? That doesn’t look like GAGETimer. ??? You must be using GTGE. But does GTGE still use GAGE? When I checked the 2.0 JavaDocs, I saw no mention of it.

[quote]But then the spaceship does not move well (well, even with the line above the movement of the spaceship is crappy). What should I do to have a smooth starfield and my player(the spaceship) movement?
[/quote]
Instead of removing the sleep call outright, just replace it with:

Thread.yield();

That will give the event thread a chance to react, and should help speed up your rendering. :slight_smile:

Actually SystemTimer is a class written by Kevin Glass in his Space Invaders tutorial that
use GAGE timer.
I have added a Thread.yield() before SystemTimer.sleep((lastLoopTime + 10) - SystemTimer.getTime());
It helped a little bit but it still not very smooth. What is the best loop structure to
run the game in full fps?


import com.dnsalias.java.timer.AdvancedTimer;


/**
 * A wrapper class that provides timing methods. This class
 * provides us with a central location where we can add
 * our current timing implementation. Initially, we're going to
 * rely on the GAGE timer. (@see http://java.dnsalias.com)
 *
 * @author Kevin Glass
 */
public class SystemTimer {
    /** Our link into the GAGE timer library */
    private static AdvancedTimer timer = new AdvancedTimer();

    /** The number of "timer ticks" per second */
    private static long timerTicksPerSecond;

    /** A little initialisation at startup, we're just going to get the GAGE timer going */
    static {
        timer.start();
        timerTicksPerSecond = AdvancedTimer.getTicksPerSecond();
    }

    /**
     * Get the high resolution time in milliseconds
     *
     * @return The high resolution time in milliseconds
     */
    public static long getTime() {
        // we get the "timer ticks" from the high resolution timer
        // multiply by 1000 so our end result is in milliseconds
        // then divide by the number of ticks in a second giving
        // us a nice clear time in milliseconds
        return (timer.getClockTicks() * 1000) / timerTicksPerSecond;
    }

    /**
     * Sleep for a fixed number of milliseconds.
     *
     * @param duration The amount of time in milliseconds to sleep for
     */
    public static void sleep(long duration) {
        timer.sleep((duration * timerTicksPerSecond) / 1000);
    }
}

Of course. I forgot all about Kev’s tut. Honestly though, I don’t recommend using the “timer” he built there. All it does is sacrifies precision and usefulness for the sake of being easy to understand. i.e. It’s built for teaching purposes, not production purposes. For most games you’ll want to use the AdvancedTimer directly.

[quote] I have added a Thread.yield() before SystemTimer.sleep((lastLoopTime + 10) - SystemTimer.getTime());
[/quote]
You should do one or the other, but not both. If you want the maximum framerate possible, then have one call to Thread.yield(). If you want to limit your framerate, then use the algo described on the GAGE Homepage under the heading “The keyboard is slow, but I’m getting a really good framerate!”

Hope this helps. :slight_smile:

tks jbanes. Just one more question.

I made the following class for testing. The purpose is to lock the game at 60 FPS. I am using
the GAGE timer. But I noticed that the variable elapsedTime varies too much. Shouldn’t it be fixed
at 16.666666? If you run this program and waits a little bit and then close the window I print
the min and max values for elapsedTime. Here in my box (Linux, j2se1.4.2_02) I’ve got different
values in range from 0-450… I can’t understand why this is happining. If you pass the mouse
over the window while the program is running the values vary much more…

I’m using the elapsedTime value in my StarField and Ship move methods, so I think that because
of this variance of the variable is that my game is not running smooth… Could u please give
me a help for setting a correct loop to fix the game at 60FPS? Also I want to pass the elapsedTime
to update the position of the StarField, the Ship, the Aliens,etc…

Tks for the help


public class TestTimer extends Canvas {

    private BufferStrategy strategy;

    private JFrame frame;

    private long lastFpsTime;

    private int fps;
    
    private long minDelta=10000;
    private long maxDelta=0;

    public TestTimer() {
        frame = new JFrame("Test Timer");

        JPanel panel = (JPanel) frame.getContentPane();
        panel.setPreferredSize(new Dimension(800, 600));
        panel.setLayout(null);

        this.setBounds(0, 0, 800, 600);
        panel.add(this);

        this.setIgnoreRepaint(true);

        frame.pack();
        frame.setResizable(false);
        frame.setVisible(true);

        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.out.println("min delta="+ minDelta + " max delta=" + maxDelta);
                System.exit(0);
            }
        });

        this.requestFocus();

        this.createBufferStrategy(2);
        this.strategy = this.getBufferStrategy();
        this.gameLoop();
    }
    

    private void gameLoop() {
            long lastTicks, currentTicks, elapsedMs, ticksPerSecond;
            AdvancedTimer timer = new AdvancedTimer();
            ticksPerSecond = AdvancedTimer.getTicksPerSecond();
            long sleepTime = AdvancedTimer.getTicksPerSecond() / 60; // 60 FPS
            long ticks = 0;
            timer.start();
            lastTicks = timer.getClockTicks();
        
        while (true) {
                  currentTicks = timer.getClockTicks();
                  elapsedMs = ((currentTicks - lastTicks) * 1000) / ticksPerSecond;

System.out.println(elapsedMs);                  
                  
                  if(elapsedMs < minDelta) {
                      minDelta = elapsedMs;
                  }
                  if(elapsedMs > maxDelta) {
                      maxDelta = elapsedMs;
                  }

                  fps++;
                  lastFpsTime += elapsedMs;
                  // Update fps counter if 1 sec has passed.
                  if(lastFpsTime >= 1000) {
                        frame.setTitle("FPS=" + String.valueOf(fps));
                        fps=0;
                        lastFpsTime =0 ;
                  }
                  
                  
            

            Graphics g = this.strategy.getDrawGraphics();
            g.setColor(Color.black);
            g.fillRect(0, 0, 800, 600);

            g.dispose();
            this.strategy.show();

                  
                  lastTicks = currentTicks;
                  timer.sleepUntil(ticks + sleepTime);
                  ticks += sleepTime;
            
        }
    }

    public static void main(String[] args) {
        TestTimer t = new TestTimer();
    }
}

GAGETimer can only lock the FPS for frames that generally generate in less time than the allotted amount. If your frames are taking longer than 16.6 ms to generate, then I’m afraid that there’s nothing that GAGETimer can do to fix it.

Things that can cause your game to slow down are:

  • Use of System.outs and other forms of blocking I/O
  • Improperly loaded images (they MUST be accelerated or Java2D is going to have a fit)
  • Drawing lots of tiny images or dots. Beware that drawXXX and fillXXX routines WILL slow your code down. Often it’s actually faster to use tiny images

I highly recommend profiling your code to find where the problem is. Good luck! :slight_smile:

But as you can see above my TestTimer class is very simple. It is using BufferStrategy in a window of 800x600 and I am performing a fillRect to clear the window each frame. Is there a better way for cleaning the screen without using fillRect? For this test I am not using any images and the time for drawing each frame is not constant as I expected (elapsedMs var). I can’t really understand what is going on.

Does anybody here can give a help?

A strange thing happen… when I keep moving the mouse over the window it seems that the time for each frame becomes more constant…but it really makes non-sense to me.

clearRect? :stuck_out_tongue: