4
\$\begingroup\$

If I have a (complex) operation that takes a long time for it to finish, for instance, a couple of seconds, my frame rate drops far below the acceptable. How could I still implement it while it is not messing up my frame rate?

\$\endgroup\$

4 Answers 4

3
\$\begingroup\$

Without using threads, here are two ways.

  • do all at once (cLogic)
  • using something I call a state machine (cLogicStateMachine)

Call cLogic::Update(), check if its member updating is TRUE, if so return or else turn it on. Do the logic. Before exiting the function, turn off updating.


In the state machine you do one thing at each frame. Leaving the state as it is afterwards. So it catch on there where you left off.

A possibility can be, make a variable that catches the time, do some iterations until 0.1 seconds has passed and leave, the states stay as they are.


Not familiar with cocos2-iphone myself I produced a pseudo-code-like example based on c++. As you are asking the principle, I think that would be okay. It surely can use optimizations.

class cLogicStateMachine
{
    cLogic() 
    :   // initialize members
        Iterating( FALSE ),
        IteratorX( -1 ),
        IteratorZ( 0 ){};
    void    Update()
            {

                if( Iterating )
                {

                    ++IteratorX;
                    if( IteratorX > 31 )
                    {

                        IteratorX = 0;

                        ++IteratorY;
                        if( IteratorY > 31 )
                        {

                            // Reset
                            IteratorX = -1;
                            IteratorY = 0;
                            Iterating = FALSE;
                            return;

                        }

                    }

                    playfield[ IteratorY * 32 + IteratorX ] = TILE_TYPE_NONE;

                }

            }
    BOOL    Iterating;
    int     IteratorX;
    int     IteratorY;
};

class cLogic
{
    cLogic() 
    :   // initialize members
        updating( FALSE ){};
    void    Update()
            {

                if( updating )
                    return;

                updating = TRUE;

                /* do logic */

                // loop around the current tile to check walkability
                for( int y = 0; y < 32; ++y )
                {

                    for( int x = 0; x < 32; ++x )
                    {

                        playfield[ y * 32 + x ] = TILE_TYPE_NONE;

                    }

                }
                /* end logic */

                updating = FALSE;

            };
    BOOL    updating;

};

class cMain
{
    cMain()
    : // initialize members
      m_timeUpdateGameLogic( 0.0f ){};
    void    update()
            {

                /* collect all data you need to know */

                m_timeUpdateGameLogic += elapsedTime;
                if( m_timeUpdateGameLogic >= 0.5f )
                {

                    m_timeUpdateGameLogic -= 0.5f; // set to 0 but without lagging

                    if( using_statemachine )
                    {

                        if( m_logic.Iterating == FALSE )
                        {

                            // start over
                            m_logic.Iterating = TRUE;

                        }

                    } else
                    // if using cLogic
                    {

                        m_logic.Update();

                    }

                }

                if( using_statemachine )
                {

                    m_statemachine.Update()

                }

                /*
                    handle other stuff like view movement
                    score update
                    and such
                */

            }
    void    render()
            {

                /* conclude the logic, i.e. render everything */

            }
    float               m_timeUpdateGameLogic;
    cLogic              m_logic;
    cLogicStateMachine  m_statemachine;

}
\$\endgroup\$
4
\$\begingroup\$

It is possible to separate the render thread from the update thread, but it is quiet difficult to make. You'll need a triple-buffer of the render state. For an explanation of the problem and solution check out:

http://blog.slapware.eu/game-engine/programming/multithreaded-renderloop-part1/ http://blog.slapware.eu/game-engine/programming/multithreaded-renderloop-part2/ http://blog.slapware.eu/game-engine/programming/multithreaded-renderloop-part3/ http://blog.slapware.eu/game-engine/programming/multithreaded-renderloop-part4/

The site contains both source + binary distribution if you're interested.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ Not only is your answer simply a link, but you answered a question that has had an answer for months. \$\endgroup\$ Oct 11, 2012 at 3:38
2
\$\begingroup\$

Create separate threads for drawing and logic, if you want improved performance.

But, you can have update() and render() functions, which get called at different times. By doing this, you ensure that these two are separated, and that they do not depend on each other. That's the general direction you want to take, because it makes debugging a lot easier. Plus, once you've done that, creating separate threads for these things will be a piece of cake!

If you were a bit more specific and told us what problems are you having exactly, it would be easier to answer the question.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I agree with the first part. However, I dont think update() and render() methods should be placed in separate threads because there is a lot of dependencies between them and it would affect performance. multithreading is good inside sub-systems, not between them. See gamedev.stackexchange.com/questions/7338/… \$\endgroup\$
    – tigrou
    Aug 6, 2012 at 22:19
  • \$\begingroup\$ Note that some engines that exist and ship actually disagree with you. For instance, UE3/UDK. \$\endgroup\$ Oct 11, 2012 at 15:22
1
\$\begingroup\$

Hrm...

My first guess would be multithreading. For example, if you had your logic and render in the main loop, if logic takes a long time, you don't get anything rendered till it is done. With multiple threads, the render can be independant of the logic, and so evedn if the logic is bogged down, stuff still gets rendered, etc.

As per how to calculate it every 1/2 seconds, I am sure whatever libraries you are using contain the simple contraption of some sort of timing devices/timers, etc. Or, in the case the logic is threaded by itself, a sleep might also suffice.

The problem of ensuring the logic is completed by the time it must next be calculated might be tricky, depending on specifically what you are doing. You could: optimize the logic calculations, thread individual part of the logic (though I haven't actually used threads in a real application, so how to seperate but coordinate the logic, I don't know much on). Alternatively, perhaps you can either set a minimum calculation time (say 0.5 seconds) and give it as much time as it needs, or somehow otherwise coordinate the application to the time it takes.

\$\endgroup\$

You must log in to answer this question.

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