Delta time

Advanced game related topics
Joubarbe
Enthusiast
Enthusiast
Posts: 555
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Delta time

Post by Joubarbe »

Hi,

So I wanted to implement delta-time (and global/individual time scale); thought it was easy... I picked up pieces of code here and there, but I'm at the point where I don't fully understand the code, even though it's not (yet) a complete fail.

Here is the code:

Code: Select all

Enumeration  
  #Cursor
EndEnumeration

Structure _fps
  targetFps.f
  fps.f   
  ticksPerSecond.i
  currentTicks.i
  frameDelay.i
  frameRate_real.i
  frameRate_internal.i
  frameStep.f
EndStructure

Structure _world
  delta.f
  timeScale.f
EndStructure

Structure _object
  sprite.i
  timeScale.f
  speed.f
  x.f
  y.f
  destX.f
  destY.f
EndStructure

Structure _xy
  x.f
  y.f
EndStructure

; ------------------------

Global world._world, object1._object
Global fps._fps

Procedure DrawCursor()
  CreateSprite(#Cursor, 2, 2, #PB_Sprite_AlphaBlending)
EndProcedure

Procedure DrawObject(*object._object)
  *object\sprite = CreateSprite(#PB_Any, 4, 4, #PB_Sprite_AlphaBlending)
EndProcedure

Procedure Init()
  InitSprite() : InitKeyboard() : InitMouse()
  
  fps\frameRate_real = 60
  fps\frameRate_internal = 60
  fps\frameStep = fps\frameRate_real * 0.1
EndProcedure

; ------------------------

Procedure InitFPSLimit(target.f)
  fps\targetFps = target
  fps\ticksPerSecond = 1000
  fps\frameDelay = GetTickCount_()
EndProcedure

Procedure SetSpeedFactor()
  fps\currentTicks = GetTickCount_()
  world\delta = (fps\currentTicks - fps\frameDelay) / (fps\ticksPerSecond / fps\targetFps)
  If world\delta <= 0  
    world\delta = fps\targetFps * 0.001
  EndIf
  fps\fps = fps\targetFps / world\delta
  fps\frameDelay = fps\currentTicks
EndProcedure

Procedure.f GetDistance(x1.i, y1.i, x2.i, y2.i)
  Define dx.f = x1 - x2                  
  Define dy.f = y1 - y2                  
  Define dist.f = Sqr(dx*dx + dy*dy)
  
  If dist < 0
    dist * -1
  EndIf
  
  ProcedureReturn dist
EndProcedure

Procedure MoveObject(*object._object, destX.i, destY.i)
  Define direction._xy, distance.f, norm.f
  
  *object\destX = destX
  *object\destY = destY
  
  direction\x = *object\destX - *object\x
  direction\y = *object\destY - *object\y
  
  norm.f = Sqr(Pow(direction\x, 2) + Pow(direction\y, 2))
  If norm
    direction\x / norm
    direction\y / norm
  EndIf
  
  distance = GetDistance(*object\x, *object\y, *object\destX, *object\destY)
  
  If distance < *object\speed
    ;*object\x + direction\x * distance
    ;*object\y + direction\y * distance
    ;*object\x = *object\destX
    ;*object\y = *object\destY
  Else
    *object\x + (direction\x * *object\speed) * world\delta
    *object\y + (direction\y * *object\speed) * world\delta
  EndIf
  
EndProcedure

Procedure InitObject(*object._object)
  DrawObject(*object)
  
  *object\speed = 5
  *object\timeScale = 1
EndProcedure

; ------------------------

Init()
OpenWindow(0, 0, 0, 640, 640, "", #PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0), 0, 0, 640, 640, 0, 0, 0, #PB_Screen_NoSynchronization)

DrawCursor()

InitObject(@object1)

SetFrameRate(fps\frameRate_real)
InitFPSLimit(fps\frameRate_internal / fps\frameStep)

Repeat
  
  While WindowEvent() : Wend
  
  FlipBuffers()
  ClearScreen(0)
    
  ExamineKeyboard() : ExamineMouse()
  
  SetSpeedFactor()
  
  If MouseButton(#PB_MouseButton_Left)
    MoveObject(@object1, MouseX(), MouseY())
  EndIf
  
  DisplayTransparentSprite(#Cursor, MouseX(), MouseY(), 255, #White)
  DisplayTransparentSprite(object1\sprite, object1\x, object1\y, 255, RGB(0, 255, 0))
  
  Delay(1)
  
Until KeyboardPushed(#PB_Key_Escape)
Keep pushing the left mouse button to move the green square. It's supposed to be the same speed at 60 FPS then at 10. By "same speed" I mean that it takes the same amount of time for the object to go from point A to point B. Which is not the case in my code. Any help would be appreciated! :)
#NULL
Addict
Addict
Posts: 1440
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: Delta time

Post by #NULL »

hi.
i did not understand the code, but onestly to me it looks to complicated for what you are trying to do :)
may i suggest another example?

Code: Select all

InitSprite()
InitMouse()

ww=800
wh=600
style | #PB_Window_ScreenCentered
style | #PB_Window_SystemMenu
style | #PB_Window_MinimizeGadget

win=OpenWindow(#PB_Any, 50,100, ww,wh, "", style) :: AddKeyboardShortcut(win, #PB_Shortcut_Escape, 10)
OpenWindowedScreen(WindowID(win), 0,0, ww,wh, 0,0,0)

Repeat
  ExamineMouse()
  
  ; calculate frame rate (updates only twice a second to be 'human readable')
  frame + 1
  If ElapsedMilliseconds() > FRt
    FRt = ElapsedMilliseconds() + 500    ; since we update each half a second
    FR = frame * 2                       ; we multiply counted frames by 2
    frame = 0
  EndIf
  
  If MouseButton(1)
    Delay(100)
  EndIf
  
  Repeat
    event = WindowEvent()
    em = EventMenu()
    Select event
      Case #PB_Event_CloseWindow
        quit = #True
      Case #PB_Event_Menu
        Select em
        Case 10
          quit = #True
        EndSelect
    EndSelect
  Until Not event
  
  ; we want angle to increase 360 degrees per second
  angle.f + Radian(360) * perSecond.f
  
  ; move around screen center with radius 100
  posX = ww/2 + Cos(angle) * 100
  posY = wh/2 + Sin(angle) * 100
  
  StartDrawing(ScreenOutput())
    DrawingMode(#PB_2DDrawing_Transparent)
    DrawText(200,20,"press left mousebutton for framerate drop")
    DrawText(20,40,"framerate: " + FR)
    DrawText(20,60,"frame duration: " + frameDuration + "ms")
    Circle(posX, posY, 10)
    Circle(MouseX(), MouseY(), 1)
  StopDrawing()
  
  FlipBuffers()
  ClearScreen($333333)
  
  ; get a 'perSecond' factor to be used for movement etc.
  ; if the frame took 500 ms we would have 2 FPS, so our perSecond factor would be 0.5
  ; if the frame took 1000 ms we would have 1 FPS, so our perSecond factor would be 1.0
  ; if the frame took 2000 ms we would have 0.5 FPS, so our perSecond factor would be 2.0
  ; we could also calculate the framerate here (FR.f = 1000.0 / frameDuration), but that's
  ; not suitable for displaying ('number flickering')
  
  perSecond.f = frameDuration / 1000
  
  ; calculate the length of current frame in milliseconds
  frameDuration = ElapsedMilliseconds() - frameFinished
  frameFinished = ElapsedMilliseconds()
  
Until quit
here we calculate the duration of the finished frame which then is available in the next frame as 'frameDuration'.
then we derive a factor 'perSecond' from that which we use in calculations like movement etc.
the framerate calculation at the beginning of the loop is only for display and not used in calculations.
Joubarbe
Enthusiast
Enthusiast
Posts: 555
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Re: Delta time

Post by Joubarbe »

Well, thank you very much sir! Your code is way more simple, smooth, and working fine :)

Sometimes I just persevere in crappy code.
Post Reply