Tuesday 17 April 2012

Function Design

I stated that the transition code from out previous post could be improved.

At the moment, the change value is calculated on each program loop.
thisNumSteps = LastFPS() * MENU_FADE
thisValue# = TransitionCount() + (1.0 / thisNumSteps)
One change would be to calculate this only once, when the transition is started.

At them moment only the menu uses transitions, so the code is in the menu block. But if later we wanted another part of the program to use one, it would mean duplicating a lot of the code.

A more significant change would be to separate this code and put it in a dedicated function.

This is part of how a program develops.
  • A need for a routine is identified
  • New code is produced and tested
  • The code is made available to other parts of the program
Let's go back to that first change for a moment as this will feature in the design of the new functions.

The length of the fade is specific to the menu since it uses the constant MENU_FADE.  This part will need to stay specific to the menu so that other parts of the program can use different transition times.

This means that time will need to be a parameter used when calling the transition function.  The other parameter will be the transition type - in this case TRANS_FADEIN.

There are essentially two parts to the transition routine.
  • Setup - which starts the transition
  • Maintenance - which advances the counter
These define the functions we will use to perform the transition.

Before we can add these, we need to store another value, the value used for the transition step.
transStep#
This is added to the displayType definition as before.

It needs a return function.
function TransitionStep()
endfunction display.transStep#
And setting to zero in Initialise().
display.transStep# = 0.0
Because all of the work has already been done, the first of our new functions is very straight forward.
function StartTransition( thisType , thisTime# )
 display.transType = thisType
 display.transCount# = 0.0
 display.transStep# = 1.0 / (lastFPS() * thisTime#)
endfunction
This simply mimics what we did in our existing routines, so the existing lines in the menu loop.
display.transType = TRANS_FADEIN
display.transCount# = 0.0
can be replaced with a call to this function - passing the values we already use.
StartTransition( TRANS_FADEIN , MENU_FADE )
and the lines which calculate the value.
thisNumSteps = LastFPS() * MENU_FADE
thisValue# = TransitionCount() + (1.0 / thisNumSteps)
can be replaced with code that uses the new return function call.
thisValue# = TransitionCount() + TransitionStep()
And the new function can be tested.

But, what's this - it doesn't work.  Instead of fading in, the Menu just appears.  POW!

So what is different from what we had before?

The difference is when the step value is calculated.  It's now calculated too early.

To see why you need to run the program and watch the FPS in the top right hand corner of the display.

It starts at 1 and then over a period of about a second, counts up until it reaches the refresh rate of the screen, then it stays fairly constant.

AGK calculates the current frame rate based on the number of times the sync() command is called per second.  At the very start of the program, it has not been called enough times for an accurate figure to be determined.

So when the StartTransition() function is called (on program loop 2), the value returned by LastFPS() is very low.  Consequently the step value calculated is very close to 1 and the transition completes in about 5 frames.

As a workaround, we can prevent the menu from being called too soon by changing the line in the setup block that sets the game state to STATE_MENU so that it looks like this.
if timer() > 2.0 then setGameState( STATE_MENU )
This uses the timer() command which returns the run time of the program.

It now calls the menu after the program has run for 2 seconds, so enough frames have passed to give a more accurate figure for the calculation.

Now the menu fade now works as it should.

No comments:

Post a Comment