PureBasic Forum
https://www.purebasic.fr/english/

Delta time
https://www.purebasic.fr/english/viewtopic.php?f=16&t=66926
Page 1 of 1

Author:  Joubarbe [ Tue Nov 08, 2016 8:05 pm ]
Post subject:  Delta time

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:
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! :)

Author:  #NULL [ Wed Nov 09, 2016 5:23 pm ]
Post subject:  Re: Delta time

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:
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.

Author:  Joubarbe [ Wed Nov 09, 2016 6:16 pm ]
Post subject:  Re: Delta time

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

Sometimes I just persevere in crappy code.

Page 1 of 1 All times are UTC + 1 hour
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/