GLBasic forum

Main forum => GLBasic - en => Topic started by: Amon on 2010-Feb-08

Title: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: Amon on 2010-Feb-08
Can anyone help convert this fixed rate logic code from BlitzMax to GLbasic, please?

Code (glbasic) Select
Global Delta:Float
Global FixedRateLogic: TFixedRateLogic = New TFixedRateLogic
Global width:Int = 100
Global x# = 0
Global change# = 0

Function ccCalcMSPerFrame#(theFrameRate%)
Return 1000.0/theFrameRate 'use .0 to ensure Float is returned
End Function

' -----------------------------------------------------------------------------
Type TFixedRateLogic
'Use to keep a game's logic running at a fixed rate, independent of refresh rate.
Field Framerate# = 200 'Speed you want the logic to run at.  Float on purpose so calculations end up as float
Field LastTime:Double
Field NumTicks:Double
Field LastNumTicks:Double
Field MS# = 0 'milliseconds per frame Float

Method Init()
CalcMS()
'Set a first value for LastTime (it will be used in the main loop)
'This method should also be called if gameplay is paused for any reason such as
'showing Paused or a Menu, or focus regained after loss of focus.
LastTime = MilliSecs()
NumTicks = 0
LastNumTicks = 1
SetDelta(1)
End Method

Method CalcMS()
MS = ccCalcMSPerFrame(Framerate)
End Method

Method Calc()
'Used Fixed Rate Logic (Retro64 method) to calculate number of Logic Loop interations
'For our purposes, a tick is based on FRAMERATE.
'Get the time and make sure at least 1 tick expired

Local TmpMS:Double 'float isn't accurate enough because Millisecs is such a big number

'New code JB 30/04/06
Local Now:Int = MilliSecs()

'little sanity check here in Case the timer flips back To 0 :)
If Now < LastTime Then
NumTicks = LastNumTicks 'best we can do
Else
TmpMS = Now - LastTime
NumTicks = TmpMS/MS
EndIf
LastTime = Now

'Account for when the user alt-tabs (i.e. don't allow a silly amount of logic iterations)
'Remember NumTicks is not in millisecs, it's Millisecs/MS and MS is normally 5 if framerate is 200.
If NumTicks > 100 Then NumTicks = LastNumTicks 'use the last sensible value (hopefully)
If NumTicks > 50 Then NumTicks = 50 'prevent too many iterations on really slow machines.
LastNumTicks = NumTicks
End Method

Method SetDelta(d#)
'Sets a global variable called Delta for use with all movement
Delta = d#
End Method
End Type

Function MainLogicLoop()
FixedRateLogic.Calc()

Local oldx# = x
'Now we do the logic loop ... from 1 not 0!
For Local i:Int = 1 To Floor(FixedRateLogic.NumTicks)
FixedRateLogic.SetDelta(1)
LogicWrapper()
Next
'Is there a remaining bit in the Numticks float?
Local remainder# = FixedRateLogic.NumTicks Mod 1
If remainder > 0 Then
FixedRateLogic.SetDelta(remainder)
LogicWrapper()
EndIf
change:Float = x - oldx
End Function

' -----------------------------------------------------------------------------
Function LogicWrapper()

End Function

' -----------------------------------------------------------------------------
Function Draw()

End Function

FixedRateLogic.Init()
Global ScreenUpdate:Double

While Not KeyHit(KEY_ESCAPE)
MainLogicLoop()
Cls
Draw()
' Flip 0 'try this to see how it stays the same speed even with VSync off
Flip 1
Wend
Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: Moru on 2010-Feb-08
There are several GLBasic versions on the boards already, look around :-)
Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: Kitty Hello on 2010-Feb-09
Isn't that what LIMITFPS does?
Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: Amon on 2010-Feb-09
Nope, limitFPS causes jitters everytime I use it. FixedRate logic seperates the Drawing from the logic and processes the logic seperately. This keeps the framerate the same no matter the computer it runs on (within reason).
Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: Moru on 2010-Feb-09
If you set LIMITFPS to 60 and the computer running the game can only manage 30 FPS because it's too slow, all your timed events will run at half speed. Did I understand the problem right? :-)
Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: Kitty Hello on 2010-Feb-09
Yes, sort of. But it will skip any delays until it will reach full 60 FPS then.
And the method he suggests runs at 60 fps, because it skips the drawing then?
Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: Amon on 2010-Feb-09
Yep! Drawing and logic are in 2 different function and processed seperately. The logic is processed at 200ticks while the drawing is left completely to the refresh rate. This way you get smooth movement and perfect logic processing.

I hope that makes sense? :)

LIMITFPS ont he other hand probably processes it all and like Kitty says waits for 60fps again and this is where the jitter happens.
Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: Amon on 2010-Feb-09
Quote from: Ocean on 2010-Feb-09
Quote from: Amon on 2010-Feb-09
Yep! Drawing and logic are in 2 different function and processed seperately. The logic is processed at 200ticks while the drawing is left completely to the refresh rate. This way you get smooth movement and perfect logic processing.

I hope that makes sense? :)

LIMITFPS ont he other hand probably processes it all and like Kitty says waits for 60fps again and this is where the jitter happens.

that makes total sense to me.... =D

Ocean

:)
Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: sf-in-sf on 2015-Mar-31
Hi!
I am facing an other problem, when I want to transfer my generative pgm to an android tablet for the multi-touch function. (it's more intuitive to use fingers than typing numbers in a console). The logic/renderer can be very long, and it must be interrupted whenever a touch/event happens from the fingers, for a decent responsiveness. What is the way to set a kind of real-time interrupt (or vector) like with the microcontrolers? ...that only reacts to the system ticks/time/clock (usually in ms), independently of the FPS / refresh rate.

In other words, LIMITFPS becomes useless in this case, when the logic takes much longer than the refresh rate. What's the way around it? Thank you!   (Please note: LIMITFPS is v. useful to synchronize some short logic with a steady frame-per-second rate, for good visual results.) 
Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: erico on 2015-Mar-31
 :offtopic: Nice dig, I see a quote from Ocean, but can´t see his post, is he gone from the boards? Damn he is a nice chap.
Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: spacefractal on 2015-Mar-31
You can use a frame skip measure when the update() called twice when the render is over budget. Or you can use timer based measure.

It's depend on game wath the used best.

Recently I'm let user set 30 or 60fps in both karma miwa (using timer measure) and greedy mouse (using frameskip measure).

Also on some devices multi touch can slowdown the device quite much, which is nothing I'm can do.
Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: MrTAToad on 2015-Mar-31
Usually you would set LIMITFPS to -1 to allow it to go as fast as possible, and then use a rate logic routine, with one being (which I converted from BlitzMax ages ago) :

Code (glbasic) Select
// --------------------------------- //
// Project: AppTimer
// Start: Thursday, September 11, 2008
// IDE Version: 5.360

//! This help file contains information for using the AppTiming system, which can be used to give a consistent movement speed
//! independant of the processor speed
//! The original code was for BlitzMax, and was written by JoshK
//! Converted to GLBasic by Nicholas Kingsley
//! You call the routines like :
//! LOCAL blah AS TAppTime
//! blah.Initialise_AppTime()
//! speed=blah.Update_AppTime()

TYPE TAppTime
AppTime_UPS;AppTime_Iterator;AppTime_CurrentTime;AppTime_PauseStart;AppTime_Speed;AppTime_DesiredLoopTime;AppTime_LastUpdateTime
AppTime_LastUPSTime;AppTime_DesiredFrequency%

//! This function initialises the AppTimer system, and must be called first.
//\param frameRate% - This is the frame rate that you want all movement to be based on.  It defaults to 60 FPS, which is the lowest rate that should be used.
//\return Nothing is returned
FUNCTION Initialise%:frameRate%=60
LOCAL sW%,sH%

self.AppTime_UPS=0.0
self.AppTime_Iterator=0.0
self.AppTime_CurrentTime=0.0
self.AppTime_PauseStart=0.0
self.AppTime_Speed=1.0
self.AppTime_LastUpdateTime=0.0
self.AppTime_LastUPSTime=0.0
self.AppTime_DesiredLoopTime=1000.0/(frameRate*1.0)
RETURN TRUE
ENDFUNCTION

//! This function updates the timing system.  It needs to be called once per loop.
//\param No parameters are passed
//\return A movement value is returned.  This should be muliplied by the amount you want to move.  If the routine is paused, then 0.0 is returned
FUNCTION Update:
LOCAL time
LOCAL elapsed

IF self.AppTime_PauseStart<>0
RETURN 0.0
ENDIF

time=GETTIMERALL()

IF self.AppTime_LastUpdateTime=0.0
self.AppTime_Speed=1.0
self.AppTime_LastUPSTime=time
ELSE
elapsed=time-self.AppTime_LastUpdateTime
IF elapsed=0.0
elapsed=1.0
SLEEP 1
INC time,1.0
ENDIF

self.AppTime_Speed=elapsed/self.AppTime_DesiredLoopTime
ENDIF
self.AppTime_LastUpdateTime=time
self.AppTime_CurrentTime=time

INC self.AppTime_Iterator,1.0 // Its a float as it can go very large...

IF self.AppTime_CurrentTime-self.AppTime_LastUPSTime>=1000.0
self.AppTime_UPS=self.AppTime_Iterator/((self.AppTime_CurrentTime-self.AppTime_LastUPSTime)/1000)
self.AppTime_LastUPSTime=self.AppTime_CurrentTime
self.AppTime_Iterator=0
ENDIF

RETURN self.AppTime_Speed
ENDFUNCTION

//! This function is used when your program is paused or not.  If it is, then the step speed is still updated
//\param pause% - If this is TRUE, then your program is paused.  If FALSE, then it isn't
//\return Nothing is returned
FUNCTION Pause%:DoPause%
LOCAL elapsed

IF DoPause%=TRUE
IF self.AppTime_PauseStart=0.0
self.AppTime_PauseStart=GETTIMERALL()
self.AppTime_UPS=0
self.AppTime_Speed=0
ENDIF
ELSE
IF self.AppTime_PauseStart<>0.0
IF self.AppTime_LastUpdateTime<>0.0
elapsed=GETTIMERALL()-self.AppTime_PauseStart
INC self.AppTime_LastUpdateTime,elapsed
ENDIF

self.AppTime_PauseStart=0.0
self.Update()
ENDIF
ENDIF
ENDFUNCTION

//! This function returns the updates per second
//\param No parameters are passed
//\return Updates per second
FUNCTION Speed:
RETURN self.AppTime_Speed
ENDFUNCTION
ENDTYPE


Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: Ian Price on 2015-Mar-31
You do realise that the original post was created 5 years ago?

:S
Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: bigsofty on 2015-Apr-01
Strangely enough, I have just went from fixed rate logic back to frame based. I am doing a little retro shmup and realised that I actually wanted everything to slow down if things get hectic and not just jerk about trying to keep up with fixed rate logic extrapolation if below the ideal fps. Dumping deltatime felt completely alien to begin with, its strange how you get 'too' used to these things.  :S
Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: spacefractal on 2015-Apr-01
When read the sf post which has was created yesterday I'm could eventually split that to own topic since he faced intoxicated similar issue but he did not created a new thread as he really should.
Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: erico on 2015-Apr-01
But sometimes digging an old thread with same subject/topic is really cool.
We get a glimpse of our/people´s mind 5 years ago. :good:
Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: MrTAToad on 2015-Apr-01
Quote from: Ian Price on 2015-Mar-31
You do realise that the original post was created 5 years ago?

:S
Fixed rate logic problems never get old though!
Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: spicypixel on 2015-Apr-01
I use this.

Code (glbasic) Select

CONSTANT FRAMES_PER_SECOND% = 60
CONSTANT SKIP_FRAMES% = 1000 / FRAMES_PER_SECOND
CONSTANT MAX_FRAMESKIP% = 2


Code (glbasic) Select

FUNCTION GAME_LOOP:
    next_game_tick% = GETTIMERALL()
    LOCAL loops%
REPEAT
loops% = 0
WHILE( GETTIMERALL() > next_game_tick% AND loops% < MAX_FRAMESKIP%)
GAME_UPDATE()
next_game_tick = next_game_tick + SKIP_FRAMES
INC loops%
WEND
GAME_RENDER()
UNTIL (EXIT_LOOP% = TRUE)
ENDFUNCTION


I have functions for rendering and logic as you can see. The game loop function is initiated from my program state machine loop, and I return to my state machine when EXIT_LOOP% is true.

STATE MACHINE EXAMPLE
Code (glbasic) Select

WHILE Quit% = FALSE
SELECT APPSTATE%

CASE AS_TITLE_SCREEN% ; EXIT_LOOP% = FALSE ; TITLE_SCREEN()
CASE AS_SETTINGS% ; EXIT_LOOP% = FALSE ; SETTINGS_SCREEN()
CASE AS_LEVEL_SELECT% ; EXIT_LOOP% = FALSE ; LEVEL_SELECT_SCREEN()
CASE AS_GAME_OVER% ; EXIT_LOOP% = FALSE ; GAME_OVER_SCREEN()
CASE AS_CREDITS% ; EXIT_LOOP% = FALSE ; CREDITS()
CASE AS_SECRET% ; EXIT_LOOP% = FALSE ; SECRET()
CASE AS_HIGHSCORES% ; EXIT_LOOP% = FALSE ; HIGH_SCORE_TABLE()
CASE AS_HIGHENTRY% ; EXIT_LOOP% = FALSE ; HIGH_SCORE_ENTRY()
CASE AS_HOWTOPLAY ; EXIT_LOOP% = FALSE ; HOW_TO_PLAY()
CASE AS_GAME_LOOP% ; EXIT_LOOP% = FALSE ; GAME_LOOP()
DEFAULT ; Quit% = TRUE

ENDSELECT
WEND
Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: sf-in-sf on 2015-Apr-05
Hi everyone!
I would like to make my question clearer; using GETTIMERALL() is a polling technique as opposed to real-time interruption. Yes I could include some gettimeral() so the renderer looks at the time regularly, but I don't wish the "logic" to be delayed by all those lookup functions. I would like it to be interrupted automatically by the system's clock/tick/timer/milliseconds. Isn't it what happens when a renderer runs in the background as a thread?
   My goal: getting a responsive touchscreen, while the renderer is easily interrupted anytime. It's not about screen f.p.s. performance! There is an equivalent of what I want: a free Mandelbrot fractal tracer, on the android market. You set the zoom/centering/rotation with your fingers any time, and the renderer works in the background, as long as you don't touch the screen. You understand?
   How can I implement that with glbasic? With some  INLINE C code? Thank you!

(Is it that bad if the original question is a few years old?)
Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: spacefractal on 2015-Apr-05
you should have created a new thread about it, so im might split it up? This is to avoid confuction which was that its happens here. Its two differnt thing now, so...

There is no callback like this on glbasic. This is something that should do require threading, but threading is something glbasic is not good at all and crash very easy. So sadly this cannot been done in glbasic at all. Recently im fixed such a callback issue in Android to prevent a threading crash.

So here its better idea to uses GETTIMEALL() and measure to a showscreen 5 seconds per fps or such. If you uses Android Extras, then KEY(1) a toggle key. KEY(1) wait that to been checked in your code to returns eiter TRUE or FALSE. When KEY(1) have been consumed, then its changes to FALSE automatic until the next key press.

There is no counterpart for TOUCHSCREEN really. But mightbeen im could add a little Android Extras function, which can been checked the last touched presses, like KEY(1)? Im put that to the TODO list. Its a easy to do that in SDLActicity.Java.
Title: Re: FixedRateLogic needs converting from BMax to GLBasic!!!
Post by: Moru on 2015-Apr-06
No, there is nothing wrong with digging up old threads. All posts have a date on them.

If you want to interrupt the calculation you need to keep checking GETTIMERALL() in your calculation loop to see if it is time to check for touches. Every time the user touches the screen you need to restart your draw anyway. It's hard to use threads in GLBasic without crashing so for the users sake, just run in one thread and avoid crashes. :-)