5
\$\begingroup\$

I have a thread that uses TimeUnit.MILLISECONDS.sleep(5);

Problem is when I load my app on a faster phone say with a snapdragon, it runs at lightning speed.

Is there a way to control this speed so processor speed is not an attributing factor?

Thanks!

\$\endgroup\$

3 Answers 3

-3
\$\begingroup\$

He'res the class I wrote for this purpose. Use it by first calling start() and then sleepRequiredTime() in your gameloop. call getTimeSinceLastSleep() for elapsed time.

runsPrSecondHint will dictate your wanted FPS. I'm not sure this solution is perfect though, so any input from others is welcome.

package com.ngame.spacegame.utils;

public class ThreadSleepManager {

private int m_runsPrSecondHint;
private float m_maxAllowedSleepTime;
private boolean m_running;

private long m_startTime = 0;
private long m_lastSleepTime = 0;

private int[] m_lastRuntimes;
private int m_runtimeToWriteToIndex = 0;
private int m_averageSleepTime = 0;
private int m_timeSinceLastSleep = 0;

private static final int AVERAGE_POOL = 10;

public ThreadSleepManager( int runsPrSecondHint ) {
    m_runsPrSecondHint = runsPrSecondHint;

    m_maxAllowedSleepTime = 1000.0f / m_runsPrSecondHint;
    initLastRuntimes();
}

private void initLastRuntimes() {
    m_lastRuntimes = new int[AVERAGE_POOL];
    for ( int i : m_lastRuntimes ) {
        m_lastRuntimes[ i ] = (int)m_maxAllowedSleepTime; 
    }
}

public int getTimeSinceLastSleep() {
    return m_timeSinceLastSleep;
}

public int getAverageSleepTime() {
    return m_averageSleepTime;
}

public void start() {
    m_startTime = System.currentTimeMillis();
    m_lastSleepTime = m_startTime;
}

/**
 * Sleeps an optimal amount of time for trying 
 * to have the current thread calling run at m_runsPrSecondHint
 */
public void sleepRequiredTime() {
    assert( m_running == true );
    long currentTime = System.currentTimeMillis();
    m_timeSinceLastSleep = (int) (currentTime - m_lastSleepTime);

    // Update data used for average sleep time calculation
    m_lastRuntimes[ m_runtimeToWriteToIndex ] = m_timeSinceLastSleep;
    m_runtimeToWriteToIndex = ( m_runtimeToWriteToIndex + 1 ) % AVERAGE_POOL;

    // Sleep long enough for the average time since last sleep to stay as close as
    // possible to m_maxAllowedSleepTime
    m_averageSleepTime = calcAverageTimeSinceLastSleep();

    int timeToSleep = (int) (m_maxAllowedSleepTime - m_averageSleepTime);
    if( timeToSleep > 0 ) {
        try {
            Thread.sleep( timeToSleep );
        }
        catch( InterruptedException e ) {

        }
    }

    m_lastSleepTime = currentTime;
}

private int calcAverageTimeSinceLastSleep() {
    int sum_sleep_time = 0;

    for ( int runtime : m_lastRuntimes ) {
        sum_sleep_time += runtime; 
    }

    return sum_sleep_time / m_lastRuntimes.length;
}

}

\$\endgroup\$
1
  • \$\begingroup\$ That being said, I would probably fix my time step if I were you. Even though this code here tries to find a smart amount of time to sleep based on the average calculation times of previous frames, it seems to stutter now and again. You should accept fix your timestep as answer instead =) \$\endgroup\$
    – Nailer
    Oct 15, 2010 at 8:37
18
\$\begingroup\$

You need to Fix Your Timestep!

http://gafferongames.com/game-physics/fix-your-timestep/

\$\endgroup\$
4
  • 2
    \$\begingroup\$ Favorite just for this link. Pesky black box physics. \$\endgroup\$ Oct 14, 2010 at 18:55
  • \$\begingroup\$ The OP should not be using a fixed sleep time when the rest of the processing can take an unknown amount of time. \$\endgroup\$ Oct 14, 2010 at 19:11
  • \$\begingroup\$ Please read the article fully then. He addresses this issue when he talks about "The Spiral of Death". \$\endgroup\$ Oct 14, 2010 at 19:19
  • \$\begingroup\$ yes, so I was commenting that the simple takeaway for the OP is that ... Fixed timestep is the One True Path, even if GoG takes a lot of words to get to the point. \$\endgroup\$ Oct 16, 2010 at 0:52
5
\$\begingroup\$

Instead of sleeping to regulate game speed, use the time elapsed per frame to give everything a consistent speed.

myObject.Move(elapsedTime*moveSpeed,0,0);

Something to that effect. No matter what speed the processor runs at or the framerate, the object would always move at the same speed. Make sure any movement or rotation that requires a specific speed uses the same idea.

\$\endgroup\$
6
  • 1
    \$\begingroup\$ how do I get elapsed time \$\endgroup\$ Oct 14, 2010 at 13:49
  • 1
    \$\begingroup\$ Depends on what you're using. If it's a game engine, check the documentation - there may be something built in. If not, you have to calculate it yourself using whatever time functions are available on your platform. \$\endgroup\$
    – beezir
    Oct 14, 2010 at 14:58
  • 2
    \$\begingroup\$ Do not use this exact method if you want physics that react the same way each time a simulation is run. The physics will look almost the same, but there will be small errors that accumulate and through through chaos theory, the physics will be much different each time. What happens if the game lags for 2 seconds? What about 10 seconds? Stuff might tunnel through walls. Your character might fall through the floors. Springs could "explode". I posted a better answer. \$\endgroup\$ Oct 14, 2010 at 16:33
  • \$\begingroup\$ Everything gets harder with a variable timestep, so while it is an option it is not a great one (IMO). \$\endgroup\$ Oct 14, 2010 at 19:09
  • \$\begingroup\$ Agreed, AttackingHobo's link could be considered the canonical reference for managing your timestep. \$\endgroup\$
    – jpaver
    Oct 14, 2010 at 19:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .