Timing game just right

New to FreeBASIC? Post your questions here.
darkhog
Posts: 132
Joined: Oct 05, 2011 21:19

Timing game just right

Postby darkhog » Dec 30, 2011 20:50

Sorry for title but couldn't think of another. There are some games, especially very old ones that on newest computers runs like hell and they glitched up, because programmer didn't think that computers will get faster eventually and only solution for that is program that will slow down your CPU, while some others which run fine on modern equipment can be cheated using cpu slower.

Well, there are some titles that doesn't have such issues, for example first Jazz Jackrabbit. If you will put Win98 (last Windows with real dos, me doesn't count) on one of modern computers (like Pentium 4 or Core2Duo, not sure if 98 will go on really modern computers ;)) it'll run as fast as it did when it came out, it won't glitch and can't be cheated with cpu slower (it has slow down option in pause menu anyway, so it is not needed for people who can't go through game otherwise).

So that brings me a question - how to time game so it'll have constant framerate, not depended on CPU speed (and therefore player won't be able to cheat it using CPU slower and it'll run on uber 500 GHz quantum computers in future [if they'll have x86 architecture or hardware emulation of it of course]) Example BASIC codes would be welcomed.
Theunis Jansen
Posts: 248
Joined: Jul 01, 2010 9:35

Re: Timing game just right

Postby Theunis Jansen » Dec 31, 2011 7:57

If I had the answer I would have done it ages ago. But the wheel has already been invented viz DOSBOX.
On XP Pro Jazz Jackrabbit cannot find the extended memory and stops with an error and those old pinball games just say brrt which means they run at blinding speed and end almost immediately.
Being as lazy as I am and to run those old games I use DOSBOX 0.74 which can be used with ME, XP, Vista and Windows 7 (32 and 64 bit).
Landeel
Posts: 752
Joined: Jan 25, 2007 10:32
Location: Brazil
Contact:

Re: Timing game just right

Postby Landeel » Dec 31, 2011 11:26

If you trust CPU cycles to limit the framerate, or don't limit the framerate at all, sure you will have problems.

To have the same framerate on different CPUs, you must use the system clock and/or sync to the monitor vertical retrace to keep a constant framerate. This is the easiest way. FreeBASIC's "SCREENSYNC" command already does that very well for you.

There are also games that use a more advanced technique: timer-based movement. It means ingame movements depend only on the clock and not on a fixed framerate. I particularly don't like this much, because unless there's some sort of framerate limit, it makes the CPU and GPU work more for nothing, as most of the modern monitors will only display 60 frames per second.
But it's useful for benchmarking. And in theory, it makes the game work without slowdowns on slower systems, but with some "frame skipping".
Gonzo
Posts: 722
Joined: Dec 11, 2005 22:46

Re: Timing game just right

Postby Gonzo » Dec 31, 2011 11:28

for your own projects, just use Timer() or glfwGetTime()

Code: Select all

sub stuff()
  dim as double _walktimer, _starttime
do
  _starttime = timer
 
  do lots of necessary stuff
 
  ' this runs only every const_waittime
  if timer > _walktimer + const_waittime then
    _walktimer = timer
    do some updates here, like moving the player
  endif
 
 
  ' this runs only if we have time to do it
  if timer > _starttime + const_safetime then goto skipwork
 
scope
  do stuff here that you can wait with doing, because there might not be time left to do it
 
end scope
 
skipwork:
 
loop until terminate 'gameloop

end sub


i hope i didnt mess it up anywhere, but thats how i do it
as landeel says, its not wise to render more than necessary.. so in opengl you can enable vsync
which means it will wait with buffer swaps matching the refreshrate of screen
Landeel
Posts: 752
Joined: Jan 25, 2007 10:32
Location: Brazil
Contact:

Re: Timing game just right

Postby Landeel » Dec 31, 2011 11:35

Lachie Dazdarian
Posts: 2338
Joined: May 31, 2005 9:59
Location: Croatia
Contact:

Re: Timing game just right

Postby Lachie Dazdarian » Dec 31, 2011 13:42

vsync is somewhat unreliably from my own experience. some video cards force it on their own and you can't turn it off. some force it off, and you can't do anything about it from your program. the user has to manually mess with it via video card settings.

time-based movement is the solution, and it will only fail or make the game run too slow if you limit the time-based movement factor on really old PCs, which is what you get with other methods as well.

Planning to write a simple tutorial on this soon...
Gonzo
Posts: 722
Joined: Dec 11, 2005 22:46

Re: Timing game just right

Postby Gonzo » Dec 31, 2011 13:56

what does vsync force off have anything to do with timing? it just means excessive fps
the rest of your engine MUST ALWAYS be perfectly and expertly timed
there is no substitute for proper timing and vsync has nothing to do with it
Landeel
Posts: 752
Joined: Jan 25, 2007 10:32
Location: Brazil
Contact:

Re: Timing game just right

Postby Landeel » Dec 31, 2011 14:02

I guess you can't trust only vsync. Specially because not all monitors will use 60 fps, and some video drivers won't obey. You have to combine it with the clock timer, or SCREENSYNC.
Gonzo
Posts: 722
Joined: Dec 11, 2005 22:46

Re: Timing game just right

Postby Gonzo » Dec 31, 2011 14:10

my 3d laptop has 120 hz, and thus 120 fps is the vertical sync
i could enable and disable it with glfw
some people have vsync always on, which is fine
some like to measure fps and go for vsync off... its their choice
it doesnt affect your game in any way, ever, unless you have physics in the renderer thread, which is wrong =)

please dont tell anyone to start timing the renderer... thats just wrong
you should rely on the hardware to do the swapping by itself

on an unrelated note if you are interested in knowing how far behind the pipeline is:
http://www.opengl.org/registry/specs/AR ... _query.txt
Landeel
Posts: 752
Joined: Jan 25, 2007 10:32
Location: Brazil
Contact:

Re: Timing game just right

Postby Landeel » Dec 31, 2011 14:51

If your monitor vsync is 120 Hz, if you create a game that runs on a fixed framerate based only on the monitor vsync, when you run it on a monitor that syncs at 60 Hz, it will run at half the speed.
In a timer-based movement game it wil probably run fine, however, some video drivers are not very reliable setting vsync on/off.
Last edited by Landeel on Dec 31, 2011 14:55, edited 1 time in total.
Gonzo
Posts: 722
Joined: Dec 11, 2005 22:46

Re: Timing game just right

Postby Gonzo » Dec 31, 2011 14:54

which is why i said you never synch the rendering to the game
nor do you synch the rendering by yourself, seeing as its hardware synchronized

btw. for clarification, the rendering should be in its own thread =)
and everything else in another (and subthreads of that)
Landeel
Posts: 752
Joined: Jan 25, 2007 10:32
Location: Brazil
Contact:

Re: Timing game just right

Postby Landeel » Dec 31, 2011 14:59

That's for an OpenGL game. In fact, you don't need to create a thread, all OpenGL rendering is automatically done in a separate thread.
For a simple fbgfx FreeBASIC game, with fixed framerate, a single thread is enough.
Gonzo
Posts: 722
Joined: Dec 11, 2005 22:46

Re: Timing game just right

Postby Gonzo » Dec 31, 2011 15:02

you are talking about software rendering?
well i should imagine you would want to make your own thread for that as well, and time it according to users wishes...
though im not sure why you would want that (software) =)

indeed, the drivers usually have their own thread running, but it almost never uses all the available cycles
and theres alot that needs to be calculated before you can send the final frame render
if you simply render everything without regards, and theres so little to render so that it will simply be the best method, then no, another thread might never be necessary...

sadly, in my experience using a single thread for rendering and otherwise, didnt pan out well
i think i got at least a straight 50% boost from separating them
Last edited by Gonzo on Dec 31, 2011 15:05, edited 1 time in total.
Lachie Dazdarian
Posts: 2338
Joined: May 31, 2005 9:59
Location: Croatia
Contact:

Re: Timing game just right

Postby Lachie Dazdarian » Dec 31, 2011 15:04

Time-based movement example:

Code: Select all

#include "fbgfx.bi"
Using FB

const FALSE = 0
const TRUE = 1

SCREEN 18,32,2,0
SETMOUSE 0,0,0 

DIM SHARED Frame(6) AS ANY PTR

DIM SHARED workpage AS INTEGER
DIM SHARED AS Double frame1=1, guybrush_x = -120
DIM Shared As Integer walk_by_time = 0
Dim Shared As Double loop_time=1, this_time, tb_movement_factor=1

' FPS related variables
Dim As Integer frames_per_sec = 0
Dim As Integer fps = 0
Dim start_time As Integer
start_time = 0

BLOAD "frames.bmp", 0
FOR imagepos AS INTEGER = 1 TO 6
   Frame(imagepos) = IMAGECREATE (105, 157)
   GET (3+(imagepos-1)*104,0)-(103+(imagepos-1)*104,155),  Frame(imagepos)
NEXT imagepos

Do
   
   
    loop_time = timer-this_time
    this_time = timer
    if loop_time = 0 then loop_time = 1 ' initial loop cap min
    if loop_time > 1.6 then loop_time = 1.6 ' initial loop cap max
    'loop_time = 1/60
    tb_movement_factor = loop_time * 60 ' adjust your movement factor to 60 FPS
                                        ' (if your program runs 60 FPS, tb_movement_factor will be 1)

   
    frame1 = frame1 + 0.09 * tb_movement_factor
    if frame1 > 6.5 then frame1 = 1
    guybrush_x = guybrush_x + 2 * tb_movement_factor
    if guybrush_x > 660 then
        guybrush_x = -120
        walk_by_time = 0
    end if
   
    screenlock ' Lock our screen (nothing will be
           ' displayed until we unlock the screen).
    screenset workpage, workpage xor 1 ' Swap work pages.
   
   
    LINE (0,0)-(639,479), RGB(255,255,255), BF
    PUT (guybrush_x ,140), Frame(frame1), PSET
   
    LOCATE 1,1
    PRINT "FPS:"; fps
    PRINT "time-based factor:"; tb_movement_factor
    PRINT "walk-by time:"; walk_by_time

    workpage xor = 1 ' Swap work pages.
    screenunlock ' Unlock the page to display what has been drawn.
   
    SLEEP 10, 1
   
    frames_per_sec += 1
    dim as double timer_elapsed = (timer - start_time)
   if timer_elapsed > 1 then
      fps = frames_per_sec/timer_elapsed
      frames_per_sec = 0
        walk_by_time = walk_by_time + 1
       start_time = timer
   end if
   
Loop Until Multikey(FB.SC_ESCAPE)


Test it for different FPS (SLEEP command).

Image you need to run the code: http://img35.imageshack.us/img35/1720/framesk.png (save as BMP)
gothon
Posts: 224
Joined: Apr 11, 2011 22:22

Re: Timing game just right

Postby gothon » Jan 02, 2012 10:12

In this example, the game runs as though the framerate is 100 fps even if it isn't. Ideally you would like to hit test the path the moving object passes through with the obsticles rather than testing the object itself in a loop. This is because on a real slow computer the hit test loop could be too slow to catch up to the time that loop itself uses, and cause a runaway frame delay.

However directly testing the path volumes of moving objects is very complex, so this example gives the idea of what needs to be computed to have stable gameplay independent of computer speed.

Code: Select all

#include "fbgfx.bi"

Const dT = 0.01

Dim Shared As Single PrevX, PrevY, circlex, circley, circlespeed
Dim Shared As Double T, PrevT, FrameT

ScreenRes 800, 600, 32

circlex = 150   ' Initial circle position
circley = 100
circlespeed = 200 ' Circle's speed => 200 pixels per sec

FrameT = Timer
Do
    'Draw our frame
    ScreenLock
        Cls
        Circle (circlex, circley), 10, RGB(255, 0, 0),,,,F
        Circle (100, 100), 20,,,,,F
    ScreenUnLock
   
    Sleep 250, 1 'Emulate Really Slow computer
   
    ' Iterate until we catch up to real time
    Do Until FrameT > T
        PrevX = circlex
        PrevY = circley
        ' According to pushed key we change the circle's coordinates.
        If MultiKey(FB.SC_RIGHT) Then circlex += circlespeed * dT
        If MultiKey(FB.SC_LEFT) Then circlex -= circlespeed * dT
        If MultiKey(FB.SC_DOWN) Then circley += circlespeed * dT
        If MultiKey(FB.SC_UP) Then circley -= circlespeed * dT
        ' Test For intersection with the obsticle
        If (circlex - 100)^2 + (circley-100)^2 < (10+20)^2 Then
            circlex = PrevX
            circley = PrevY
        End If
        FrameT += dT
    Loop
   
    ' On fast computers sleep a frame time
    If Timer - PrevT < dT Then Sleep dT*1000, 1
   
    PrevT = T
    T = Timer
Loop Until MultiKey(FB.SC_Q) Or MultiKey(FB.SC_ESCAPE) Or Inkey = Chr(255) & "k"

Return to “Beginners”

Who is online

Users browsing this forum: No registered users and 11 guests