Page 1 sur 4

Comment éviter de perturber un timer?

Publié : mer. 15/déc./2004 23:03
par Torp
Salut,

Je m'explique. J'ai intégrer dans mon prog un timer qui gère le temps imparti aux joueurs. A chaque déclenchement du timer le temps restant s'affiche. Le problème est que les déplacements de la souris (ou tout autre action) semble ralentir le timer, ou plutot on dirait qu'il fait des sauts pour rattraper le temps perdu..

Il y a t'il une solution pour rendre un timer imperturbable... :? ?

Merci
Torp

Publié : mer. 15/déc./2004 23:06
par Backup
tu doit surement utiliser un "WaitWindowEvent() "

utilise un "WindowEvent()" suivi d'un delay(2) et tu aura un meilleurs
rendu , je pense ! :)

Publié : mer. 15/déc./2004 23:13
par Torp
Ben c'est ce que j'ai. Ca parait un peu mieux mais c'est pas encore ca. C'est pas vraiment linéaire comme pourrait l'etre... euh... un chrono. Si je bouge la souris rapidement (voir frénétiquement :lol:) j'arrive casiement a le stoppper que ce soit avec un WaitWindowEvent() ou un WindowEvent() avec delay(20). Il doit y avoir une solution car si tu prends en exemple la "pendule" de Windows, tu as beau bouger la souris comme un bourrin elle est IMPERTURBABLE, comme...euh...un chrono...:lol:..

Publié : mer. 15/déc./2004 23:16
par nico
T'aurais pas un petit code pour mettre en évidence?

Publié : mer. 15/déc./2004 23:16
par Torp
ouep bouge pas je prépare ca...

Publié : mer. 15/déc./2004 23:19
par Le Soldat Inconnu
Un timer renvoie un évènement donc il est inutile de passer par un windowevent()

après, tout dépend comment tui gère ton chrono. moi, j'ai jamais eu de problème.

si tu passes par une procedure

SetTimer(Windowid(), 0, 1000, @procedure())

la procedure est exécuté dans un thread différent donc pas de souci

sinon, avec ceci
SetTimer(WindowID(), 0, 1000, 0)

il faut récupérer l'évènement WM_Timer

Tu fais comment ?


petite précision, dans un jeux openscreen, on a le flipbuffer qui attend la synchronisation avec l'écran pour basculer

cela signifie que si ton fps est de 85 HZ (fps max sur un écran 85hz), tu ne peux pas être plus précis que 1/85 de secondes

et si ton FPS est plus bas, la précision est encore moindre

Publié : mer. 15/déc./2004 23:34
par Torp
Je colle un lien car il y a 2 images avec...
Le code est un peu long pour un exemple mais c'est parceque c'est un extrait de mon prog original (j'ai juste gardé ce qu'il fallait pour illustrer)
Il faut changer le C:\Temp\ dans le code, par le chemin où l'archive sera décompressée....
ouais je sais c'est pas simple :oops:

Pour illuster l'exemple, lorsque tu verras les chiffres défiler, gardes le bouton de la souris enfoncé et bouge un peu la souris.... le défilement se bloque...

Il y a les 2 codes. WaitWindowEvent et WindowEvent.

http://www.penguinbyte.com/apps/pbwebst ... /Timer.zip

Publié : mer. 15/déc./2004 23:43
par Chris
Dans le fichier avec WindowEvent, essaie de mettre:

Code : Tout sélectionner

  Select WindowEvent()
    Case 0
      Delay(20)
  EndSelect
juste avant le "Forever"

Publié : mer. 15/déc./2004 23:47
par Torp
En fait mon prog original c'est l'autre (le WaitWindowEvent). Il marche d'ailleurs mieux que celui avec WindowEvent, mais le compteur ne défile pas de facon linéaire, meme si c'est moins perceptible...

Publié : mer. 15/déc./2004 23:56
par Chris
En fait, il y a déjà un problème au niveau de la gestion de la touche Escape.

Normalement, comme tu utilises un WindowedScreen(), tu ne devrais même pas avoir besoin d'utiliser la boucle des évènements.

D'ailleurs, elle ne te sers que pour capter la touche Escape qui ferme le programme.

Essaye ça à la place:

Code : Tout sélectionner

  ;+++++++++++++++++++++++++++++++++++++++
  FlipBuffers(0)
  
  ExamineKeyboard()
  If KeyboardPushed(#PB_Key_Escape)
    End
  EndIf
  
  While WindowEvent():Wend
  Delay(1)
ForEver

Publié : mer. 15/déc./2004 23:59
par Le Soldat Inconnu
bon, ben voilà, ça marche

Code : Tout sélectionner

; +-------------------------------------------------------------------
; PURE ARNAQUE
; par Torp
; Pure Basic 3.92
; +-------------------------------------------------------------------
; OpenConsole()
; +-------------------------------------------------------------------
;- Declaration des constantes
; +-------------------------------------------------------------------
#Plateau = 1
#Cpt1 = 32 : #CptX = 7 : #CptY = 384
#Sprite = 2 : #TxtCpt = 0
; +-------------------------------------------------------------------
;- Declarations des Variables et affectations des valeurs
; +-------------------------------------------------------------------
Declare Timer()
Declare Sablier(hwnd.l, uMsg.l, idEvent.l, dwTime.l)
Global AffCpt.b, Ro.w, Ve.w, Bl.w, ValCpt.b
AffCpt = #False
PosJoueur2 = 0 : Ro = 255 : Ve = 255 : Bl = 0
Installation$ = "C:\Temp\"
LoadFont(#TxtCpt, "arial", 16) : UseFont(#TxtCpt)

; +-------------------------------------------------------------------
;- Initialisation de ecran du jeu
; +-------------------------------------------------------------------
If InitSprite() = 0 Or InitSound() = 0
  MessageRequester("Erreur", "Impossible d'initialiser DirectX", 0)
  End
EndIf

If OpenWindow(0, 0, 0, 800, 600, #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered | #PB_Window_TitleBar, "Le jarnac") = 0
  MessageRequester("Erreur", "Impossible d'afficher l'écran principal", 0)
  End
EndIf

If OpenWindowedScreen(WindowID(), 0, 0, 800, 600, 0, 0, 0) = 0
  MessageRequester("Erreur", "Impossible d'afficher l'écran principal", 0)
  End
EndIf

; +-------------------------------------------------------------------
;- Structures et listes chainees et tableaux
; +-------------------------------------------------------------------

; +-------------------------------------------------------------------
;- Chargement des Sprites
; +-------------------------------------------------------------------
UsePNGImageDecoder()
LoadSprite(#Cpt1, "Cpt1.png")
LoadSprite(#Plateau, "Plateau.png")

; +-------------------------------------------------------------------
;- Premier Tirage de Lettres
; +-------------------------------------------------------------------
Timer()
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

; +-------------------------------------------------------------------
;- Programme principal
; +-------------------------------------------------------------------

CreateSprite(#Sprite, 40, 19)

Repeat
  
  ; +++++++++++++++++++++++++++++++++++++++
  
  Select WaitWindowEvent()
      
    Case #WM_KEYDOWN
      
      key.b = EventwParam()
      
      If key = 27 : End : EndIf
      
    Case #WM_TIMER
      Select EventwParam() ; Recupere le N° du Timer
        Case 1 ; Timer N°1
          ValCpt + 1
        
          DisplaySprite(#Cpt1, #CptX, #CptY)
          StartDrawing(ScreenOutput())
            DrawingFont(UseFont(#TxtCpt))
            DrawingMode(1)
            FrontColor(Ro, Ve, Bl)
            Locate(#CptX + 20, #CptY + 12)
            DrawText(Str(ValCpt))
          StopDrawing()
          
          FlipBuffers(0)
          
        Case 2 ; Timer N°2
          KillTimer_(WindowID(0), 1) ; Destruction du Timer N°1
          KillTimer_(WindowID(0), 2) ; Destruction du Timer N°2
          AffCpt = #False : ValCpt = 0
          Timer()
      EndSelect
      
  EndSelect
  
ForEver

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


; +-------------------------------------------------------------------
;- Mise en route des Timers
; +-------------------------------------------------------------------
Procedure Timer()
  Timer1 = SetTimer_(WindowID(0), 1, 1000, 0)
  Timer2 = SetTimer_(WindowID(0), 2, 21000, 0)
EndProcedure
exactement le problème cité ci dessus, le flibuffers qui ralentit le programme, et comme il est dans la boucle de lecture des évènement, on les lit au ralentit

Publié : jeu. 16/déc./2004 0:00
par hardy
essaie ça.
mieux vaut ne pas attacher un timer à une fenêtre : ça crée des décalages selon l'"occupation" de celle-ci.
Et crée deux procédures distinctes pour les deux timers.
De plus, pour changement immédiat et pas d'interruption d'affichage, il faut mettre les displaysprites dans la boucle de la fenêtre et dans la procédure

Code : Tout sélectionner

;+-------------------------------------------------------------------
;PURE ARNAQUE
;par Torp
;Pure Basic 3.92
;+-------------------------------------------------------------------
;OpenConsole()
;+-------------------------------------------------------------------
;-Declaration des constantes
;+-------------------------------------------------------------------
#Plateau=1
#Cpt1=32:#CptX=7:#CptY=384
#Sprite=2:#TxtCpt=0
;+-------------------------------------------------------------------
;-Declarations des Variables et affectations des valeurs
;+-------------------------------------------------------------------
Declare Timer()
Declare Sablier()      
Global AffCpt.b,Ro.w,Ve.w,Bl.w,ValCpt.b
AffCpt=#False
PosJoueur2=0:Ro=255:Ve=255:Bl=0
Installation$="d:\téléchargements\timer\"
LoadFont(#TxtCpt,"arial",16):UseFont(#TxtCpt)

;+-------------------------------------------------------------------
;-Initialisation de ecran du jeu
;+-------------------------------------------------------------------
If InitMouse()=0 Or InitSprite()=0 Or InitKeyboard()=0 Or InitSound()=0
  MessageRequester("Erreur","Impossible d'initialiser DirectX",0)
  End
EndIf

If OpenWindow(0,0,0,800,600,#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered|#PB_Window_TitleBar,"Le jarnac")=0
  MessageRequester("Erreur","Impossible d'afficher l'écran principal",0)
  End
EndIf

If OpenWindowedScreen(WindowID(),0,0,800,600,0,0,0)=0
  MessageRequester("Erreur","Impossible d'afficher l'écran principal",0)
  End
EndIf

;+-------------------------------------------------------------------
;-Structures et listes chainees et tableaux
;+-------------------------------------------------------------------

;+-------------------------------------------------------------------
;-Chargement des Sprites
;+-------------------------------------------------------------------
UsePNGImageDecoder() 
LoadSprite(#Cpt1,Installation$+"Cpt1.png")
LoadSprite(#Plateau,Installation$+"Plateau.png")

;+-------------------------------------------------------------------
;-Premier Tirage de Lettres
;+-------------------------------------------------------------------
  Timer()
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

;+-------------------------------------------------------------------
;-Programme principal
;+-------------------------------------------------------------------
          Repeat

            DisplaySprite(#Plateau,0,0)
            DisplaySprite(#Cpt1,#CptX,#CptY)
            CreateSprite(#Sprite, 40, 19)
            StartDrawing(SpriteOutput(#Sprite))
            DrawingFont(UseFont(#TxtCpt))
            DrawingMode(1)
            FrontColor(Ro,Ve,Bl)
            DrawText(Str(ValCpt))
            StopDrawing()
            DisplayTransparentSprite(#Sprite,#CptX+25+PosJoueur2,#CptY+12)
                      
            ;++++++Affichage des compteurs
            
            
            
            ;+++++++++++++++++++++++++++++++++++++++
            
            Select WaitWindowEvent()

              Case #WM_KEYDOWN 
                          
                key.b = EventwParam()
      
                If key = 27:End:EndIf

            EndSelect
            
            FlipBuffers(0)
            
          ForEver

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


;+-------------------------------------------------------------------
;-Mise en route des Timers
;+-------------------------------------------------------------------
Procedure Timer()
Timer1=SetTimer_(0,0, 1000, @Sablier())
;Timer2=SetTimer_(WindowID(0), 2, 21000, @Sablier())
EndProcedure

;+-------------------------------------------------------------------
;-Tache a effectuer par le declenchement des Timers
;+-------------------------------------------------------------------
Procedure Sablier()
  ValCpt+1
  DisplaySprite(#Cpt1,#CptX,#CptY)
  CreateSprite(#Sprite, 40, 19)
  StartDrawing(SpriteOutput(#Sprite))
  DrawingFont(UseFont(#TxtCpt))
  DrawingMode(1)
  FrontColor(Ro,Ve,Bl)
  DrawText(Str(ValCpt))
  StopDrawing()
  DisplayTransparentSprite(#Sprite,#CptX+25+PosJoueur2,#CptY+12)
EndProcedure

Publié : jeu. 16/déc./2004 0:01
par Le Soldat Inconnu
une autre solution qui marche également

Code : Tout sélectionner

; +-------------------------------------------------------------------
; PURE ARNAQUE
; par Torp
; Pure Basic 3.92
; +-------------------------------------------------------------------
; OpenConsole()
; +-------------------------------------------------------------------
;- Declaration des constantes
; +-------------------------------------------------------------------
#Plateau = 1
#Cpt1 = 32 : #CptX = 7 : #CptY = 384
#Sprite = 2 : #TxtCpt = 0
; +-------------------------------------------------------------------
;- Declarations des Variables et affectations des valeurs
; +-------------------------------------------------------------------
Declare Timer()
Declare Sablier(hwnd.l, uMsg.l, idEvent.l, dwTime.l)
Global AffCpt.b, Ro.w, Ve.w, Bl.w, ValCpt.b
AffCpt = #False
PosJoueur2 = 0 : Ro = 255 : Ve = 255 : Bl = 0
Installation$ = "C:\Temp\"
LoadFont(#TxtCpt, "arial", 16) : UseFont(#TxtCpt)

; +-------------------------------------------------------------------
;- Initialisation de ecran du jeu
; +-------------------------------------------------------------------
If InitMouse() = 0 Or InitSprite() = 0 Or InitKeyboard() = 0 Or InitSound() = 0
  MessageRequester("Erreur", "Impossible d'initialiser DirectX", 0)
  End
EndIf

If OpenWindow(0, 0, 0, 800, 600, #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered | #PB_Window_TitleBar, "Le jarnac") = 0
  MessageRequester("Erreur", "Impossible d'afficher l'écran principal", 0)
  End
EndIf

If OpenWindowedScreen(WindowID(), 0, 0, 800, 600, 0, 0, 0) = 0
  MessageRequester("Erreur", "Impossible d'afficher l'écran principal", 0)
  End
EndIf

; +-------------------------------------------------------------------
;- Structures et listes chainees et tableaux
; +-------------------------------------------------------------------

; +-------------------------------------------------------------------
;- Chargement des Sprites
; +-------------------------------------------------------------------
UsePNGImageDecoder()
LoadSprite(#Cpt1, Installation$ + "Cpt1.png")
LoadSprite(#Plateau, Installation$ + "Plateau.png")

; +-------------------------------------------------------------------
;- Premier Tirage de Lettres
; +-------------------------------------------------------------------
Timer()
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

; +-------------------------------------------------------------------
;- Programme principal
; +-------------------------------------------------------------------
Repeat
  
  DisplaySprite(#Plateau, 0, 0)
  
  
  ; ++++++Affichage des compteurs
  
  If AffCpt = #True
    
    DisplaySprite(#Cpt1, #CptX, #CptY)
    CreateSprite(#Sprite, 40, 19)
    StartDrawing(SpriteOutput(#Sprite))
      DrawingFont(UseFont(#TxtCpt))
      DrawingMode(1)
      FrontColor(Ro, Ve, Bl)
      DrawText(Str(ValCpt))
    StopDrawing()
    DisplayTransparentSprite(#Sprite, #CptX + 25 + PosJoueur2, #CptY + 12)
    
  EndIf
  
  ; +++++++++++++++++++++++++++++++++++++++
  
  Repeat
    Event = WindowEvent()
    Select Event
      Case #WM_KEYDOWN
        
        key.b = EventwParam()
        
        If key = 27 : End : EndIf
        
    EndSelect
  Until Event = 0
  
  FlipBuffers(0)
  
ForEver

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


; +-------------------------------------------------------------------
;- Mise en route des Timers
; +-------------------------------------------------------------------
Procedure Timer()
  Timer1 = SetTimer_(WindowID(0), 1, 1000, @Sablier())
  Timer2 = SetTimer_(WindowID(0), 2, 21000, @Sablier())
EndProcedure

; +-------------------------------------------------------------------
;- Tache a effectuer par le declenchement des Timers
; +-------------------------------------------------------------------
Procedure Sablier(hWnd, uMsg, idEvent, dwTime)
  Select uMsg
    Case #WM_TIMER
      Select idEvent ; Recupere le N° du Timer
        Case 1 ; Timer N°1
          ValCpt + 1
          AffCpt = #True
        Case 2 ; Timer N°2
          KillTimer_(WindowID(0), 1) ; Destruction du Timer N°1
          KillTimer_(WindowID(0), 2) ; Destruction du Timer N°2
          AffCpt = #False : ValCpt = 0
          Timer()
      EndSelect
  EndSelect
EndProcedure

par contre, évite de metre un sprite qui est crée à chaque tour de la boucle principale, voir code du message précédent

Publié : jeu. 16/déc./2004 0:03
par Chris
C'est bien pour ça que les timers sont gérés par une procédure, il n'y a pas d'évenements fenêtre à récupérer puisque le WindowedScreen() couvre la totalité de la fenêtre, donc, il est inutile de faire une boucle d'évènement.

Publié : jeu. 16/déc./2004 0:08
par Le Soldat Inconnu
oui, enfin, on peut gérer le bouton fermer de windows par la boucle d'évènement, c'est plus pratique que de faire echap