Mouvement constant via deltatime

Informations pour bien débuter en PureBasic
G-Rom
Messages : 3626
Inscription : dim. 10/janv./2010 5:29

Mouvement constant via deltatime

Message par G-Rom »

Suite a la demande d'un collègue , voici un petit code qui montre comment gérer correctement les déplacements d'une entité ( 2d / 3d , d'une animation dans une application , etc.. ) ) via le deltatime.

Le deltatime est le temps que met votre boucle principale à être parcourue par votre programme , ce deltatime diffère suivant un PC puissant , ou moins puissant.
cela permet d'avoir un mouvement constant , et ce, sur n'importe quel pc, vous n'aurez donc pas de soucis qu'un de vos vieux code , tourne un jour beaucoup trop vite en utilisant cette méthode , le code est parlant :

si vous avez des questions , le topic est fait pour cela ;)

Code : Tout sélectionner

;
; ------------------------------------------------------------
;   21/07/2015 G-Rom
;
;   Deplacement en fonction du deltatime
;
;   le deltatime est le temps entre chaque boucle principale
;   d'une application / ou d'un jeu
;   il permet d'avoir un déplacement constant 
;   sur n'importe quel PC
; ------------------------------------------------------------
;


InitSprite() : InitKeyboard()

wnd = OpenWindow(#PB_Any,0,0,1024,768,"DeltaTime - special pour Falsam ^^")
OpenWindowedScreen(WindowID(wnd),0,0,1024,768)


deltatime.f = 0

run.b = #True

moveUp.b    = #False
moveDown.b  = #False
moveRight.b = #False
moveLeft.b  = #False

posx    = 512
posy    = 384
vitesse = 100 ; 100 pixels par secondes


While run
  
  ;
  ; on demare le "chrono"
  ;
  StartTime.i = ElapsedMilliseconds()
  
  ;
  ; window event
  ;
  Repeat
    event = WindowEvent()
    If event = #PB_Event_CloseWindow
      run = #False
    EndIf 
  Until event = 0
  
  ; 
  ; real time input
  ;
  ExamineKeyboard()
  
  If(KeyboardPushed(#PB_Key_Up))
    moveUp = #True
  Else
    moveUp = #False 
  EndIf 
  
  If(KeyboardPushed(#PB_Key_Down))
    moveDown = #True
  Else
    moveDown = #False 
  EndIf 
  
  If(KeyboardPushed(#PB_Key_Right))
    moveRight = #True
  Else
    moveRight = #False 
  EndIf 
  
  If(KeyboardPushed(#PB_Key_Left))
    moveLeft = #True
  Else
    moveLeft = #False 
  EndIf 
  
  ;
  ; update du jeu
  ;
  If moveUp     : posy - vitesse * deltatime : EndIf 
  If moveDown   : posy + vitesse * deltatime : EndIf 
  If moveRight  : posx + vitesse * deltatime : EndIf 
  If moveLeft   : posx - vitesse * deltatime : EndIf 
  
  
  ;
  ; rendu
  ;
  ClearScreen(RGB(64,128,255))
    StartDrawing(ScreenOutput())
    Circle(posx,posy,10,RGB(255,128,64))
    StopDrawing()
  FlipBuffers()
  
    
  ;
  ; on calcul le temps qu'a mis la boucle pour faire un tour & on divise par mille
  ;
  deltatime = (ElapsedMilliseconds() - StartTime) / 1000
  
  
Wend 
Edit 2023 :

Bon, un tocard du discord de Falsam dénommé "Nemrod" à pensé à tord avec son air pédant que le DeltaTime était utilisé pour le réseau et pour synchronisé des choses... , du moins il pensais que je le pensais, bref.

Le DeltaTime ne sert uniquement à avoir des déplacements constant entre 2 pc AYANT des configurations différentes, en aucun cas, je ne parle de PC connecté, si vous avez besoins de conseils techniques , demandez à Nemrod, il a décompilé mortal kombat 11 et à vu que mk11 n'avait pas d'implémentation de deltatime ( pas de bol , le jeu utilise unreal engine et utilise aussi le deltatime ) et mis en place un serveur minecraft... bref, encore un cador en prog... :D
Dernière modification par G-Rom le mar. 21/févr./2023 0:50, modifié 1 fois.
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Mouvement constant via deltatime

Message par falsam »

Merci beaucoup G-Rom pour ces explications. Tu as souvent évoqué cette gestion des déplacements d'une entité (2d / 3d) via le deltatime. Ce code est le bienvenu.
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Mesa
Messages : 1092
Inscription : mer. 14/sept./2011 16:59

Re: Mouvement constant via deltatime

Message par Mesa »

Je me permets de modifier très légèrement le code de GROM en remplaçant le while par un repeat afin de retrouver le fameux double repeat qui a été utilisé dans la doc notamment dans l'exemple de la fonction OpenWindowedScreen().

Évidemment, remplacer un while par un repeat n'est ni mieux ni moins bien, c'est juste pour faire référence à la doc. :wink:

Code : Tout sélectionner

;
; ------------------------------------------------------------
;   21/07/2015 G-Rom
;
;   Deplacement en fonction du deltatime
;
;   le deltatime est le temps entre chaque boucle principale
;   d'une application / ou d'un jeu
;   il permet d'avoir un déplacement constant 
;   sur n'importe quel PC
; ------------------------------------------------------------
;


InitSprite() : InitKeyboard()

wnd = OpenWindow(#PB_Any,0,0,1024,768,"DeltaTime - special pour Falsam ^^")
OpenWindowedScreen(WindowID(wnd),0,0,1024,768)


deltatime.f = 0

moveUp.b    = #False
moveDown.b  = #False
moveRight.b = #False
moveLeft.b  = #False

endGame.b   = #False

posx    = 512
posy    = 384
vitesse = 100 ; 100 pixels par secondes


Repeat;While #True 
  
  ;
  ; on demare le "chrono"
  ;
  StartTime.i = ElapsedMilliseconds()
  
  
  ;
  ; window event
  ;
  Repeat
    event = WindowEvent()
    If event = #PB_Event_CloseWindow
      End;Break 2 fonctionne aussi sauf si le programmeur ajoute une boucle entre les 2 repeat
    EndIf 
  Until event = 0
  
  ; 
  ; real time input
  ;
  ExamineKeyboard()
  
  If(KeyboardPushed(#PB_Key_Up))
    moveUp = #True
  Else
    moveUp = #False 
  EndIf 
  
  If(KeyboardPushed(#PB_Key_Down))
    moveDown = #True
  Else
    moveDown = #False 
  EndIf 
  
  If(KeyboardPushed(#PB_Key_Right))
    moveRight = #True
  Else
    moveRight = #False 
  EndIf 
  
  If(KeyboardPushed(#PB_Key_Left))
    moveLeft = #True
  Else
    moveLeft = #False 
  EndIf 
  
  If(KeyboardPushed(#PB_Key_Escape))
    endGame = #True
  Else
    endGame = #False 
  EndIf 
  
  ;
  ; update du jeu
  ;
  If moveUp     : posy - vitesse * deltatime : EndIf 
  If moveDown   : posy + vitesse * deltatime : EndIf 
  If moveRight  : posx + vitesse * deltatime : EndIf 
  If moveLeft   : posx - vitesse * deltatime : EndIf 
  
  
  ;
  ; rendu
  ;
  ClearScreen(RGB(64,128,255))
  StartDrawing(ScreenOutput())
  Circle(posx,posy,10,RGB(255,128,64))
  StopDrawing()
  FlipBuffers()
  
  
  ;
  ; on calcul le temps qu'a mis la boucle pour faire un tour & on divise par mille
  ;
  deltatime = (ElapsedMilliseconds() - StartTime) / 1000
  
  
Until endGame;Wend 

M.
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Mouvement constant via deltatime

Message par falsam »

Mesa j'ajoute un like sur ce que tu viens de dire même si je sais que c'est un sujet polémique sur ce forum :mrgreen:
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
G-Rom
Messages : 3626
Inscription : dim. 10/janv./2010 5:29

Re: Mouvement constant via deltatime

Message par G-Rom »

J'ai remplacer le break ( qui est crado ) par un boolean , plus propre.
G-Rom
Messages : 3626
Inscription : dim. 10/janv./2010 5:29

Re: Mouvement constant via deltatime

Message par G-Rom »

@Spock
je code comme cela car je "compartimente" mon code , si tu regardes bien , mon code à le format suivant :

Code : Tout sélectionner

run 
{
  événement système
  événement E/S ( clavier souris , etc... )
  update du jeu 
  affichage
}
pour un petit code, je te l'accorde , c'est superflu , mais dès lors que ton programmes va s’alourdir , tu ne sauras plus comment et ou & qui fait quoi si tu mélanges tout , là tu mélanges le clavier, les déplacements et tu ralentit de 2ms la boucle principale avec ton wait. c'est une très mauvaise habitude qu'il ne faut surtout pas prendre. je ne veut pas la prendre, ni la communiqué, et c'est pas 10 lignes de plus qui vont te bouffer ton disque dur ;)
G-Rom
Messages : 3626
Inscription : dim. 10/janv./2010 5:29

Re: Mouvement constant via deltatime

Message par G-Rom »

Spock a écrit : pour ce que tu dis a propos du melange ... ben non , je ne melange rien

Code : Tout sélectionner

If(KeyboardPushed(#PB_Key_Up))
      posy - vitesse * deltatime
     ;ici je continu a remplir .. mais c'est moins propre

     ; ou bien je saute dans une ou plusieurs procedures

     collision()
     point()
     ;etc...
EndIf

hum... la je vois un beau mélange ( input & update )
Pourquoi c'est "le mal absolu" ?
Déjà , sans rentré dans l'architecture d'un jeu complet, si tu veut pouvoir personnalisé tes touches d'action , avec ta façon le code va être crado.
imagine que tu veuilles utilisé et le clavier & un joypad , comment tu va faire, déplacer ton player à chaque type d'input ?

Voilà un exemple ou les choses sont bien séparer , les inputs PB d'un coté , le traitement de l'autre, suivi de l'update :

Code : Tout sélectionner

; gestion des inputs
;
If KeyboardPushed(KeyAction["up"].keyboardbutton)
  KeyAction["up"].state = #True
EndIf 

If JoystickAxisY(0,0) = -1
  KeyAction["up"].state = #True
EndIf 

If Not KeyboardPushed(KeyAction["up"].keyboardbutton) And Not JoystickAxisY(0,0) = -1
  KeyAction["up"].state = #False 
EndIf 



; Traitement des inputs
;
If KeyAction["up"].state = #True 
  PlayerMoveUp = #True
Else
  PlayerMoveUp = #False
EndIf 



; update
;
If PlayerMoveUp = #True 
  PlayerY - 100 * deltatime
EndIf 
Chaque partie peu bien sur être dans une procédure séparée et réduire le tout dans une unique procédure :

Code : Tout sélectionner

Procedure GameRun(Game* MyGame)
  While MyGame.run()  
    MyGame.event() ; event fenetre
    MyGame.processInput();
    MyGame.update(Game.deltatime)
    MyGame.render()  
  Wend 
EndProcedure
Bref, ce n'est pas le sujet, et je ne vais pas faire un engine complet , pour te prouvé ma façon de faire & plus efficace sur le long terme ;)
Répondre