[games] Events et actions

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

[games] Events et actions

Message par blendman »

salut

J'essaie de tester un système d'event et d'action façon Game maker (pour ceux qui connaissent).

Voici le code que j'ai commencé pour étudier ça (je veux un code très simple) :

Code : Tout sélectionner

;{ enumeration

#window_main  = 0

; Fixé par le créateur du jeu, dans PGC
#canvas       = 0
#WindowWidth  = 640
#WindowHeight = 480
#FPSMax         = 40 ; le FPS souhaité (approximation à environ -7)

Enumeration EventObject
  
  ; les events de chaque objets
  
  #EventCreate
  #EventStep
  #EventDraw
  #EventDestroy
  
EndEnumeration

Enumeration EventGame
  
  ; les events généraux du jeu
  
  #EvtGame_GameStart
  #EvtGame_GameEnd
  #EvtGame_RoomStart
  #EvtGame_RoomEnd
  #EvtGame_Step
  
EndEnumeration

;}

;{ structure

Structure ST_object
  
  Name$
  
  ; event
  Event.i
  EventCreate.a
  EventDestroy.a
  
  ; pour certains event, pour vérifier si on les a ajouté
  EventDraw.a
  
  ; autre paramètres
  Life.w  
  SpriteId.i
  X.w
  Y.w
  
EndStructure
Global NewList Object.ST_object()

;}

;{ variable

Global ObjectId.i, Exit.a, EventGame.a, Room.a, Color.i

;}

;{ Declare
Declare RoomGotoNext()
Declare GameEnd()
;}

;{ procedures

;{ Event Actions pour objets

Procedure EO_Create(List Obj.ST_object())
  
  If Obj()\EventCreate = 0
    Debug  "Create " + Obj()\Name$
    Obj()\EventCreate = 1
    Obj()\Event = #EventStep
  EndIf 
  
EndProcedure

Procedure Instance_Create(List Obj.ST_object())
  
  AddElement(Obj())
  
  With Obj()
    
    \Name$  = "Obj_" + ObjectId
    ObjectId + 1
    \Life   = 20 + Random(20)    
    \X      = Random(#WindowWidth)
    \Y      = Random(#WindowHeight)
    \Event  = #EventCreate
    
    \EventDraw = 1 ; on a ajouté un code dans l'event draw
    
    ; le sprite
    \SpriteId = CreateSprite(#PB_Any, 64, 64)
    
    If \SpriteId
      
      If StartDrawing(SpriteOutput(\SpriteId))
        Box(0, 0, 64, 64, RGB(Random(255), Random(255), Random(255)))
        StopDrawing()
      EndIf
      
    EndIf
    
  EndWith
  
EndProcedure

Procedure EO_Step(List Obj.ST_object())
  
  ;{ begin step
  
  ;}
  
  ;{ step
  
  ; un code par exemple
  If Obj()\X > - 64
    Obj()\X - 1
  Else
    Obj()\x = #WindowWidth
  EndIf
  
  Obj()\Life - 1
  
  If Obj()\life <= 0
    Obj()\Event = #EventDestroy; <-- action destroy
  EndIf
  ;}
  
  ;{ End step

    ;}
    
EndProcedure

Procedure Instance_number(List Obj.ST_object())
  
  ProcedureReturn ListSize(obj())
 
EndProcedure

Procedure EO_Draw(List Obj.ST_object())

  DisplaySprite(Obj()\SpriteId, Obj()\x, Obj()\y)  

EndProcedure

Procedure EO_Destroy(List Obj.ST_object())
  
  If Obj()\EventDestroy = 0
    
    Obj()\EventDestroy = 1
    Debug "Destroy"
    DeleteElement(Obj(),1)    
  EndIf

  ; un code par exemple, sur l'event Destroy
  
  ; on crée une instance au hasard quand on détruit l'objet
  Hasard = Random(1)
  If hasard = 1
    Instance_Create(Obj())
  EndIf
  
  ; exemple d'ajout d'un code
  If Instance_number(Obj()) <=0 
    Debug "plus d'instance de l'objet"
    RoomGotoNext()
  EndIf
  
EndProcedure

;}

;{ Event Generaux

Procedure RoomGotoNext() 
  
  EventGame = #EvtGame_RoomEnd
  Debug "RoomGotoNext"
  
EndProcedure

Procedure GameStart()
  
  Debug "GameStart"
  
  ; On lance les actions issues du GameStart
  
  EventGame = #EvtGame_RoomStart
  
EndProcedure

Procedure GameEnd()
  
  EventGame = #EvtGame_GameEnd
  
EndProcedure

Procedure GameEvents()
  
  Select EventGame
      
     Case #EvtGame_Step
      ;{ event Step
      
      ; le step de chaque objet
          
      ForEach Object()
        
        Select Object()\event
                   
          Case #EventCreate
            EO_Create(Object())
            
          Case #EventStep
            EO_Step(Object())  
            ;EO_Draw(object())  
            
          Case #EventDestroy
            EO_Destroy(Object())
            
        EndSelect
        
      Next
        
        
      ;}     
      
    Case #EvtGame_RoomStart
      ;{ event Roomstart
      ; on fait les actions de l'event Roomstart
      Debug "Room Start: " + Room
      
      ;{ Par exemple on crée 3 objets pour commencer (avec soit un code room soit un objet ayant lui-même ce code)
      
      For i = 0 To 2
        Instance_Create(Object())
      Next i
      
      ;}
      
      ; puis on passe à l'évent Step      
      EventGame = #EvtGame_Step
      ;}
      
    Case #EvtGame_RoomEnd
      ;{ event RoomEnd
      Debug "Room End : " + Room
      If Room > 3 ; le nombre de room qu'on aura créée
        Debug "Room : " + Room
        GameEnd()
      Else
        Room + 1
        Color = RGB(50 + Random(50),50 +  Random(50),50 + Random(50))
        EventGame = #EvtGame_RoomStart
      EndIf
      ;}
      
    Case #EvtGame_GameEnd
      ;{ event GameEnd
      
      ; actions pour la fin du jeu      
      Debug "GameEnd"
      
      ; sortie de boucles
      Exit = 1
      ;}
            
  EndSelect
  
EndProcedure

Procedure GameDraw()
  
  ; event draw general
  
  ClearScreen(0)
  
  If StartDrawing(ScreenOutput())
    
    ; un fond
    Box(0, 0, #WindowWidth, #WindowHeight, Color)
    DrawText(200,0, "Room "+Str(Room) + " - Nb Objets : " + Str(ListSize(Object())))
    StopDrawing()
    
  EndIf    
  
  ForEach Object()
    If Object()\EventDraw = 0
      DisplaySprite(Object()\SpriteId, Object()\x, Object()\y)  
    Else
      EO_Draw(object())  
    EndIf    
  Next
  
  FlipBuffers()
  
  
EndProcedure


Procedure FPS()
  Shared s, fps
  
  ss  = Second(Date())
  fps + 1
  
  If s <> ss
    
    SetWindowTitle(0,"FPS: "+Str(FPS))
    s   = ss
    fps = 0
    
  EndIf
  
EndProcedure

;}

;}

;{ window & Loop

If InitSprite() : EndIf

If OpenWindow(#window_main, 0, 0, #WindowWidth, #WindowHeight, "Game Events", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)
  
  If OpenWindowedScreen(WindowID(#window_main), 0, 0, #WindowWidth, #WindowHeight, 1, 0, 0)
        
    ; Init the game
    Room = 1
    Color = RGB(Random(50), Random(50), Random(50))
    ; on lance la première room
    
    GameStart()
    
    
    Repeat
      
      Event = WindowEvent()
      
      If ElapsedMilliseconds() > CheckTime + 1000/#FPSMax
        CheckTime = ElapsedMilliseconds()
                 
        GameEvents()
        GameDraw()
        
        FPS()
                
      Else
        
        Delay(1)
        
      EndIf
      
      ; autre : menu, par exemple ?
      
            
    Until event = #PB_Event_CloseWindow Or Exit = 1
  EndIf
  
EndIf
;}

J'aimerai avoir votre avis sur ce système.
Pensez-vous que ce soit une bonne technique (ça doit permettre d'être "générique", c'est à dire s'adapter au maximum de situation) ?

Vous pouvez aussi m'indiquer votre FPS, chez moi, ça tourne à 32/33.
Avatar de l’utilisateur
falsam
Messages : 7317
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: [games] Events et actions

Message par falsam »

blendman a écrit :Vous pouvez aussi m'indiquer votre FPS, chez moi, ça tourne à 32/33.
Idem 32/33 sans débug.
Intel Core2 Duo CPU 8600 2.40 Ghz, Nvidia Geforce 9600 M 512 mo. Windows 7
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
flaith
Messages : 1487
Inscription : jeu. 07/avr./2005 1:06
Localisation : Rennes
Contact :

Re: [games] Events et actions

Message par flaith »

Idem, 32 (avec ou sans debug) sur un LENOVO :wink:
Avatar de l’utilisateur
Ar-S
Messages : 9539
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: [games] Events et actions

Message par Ar-S »

32 fps avec ou sans debug :wink:
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
Good07
Messages : 308
Inscription : ven. 23/avr./2004 18:08
Localisation : Hérault 34190 Laroque

Re: [games] Events et actions

Message par Good07 »

38 fps sur Mac.
Processeur 2,8 Ghz intel core i7
Mémoire 8GB 1067 MHz DDR3
Mesa
Messages : 1126
Inscription : mer. 14/sept./2011 16:59

Re: [games] Events et actions

Message par Mesa »

32, 33 fps avec un vieux P4 monocore.

J'ai fait un petit truc à l'arrache, un patron de jeu.
Je ne sais pas s'il fonctionne dans l'état mais c'est l'idée qu'il faut prendre.

Le but de ce patron est d'avoir une boucle la plus courte possible afin d'avoir une vitesse et une réponse maximale.

Dans la boucle, on se contente de scanner une douzaine de touches du clavier et la souris. On ne peut pas faire plus rapide. On peut ajouter un IA intelligence artificielle. Et dans un second temps on execute un code en fonction de la touche.

Code : Tout sélectionner

; enumeration
; structure
; variable globale

; Declare procedure
; InitGame()
; InitLevel(n)
; InitRoom(m)
; EndRoom()
; EndLevel()
; EndGame()
; NextLife(v)
; Menu()
;   Menu_NewGame()
;  ...
; IA()
; ControleFPS()
; DisplayFPS()
; ...

;Declare procedure evenement
; OnKeyboard()
; OnMouse()
; ...
;}



; window & Loop

If InitSprite() : EndIf

If OpenWindow(#window_main, 0, 0, #WindowWidth, #WindowHeight, "Game Events", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)
  
  If OpenWindowedScreen(WindowID(#window_main), 0, 0, #WindowWidth, #WindowHeight, 1, 0, 0)
    
    InitGame()
    
    
    While lifes < 5
      
      For Level=1 To 12
        InitLevel(level)
        
        For room =1 To 8
          InitRoom(room)
          
          Repeat
            ; Le but ici, avoir la boucle qui gère le clavier et la souris et l'ia, la plus rapide possible
            ; pour garantir la fluidié du jeu en toutes circonstances
            Event = WindowEvent()
            
            ControleFPS()
            If Event						
              OnKeyboard() ; dans onkeyboard() =>par ex.  if 'esc' then pausegame() and displaymenu() if 'space' then jump(), etc.
              OnMouse()
              IA()
              
              DisplayFPS()
              
            Else
              
              Delay(1)
              
            EndIf
            
          Until alive=#False
          nextlife()
          
        Next room
        endroom()
        
      Next level
      endlevel()
      
    Wend
    endgame()
    
  EndIf
EndIf

; Les procedures ici

; Les procédures qui impliquent un événement commence par "On" pour les repérer plus facilement.



Voilà, je ferais un truc qui ressemble à ça.

Mesa.
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Re: [games] Events et actions

Message par Backup »

Mesa a écrit :
Dans la boucle, on se contente de scanner une douzaine de touches du clavier et la souris. On ne peut pas faire plus rapide.
heu.. t'es sur ? .....


non parceque si tu met ta procedure de test claviers , dans un Thread , ben forcement tu va gagner en rapidité ... enfin j'dit ça :mrgreen:
ps: meme ton P4 est multithreadé (4 de memoire)
stombretrooper
Messages : 117
Inscription : dim. 21/déc./2008 18:39

Re: [games] Events et actions

Message par stombretrooper »

Je suis pas sur que blendman cherche à jouer avec les threads, sa risque de compliquer beaucoup (si tu veux un truc très rapide). Mais c'est sûr, que si le nombre d'instance à gérer dans sa boucle est très élevé, l'utilisation d'un thread accéléré beaucoup la chose

@Blendman :
Sur mon core i7, Window 8 ; 32 FPS MAIS, si tu change un peu la technique, je tourne autour des 40 FPS (comme la limite fixé par ta constante) ;

Ta boucle :

Code : Tout sélectionner

    Repeat
      
      Event = WindowEvent()
      If ElapsedMilliseconds() > CheckTime + 1000/#FPSMax
        CheckTime = ElapsedMilliseconds()
                 
        GameEvents()
        GameDraw()
        
        FPS()
                
      Else
        
        Delay(1)
        
      EndIf
    Until event = #PB_Event_CloseWindow Or Exit = 1
Déjà, 1000/#FPSMax j'en ai fait une constante : #FPSLimit
Et plutôt qu'attendre 1 millisec tant qu'on a pas atteint la limite de FPS, je regarde à la fin de la boucle combien de millisec, on doit attendre pour garder le bon FPS, et je mes directement le Delay sur cette valeur :

Mon code est le suivant (pour la même boucle) :

Code : Tout sélectionner

    Repeat
      
      Event = WindowEvent()
      CheckTime = ElapsedMilliseconds()
        
      GameEvents()
      GameDraw()
      FPS()
        
      CheckTime = ElapsedMilliseconds() - CheckTime
      If #FPSLimit - CheckTime > 0
         Delay(#FPSLimit - CheckTime)
      EndIf
    Until event = #PB_Event_CloseWindow Or Exit = 1
Je sais pas si c'est plus "propre", mais en tout cas, le FPS correspond beaucoup mieux à ce que tu fixe au départ (sur mon i7 je tiens le FPS, jusqu'à 60, où la je penses, que c'est la vitesse de refresh de l'écran qui limite le FPS :D ).

PS : je te confirme, si je désactive la synchronisation, que j'augmente la durée de vie de tes instances, et que je fixe le FPS à 250, je tourne autour d'un FPS à 180 (ton code avec ma boucle).
http://www.purebasicstreet.com/ - Site dédié à purebasic.
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: [games] Events et actions

Message par blendman »

Merci pour vos réponses.

En fait, l'idée c'est d'obtenir un code "générique", qui permette de réaliser n'importe quel jeu (un game maker, quoi ^^).
Je pourrais toujours ajouter une option "thread" dans les options d'optimisation du jeu, pour les gros jeux on va dire. J'ajouterai ça lorsque j'aurai codé les bases du système d'event/action.

@Strombre : merci pour ton code, je vais l'utiliser sir ça permet d'être plus proche de ce qu'on a fixé au départ ;).
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: [games] Events et actions

Message par blendman »

@Strombre : je viens de retester ton code, mais sur mon ordinateur, ce n'est pas fluide du tout le déplacement, ça saccade (ça accélère, ça ralentit, etc..le fps passe de 40 à 48 puis 42, etc.. ça n'arrête pas de changer ^^), alors qu'avec mon code, ça ne saccade pas c'est toujours à 32fps environ.

Tu penses qu'il y a moyen de modifier ça ?
Avatar de l’utilisateur
Jenova
Messages : 96
Inscription : mar. 09/mars/2004 10:27

Re: [games] Events et actions

Message par Jenova »

Salut all et Joyeux Noël.
Le problème que tu rencontre je l'ai eu il y a bien longtemps.
Le seul remède que j'ai trouvé c'était de remplacer
CheckTime = ElapsedMilliseconds()

par
CheckTime +1000/#FPSMax

Avec ça les jeux 2D chez moi passent du stade 30 fps qui saccadent aux stade turboGTI double injection (avec attente de synchro V) et il en redemande.
Le truc que j'ai aussi remarqué (et qui est bizarre d'ailleurs) c'est que le FPSMax que l'on demande (dans le cas ou on attend la Vsync) ne doit pas dépasser les 56 voir 57 FPS et ceux, malgré que le framerate de ma carte est officiellement à 60Hz.
Par contre avec cette méthode il faut vérifier un point, le cas ou le jeu se met à ramer pour X ou Y raisons et ou le ElapsedMilliseconds() dépasse de loin le CheckTime.
Imagine que dans ton jeu un million de boulettes se baladent et font ramer le jeu. Le CheckTime avance de +1000/#FPSMax par frame mais l'heure tourne et ElapsedMilliseconds() prend un sacré écart.
Quand ton jeu fait disparaitre toutes tes boulettes et qu'il reprend une allure normale il va se mettre à booster pour rattraper l'écart.
C'est pourquoi il te faut vérifier que l'écart entre CheckTime et ElapsedMilliseconds() n'est pas plus grand que deux frames et dans le cas contraire faire un ponctuel CheckTime = ElapsedMilliseconds().
Ce CheckTime = ElapsedMilliseconds() ne surviendra que dans des cas extrêmes et passera en transparence.
@+ les zamis
Répondre