Organiser un code pour le jeu

Programmation avancée de jeux en PureBasic
Avatar de l’utilisateur
venom
Messages : 3072
Inscription : jeu. 29/juil./2004 16:33
Localisation : Klyntar
Contact :

Organiser un code pour le jeu

Message par venom »

Bonjour,

Voilà je me suis amusé a faire quelques essais de jeu en purebasic. Jusque la rien de très spécial, mais j'aurais voulu savoir comment on organise un code quand il y a par exemple :

- un menu avant de lancer le jeu
- plusieurs niveaux
- un tableau des scores quand on perd
- un générique de fin
etc...

Donc ma réel question est comment boucler tout ça ?

Est ce que l'on programme chaque étape dans différents fichiers (chacun utilise son screen, chacun utilise le clavier etc..) qu'on inclus ensuite via des procédures ? (je ne pense pas) :wink:
Ou autre façon ?

Je ne demande pas un code complet mais savoir comment un tel projet peut se goupiller.


Pour exemple, voici un code qui affiche un menu avec pour option :
Démarrer, Options, Quitter.
Il y inclue la fonction clavier qui permet de choisir son menu et via la touche entrée de sélectionner le menu désiré:

Code : Tout sélectionner

;{ Initialisations
; /////////////////////////////////////////////////////////////////////////////
If InitSprite() = 0
 MessageRequester("Erreur", "Le système de Sprite ne peut être initialisé", 0)
  End
EndIf

If InitKeyboard() = 0
 MessageRequester("Erreur", "Le clavier ne peut être initialisé", 0)
  End
EndIf 

If InitSound() = 0
 MessageRequester("Erreur", "L'environnement sonorene peut être initialisé", 0)
  End
EndIf 
;}

;{ Enumerations
; /////////////////////////////////////////////////////////////////////////////
Enumeration
  #Police_0
  #Sprite_Menu
  #Sprite_Menu_Demarrer
  #Sprite_Menu_Options
  #Sprite_Menu_Quitter
  #Window_0
EndEnumeration
;}

;{ Police de caractere
; /////////////////////////////////////////////////////////////////////////////
LoadFont(#Police_0, "Comic sans ms", 70, #PB_Font_Bold)
;}

;{ Ouverture de la fenetre
; /////////////////////////////////////////////////////////////////////////////
If OpenWindow(#Window_0, 0, 0, 1024, 768, "", #PB_Window_ScreenCentered)
 If OpenWindowedScreen(WindowID(#Window_0), 0, 0, 1024, 768)
   
;{ création du menu
; /////////////////////////////////////////////////////////////////////////////
  If CreateSprite(#Sprite_Menu, 1024, 768, #PB_Sprite_AlphaBlending)
    
   If CreateSprite(#Sprite_Menu_Demarrer, 300, 50)
    If StartDrawing(SpriteOutput(#Sprite_Menu)) 
     DrawingFont(FontID(#Police_0))
     DrawText(265, 100, "DEMARRER", RGB(255, 255, 255), RGB(0, 0, 0))
		 StopDrawing()
	  EndIf
	 EndIf 
	 
	 If CreateSprite(#Sprite_Menu_Options, 300, 50)
    If StartDrawing(SpriteOutput(#Sprite_Menu)) 
     DrawingFont(FontID(#Police_0))
     DrawText(310, 300, "OPTIONS", RGB(255, 255, 255), RGB(0, 0, 0))
		 StopDrawing()
	  EndIf
	EndIf 
	
	 If CreateSprite(#Sprite_Menu_Quitter, 300, 50)
    If StartDrawing(SpriteOutput(#Sprite_Menu)) 
     DrawingFont(FontID(#Police_0))
     DrawText(315, 500, "QUITTER", RGB(255, 255, 255), RGB(0, 0, 0))
		 StopDrawing()
	  EndIf
	 EndIf 
	 
	 sprite = #Sprite_Menu_Demarrer
	 If StartDrawing(SpriteOutput(#Sprite_Menu)) 
    DrawingFont(FontID(#Police_0))
    DrawText(265, 100, "DEMARRER", RGB(255, 0, 0), RGB(0, 0, 0))
		StopDrawing()
	 EndIf
   
	EndIf 
;}

 EndIf
EndIf
;}

;{ Event_Loop
; /////////////////////////////////////////////////////////////////////////////
Repeat 
 Repeat
   EventID = WindowEvent()
 Until EventID = 0
 FlipBuffers() 
 ClearScreen(RGB(0, 0, 0))
 ExamineKeyboard() 
 
 
;{ Gestion du menu avec les flèches
; /////////////////////////////////////////////////////////////////////////////
   If KeyboardReleased(#PB_Key_Up)
     If sprite = #Sprite_Menu_Demarrer
     sprite = #Sprite_Menu_Quitter
     If StartDrawing(SpriteOutput(#Sprite_Menu)) 
      DrawingFont(FontID(#Police_0))
      DrawText(265, 100, "DEMARRER", RGB(255, 255, 255), RGB(0, 0, 0))
		  StopDrawing()
		 EndIf
     If StartDrawing(SpriteOutput(#Sprite_Menu)) 
      DrawingFont(FontID(#Police_0))
      DrawText(315, 500, "QUITTER", RGB(255, 0, 0), RGB(0, 0, 0))
      StopDrawing()
	   EndIf

		ElseIf sprite = #Sprite_Menu_Options
		 sprite = #Sprite_Menu_Demarrer
		 If StartDrawing(SpriteOutput(#Sprite_Menu)) 
      DrawingFont(FontID(#Police_0))
      DrawText(310, 300, "OPTIONS", RGB(255, 255, 255), RGB(0, 0, 0))
		  StopDrawing()
		 EndIf
		 If StartDrawing(SpriteOutput(#Sprite_Menu)) 
      DrawingFont(FontID(#Police_0))
      DrawText(265, 100, "DEMARRER", RGB(255, 0, 0), RGB(0, 0, 0))
		  StopDrawing()
		 EndIf
	
    ElseIf sprite = #Sprite_Menu_Quitter
     sprite = #Sprite_Menu_Options
     If StartDrawing(SpriteOutput(#Sprite_Menu)) 
      DrawingFont(FontID(#Police_0))
      DrawText(315, 500, "QUITTER", RGB(255, 255, 255), RGB(0, 0, 0))
		  StopDrawing()
		 EndIf
     If StartDrawing(SpriteOutput(#Sprite_Menu)) 
      DrawingFont(FontID(#Police_0))
      DrawText(310, 300, "OPTIONS", RGB(255, 0, 0), RGB(0, 0, 0))
		  StopDrawing()
	   EndIf
	  EndIf
	 
   EndIf 

   If KeyboardReleased(#PB_Key_Down)
     If sprite = #Sprite_Menu_Demarrer
     sprite = #Sprite_Menu_Options
     If StartDrawing(SpriteOutput(#Sprite_Menu)) 
      DrawingFont(FontID(#Police_0))
      DrawText(265, 100, "DEMARRER", RGB(255, 255, 255), RGB(0, 0, 0))
		  StopDrawing()
		 EndIf
     If StartDrawing(SpriteOutput(#Sprite_Menu)) 
      DrawingFont(FontID(#Police_0))
      DrawText(310, 300, "OPTIONS", RGB(255, 0, 0), RGB(0, 0, 0))
		  StopDrawing()
	   EndIf
		 
		ElseIf sprite = #Sprite_Menu_Options
		 sprite = #Sprite_Menu_Quitter
		 If StartDrawing(SpriteOutput(#Sprite_Menu)) 
      DrawingFont(FontID(#Police_0))
      DrawText(310, 300, "OPTIONS", RGB(255, 255, 255), RGB(0, 0, 0))
		  StopDrawing()
		 EndIf
		 If StartDrawing(SpriteOutput(#Sprite_Menu)) 
      DrawingFont(FontID(#Police_0))
      DrawText(315, 500, "QUITTER", RGB(255, 0, 0), RGB(0, 0, 0))
      StopDrawing()
	   EndIf

    ElseIf sprite = #Sprite_Menu_Quitter
     sprite = #Sprite_Menu_Demarrer
     If StartDrawing(SpriteOutput(#Sprite_Menu)) 
      DrawingFont(FontID(#Police_0))
      DrawText(315, 500, "QUITTER", RGB(255, 255, 255), RGB(0, 0, 0))
		  StopDrawing()
		 EndIf
     If StartDrawing(SpriteOutput(#Sprite_Menu)) 
      DrawingFont(FontID(#Police_0))
      DrawText(265, 100, "DEMARRER", RGB(255, 0, 0), RGB(0, 0, 0))
		  StopDrawing()
	   EndIf
	  EndIf
	 
   EndIf 
;}
   

;{ quand ont fait ENTREE sur un menu
; /////////////////////////////////////////////////////////////////////////////
   If KeyboardReleased(#PB_Key_Return)
     
    If sprite = #Sprite_Menu_Demarrer ; quand ont fait entree sur le menu demarrer
     Debug"demarrer"
    EndIf 
    
    If sprite = #Sprite_Menu_Options ; quand ont fait entree sur le menu options
     Debug"options"
    EndIf 
   
    If sprite = #Sprite_Menu_Quitter ; quand ont fait entree sur le menu quitter
     Debug"quitter"
     End
    EndIf 
   
   EndIf 
;}
   
;- Affichage du menu a l'écran
; /////////////////////////////////////////////////////////////////////////////
   DisplaySprite(#Sprite_Menu, 0, 0)

;- appuie sur la touche echap pour quitter
; /////////////////////////////////////////////////////////////////////////////
	 If KeyboardPushed(#PB_Key_Escape)
    EventID = #PB_Event_CloseWindow
  EndIf 
  
Until EventID = #PB_Event_CloseWindow
;}
Et voici le code de la Doc qui fait bouger un sprite dans une fenetre:

Code : Tout sélectionner

If InitSprite() = 0
    MessageRequester("Erreur", "Impossible d'ouvrir l'écran & l'environnement nécessaire aux sprites !", 0)
    End
  EndIf
  
  If OpenWindow(0, 0, 0, 220, 160, "Un écran dans une fenêtre...", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    ButtonGadget(0, 170, 135, 45, 20, "Quitter")

    If OpenWindowedScreen(WindowID(0), 0, 0, 160, 160)
      CreateSprite(0, 20, 20)
      If StartDrawing(SpriteOutput(0))
        Box(0, 0, 20, 20, RGB(255, 0, 155))
        Box(5, 5, 10, 10, RGB(155, 0, 255))
        StopDrawing()
      EndIf
    Else
      MessageRequester("Erreur", "Impossible d'ouvrir un écran dans la fenêtre!", 0)
      End
    EndIf
  EndIf
  
  direction = 2
  Repeat
    ; Il est très important de traiter tous les événements restants dans la file d'attente à chaque tour
    ;
    Repeat
      Event = WindowEvent()
      
      Select Event 
        Case #PB_Event_Gadget
          If EventGadget() = 0
            End
          EndIf
        
        Case #PB_Event_CloseWindow
          End 
      EndSelect
    Until Event = 0
  
    FlipBuffers() 
    ClearScreen(RGB(0, 0, 0))
    DisplaySprite(0, x, x)
    x + direction
    If x > 140 : direction = -2 : EndIf
    If x < 0   : direction =  2 : EndIf
    Delay(1)
  ForEver
imaginons que le 2eme code est mon niveau 1. Pourriez vous montrer votre façon de résoudre ce probleme, ou quel est la meilleur façon de faire ?

Je pense que cette question peut paraitre bête aux yeux de certain, mais je ne doit pas être le seul ma m'avoir déjà posé cette question. :wink:
j'espere :D

Merci de votre futur réponse.







@++
Windows 10 x64, PureBasic 5.73 x86 & x64
GPU : radeon HD6370M, CPU : p6200 2.13Ghz
Lemaquis
Messages : 271
Inscription : mer. 25/déc./2013 7:34
Localisation : la corse

Re: Organiser un code pour le jeu

Message par Lemaquis »

Merci venom pour le code du menu , je galere pour la 2d
LeMaquis
Avatar de l’utilisateur
Micoute
Messages : 2522
Inscription : dim. 02/oct./2011 16:17
Localisation : 35520 La Mézière

Re: Organiser un code pour le jeu

Message par Micoute »

Bonjour venom,

je ne programme de jeux, mais, c'est juste une question de bon sens, dans ton programme on trouve :
If sprite = #Sprite_Menu_Demarrer ; quand ont fait entree sur le menu demarrer
Debug"demarrer"
EndIf
ça veut dire qu'il faut que tu crée une procédure demarrer() et au lieu d'afficher un debug, tu lances ta procédure et tu fais pareil pour "options" et "quitter", ce n'est pas plus compliqué
Microsoft Windows 10 Famille 64 bits : Carte mère : ASRock 970 Extreme3 R2.0 : Carte Graphique NVIDIA GeForce RTX 3080 : Processeur AMD FX 6300 6 cœurs 12 threads 3,50 GHz PB 5.73 PB 6.00 LTS (x64)
Un homme doit être poli, mais il doit aussi être libre !
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Organiser un code pour le jeu

Message par falsam »

@Micoute : je crois que venom l'avait bien compris. C'était juste un exemple traçable par un débug :)
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%
poshu
Messages : 1138
Inscription : sam. 31/juil./2004 22:32

Re: Organiser un code pour le jeu

Message par poshu »

Si j'ai le temps la semaine prochain, je vais écrire une petite stepmachine pour te montrer comment qu'on fait.
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Organiser un code pour le jeu

Message par graph100 »

c'est dommage de revenir là dessus, mais ça :

Code : Tout sélectionner

;{ Enumerations
; /////////////////////////////////////////////////////////////////////////////
Enumeration
	#Police_0
	#Sprite_Menu
	#Sprite_Menu_Demarrer
	#Sprite_Menu_Options
	#Sprite_Menu_Quitter
	#Window_0
EndEnumeration
;}

c'est pas bien !
il faut faire une énumération pour chaque type d'objet différents:

Code : Tout sélectionner

;{ Enumerations
; /////////////////////////////////////////////////////////////////////////////
Enumeration ; police
	#Police_0
EndEnumeration

Enumeration	; sprite
	#Sprite_Menu
	#Sprite_Menu_Demarrer
	#Sprite_Menu_Options
	#Sprite_Menu_Quitter
EndEnumeration

Enumeration	; fenetres
	#Window_0
EndEnumeration
;}
Sinon, pour ta question initiale, moi j'utilise des "Modes". Ils permettent de savoir ou es-ce qu'on en est dans le programme : menu / jeu / affichage de défaite ou victoire / etc..
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Organiser un code pour le jeu

Message par graph100 »

Autre chose, je n'avais pas regardé ton code en détail, mais maintenant oui.
Je suis désolé, mais c'est n'importe quoi !

Alors quand je dis n'importe quoi :
- tu initiales des sprites que tu n'utilise jamais ! (tu n'utilises que le sprite_menu)
- tu dessines à chaque boucle sur le même sprite, alors que le but d'un sprite c'est justement de ne faire le dessin qu'une seule fois
- tu dessines plein de fois différente dans les startdrawing() / stopdrawing() différent ! C'est à BANNIR, car même si là c'est n'a pas de conséquence, il faut bien retenir qu'il est beaucoup plus long de faire plein de startdrawing() que d'en faire 1 seul et tout le dessin d'un coup.
- tu dessines dans la zone pour gérer le clavier. regarde bien mon code en dessous pour voir comment c'est plus simple et surtout plus organiser de faire.
- tu flip le buffer d'affichage loin de l'affichage, ça doit être fait juste après, car ce n'est qu'à ce moment là que le dessin est montré sur l'écran (même si c'est une boucle c'est pas bien)

bref, je te critique beaucoup, mais c'est pour ton bien :lol:

Voici une version "corrigée" : (ici encore, la correction n'engage que moi, mais je te conseil d'y jeter un bon coup d'oeil)

Code : Tout sélectionner

;{ Initialisations
; /////////////////////////////////////////////////////////////////////////////
If InitSprite() = 0
	MessageRequester("Erreur", "Le système de Sprite ne peut être initialisé", 0)
	End
EndIf

If InitKeyboard() = 0
	MessageRequester("Erreur", "Le clavier ne peut être initialisé", 0)
	End
EndIf 

If InitSound() = 0
	MessageRequester("Erreur", "L'environnement sonorene peut être initialisé", 0)
	End
EndIf 
;}

;{ Enumerations
; /////////////////////////////////////////////////////////////////////////////
Enumeration police
	#Police_0
EndEnumeration

Enumeration	sprite
	#Sprite_Menu
	#Sprite_Menu_Demarrer
	#Sprite_Menu_Options
	#Sprite_Menu_Quitter
	#Sprite_Menu_credit ; pour l'exemple
EndEnumeration

Enumeration	fenetre
	#Window_0
EndEnumeration
;}

;{ Police de caractere
; /////////////////////////////////////////////////////////////////////////////
LoadFont(#Police_0, "Comic sans ms", 70, #PB_Font_Bold)
;}

;{ Ouverture de la fenetre
; /////////////////////////////////////////////////////////////////////////////
If OpenWindow(#Window_0, 0, 0, 1024, 768, "", #PB_Window_ScreenCentered)
	If OpenWindowedScreen(WindowID(#Window_0), 0, 0, 1024, 768) = 0
		End
	EndIf
Else
	End
EndIf
;}

;{ création du menu
; /////////////////////////////////////////////////////////////////////////////

Macro Menu_DrawText(TEXT, y)
	DrawText((ScreenWidth() - TextWidth(TEXT))/2, offset_menu * y + (y-1) * TextHeight("A"), TEXT, RGB(255, 255, 255), RGB(0, 0, 0))
	
	; je crée les sprite à la taille du texte. Je ne sais pas si le faire dans le bloc start / stop drawing est une bonne idée,
	; mais on est obligé pour pouvoir utiliser TextWidth et TextHeight
	CreateSprite(y, TextWidth(TEXT), TextHeight(TEXT))
EndMacro


CreateSprite(#Sprite_Menu, 1024, 768, #PB_Sprite_AlphaBlending)
If StartDrawing(SpriteOutput(#Sprite_Menu)) 
	DrawingFont(FontID(#Police_0))
	
	; pour avoir le menu centré
	nb_de_choix = 4
	offset_menu = (ScreenHeight() - nb_de_choix * TextHeight("A")) / (nb_de_choix + 1)
	; pour que ça fonctionne bien, le 1er sprite du menu doit commencer à 1, c'est une astuce ici, mais il faut adapter si c'est pas pareil
	
	Menu_DrawText("DEMARRER", #Sprite_Menu_Demarrer)
	Menu_DrawText("OPTIONS", #Sprite_Menu_Options)
	Menu_DrawText("QUITTER", #Sprite_Menu_Quitter)
	Menu_DrawText("Crédit", #Sprite_Menu_credit)
	
	
	StopDrawing()
EndIf

; utilise des macro simple lorsque du code se répète inutilement, comme ça si tu dois changer un truc ensuite, tu n'as besoin de le faire qu'une fois
Macro Menu_DrawSprite(_sprite_, TEXT)
	If StartDrawing(SpriteOutput(_sprite_)) 
		DrawingFont(FontID(#Police_0))
		DrawText(0, 0, TEXT, RGB(255, 0, 0), RGB(0, 0, 0))
		StopDrawing()
	EndIf
EndMacro

Menu_DrawSprite(#Sprite_Menu_Demarrer, "DEMARRER")
Menu_DrawSprite(#Sprite_Menu_Options, "OPTIONS")
Menu_DrawSprite(#Sprite_Menu_Quitter, "QUITTER")
Menu_DrawSprite(#Sprite_Menu_credit, "Crédit")

sprite = #Sprite_Menu_Demarrer

;}

;{ Event_Loop
; /////////////////////////////////////////////////////////////////////////////
Repeat 
	
	;{ les events
	Repeat
		EventID = WindowEvent()
	Until EventID = 0 Or EventID = #PB_Event_CloseWindow
	
	;}
	
	ExamineKeyboard() 
	
	
	;{ Gestion du clavier
	; /////////////////////////////////////////////////////////////////////////////
	If KeyboardReleased(#PB_Key_Up)
		sprite - 1
		If sprite < #Sprite_Menu_Demarrer : sprite = #Sprite_Menu_credit : EndIf
	EndIf 
	
	If KeyboardReleased(#PB_Key_Down)
		sprite + 1
		If sprite > #Sprite_Menu_credit : sprite = #Sprite_Menu_Demarrer : EndIf
	EndIf
	
	;- appuie sur la touche echap pour quitter
	; /////////////////////////////////////////////////////////////////////////////
	If KeyboardPushed(#PB_Key_Escape)
		EventID = #PB_Event_CloseWindow
	EndIf 
	
	;{ quand ont fait ENTREE sur un menu
	; /////////////////////////////////////////////////////////////////////////////
	If KeyboardReleased(#PB_Key_Return)
		
		If sprite = #Sprite_Menu_Demarrer ; quand ont fait entree sur le menu demarrer
			Debug"demarrer"
		EndIf 
		
		If sprite = #Sprite_Menu_Options ; quand ont fait entree sur le menu options
			Debug"options"
		EndIf 
		
		If sprite = #Sprite_Menu_Quitter ; quand ont fait entree sur le menu quitter
			Debug"quitter"
			End
		EndIf 
		
	EndIf 
	;}
	
	;}
	
	
	ClearScreen(RGB(0, 0, 0)) ; le clearscreen ICI, juste avant les opérations d'affichage
	
	;{ Affichage du menu a l'écran
	; /////////////////////////////////////////////////////////////////////////////
	DisplaySprite(#Sprite_Menu, 0, 0)
	DisplaySprite(sprite, (ScreenWidth() - SpriteWidth(sprite)) / 2, offset_menu * sprite + (sprite-1) * SpriteHeight(sprite))
	
	;}
	
	FlipBuffers(); Met le ICI, après la fin des opérations d'affichage
	
Until EventID = #PB_Event_CloseWindow

;}

End

_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Lemaquis
Messages : 271
Inscription : mer. 25/déc./2013 7:34
Localisation : la corse

Re: Organiser un code pour le jeu

Message par Lemaquis »

au début du code c'est mieux de mettre en une seule fois :

Code : Tout sélectionner

If InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0 And InitSound() = 0
    MessageRequester("Error", "Sprite system can't be initialized", 0)
    End
  EndIf
LeMaquis
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Organiser un code pour le jeu

Message par graph100 »

Ca dépend, si tu veux savoir ou se situe le problème. En pratique, il n'y a jamais de problème avec ces initialisations là.
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
poshu
Messages : 1138
Inscription : sam. 31/juil./2004 22:32

Re: Organiser un code pour le jeu

Message par poshu »

graph100 a écrit :Ca dépend, si tu veux savoir ou se situe le problème. En pratique, il n'y a jamais de problème avec ces initialisations là.
Jusqu'à ce qu'on en ait un, en particulier avec DirectX9 qui n'est plus installé de manière standard depuis vista :p
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Organiser un code pour le jeu

Message par graph100 »

exactement, il vaut mieux séparer !
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
poshu
Messages : 1138
Inscription : sam. 31/juil./2004 22:32

Re: Organiser un code pour le jeu

Message par poshu »

Bon, je n'utilise plus pure pour le jeu (parce que trop de temps perdu à bricoler des trucs qui devraient être standard), mais j'ai fait quelques gamejams avec, et voilà à peut pret à quoi ressemblaient le système général de mes jeux.

Je ne prétends pas que ce soit la meilleure solution (vi, parce que mes gamejams avec pure, c'était aussi mes premiers jeux, haha), mais ça a le mérite d'être fonctionnel :p

Code : Tout sélectionner

;{ Constants
Enumeration Images
   #Sprite_Splash
EndEnumeration

#MyGame = "Un jeu qu'il envoie du poulet"
#Input_Released = #False
#Input_Normal = #True
;}

;{ Initialize the needed librarys
If Not InitSprite() : MessageRequester(#MyGame + " Error","Cannot initialize the sprite engine. Check if DirectX is correctely installed.") : End : EndIf

If Not InitSound() : MessageRequester(#MyGame + " Error","Cannot initialize the sound engine. Check if DirectX is correctely installed.") : End : EndIf

If Not InitKeyboard() : MessageRequester(#MyGame + " Error","Cannot initialize the keyboard. Check if DirectX is correctely installed.") : End : EndIf
UsePNGImageDecoder()
;}

;{ Variables & Structures
Structure _InputConfiguration
   Up.a
   Down.a
   Left.a
   Right.a
   A.a
   B.a
   Start.a
EndStructure

Structure _Input ; réflexe de base à prendre : virtualiser les inputs, sinon à un moment où à un autre, tu vas le regréter.
   Up.b
   Down.b
   Left.b
   Right.b
   A.b
   B.b
   Start.b
   UpReleased.b ; <- ça, ça servira à check si le bouton était appuyé ou non à la frame précédente (en gros, c'est utile pour les menus et des actions comme un double saut)
   DownReleased.b
   LeftReleased.b
   RightReleased.b
   AReleased.b
   BReleased.b
   StartReleased.b
EndStructure

Global._input _Player1_Input, _Player2_Input
Global._InputConfiguration _Player1_InputConf,_Player2_InputConf

; Pourquoi des _ devant tout ça? Bah simplement parce que le dev ne devrait pas y accéder directement, donc si il a des noms comparable dans le reste du code, ça évitera à l'autocomplétion de se remplir pour rien.

Global GameState
;}

;{ Input management
Procedure CheckInput() ;ça, c'est la méthode : "je suis en jam, j'économise des lignes et j'aime faire mumuse avec les pointeurs"... Par contre, faut faire gaffe, ça dépend de l'ordre de _Input et _InputConfiguration; perso je conseillerai d'utiliser un code plus long mais moins bourrin... Sauf que là, j'ai la flème.
   ; Du coup, je commente rien, de toutes façons si tu sais pas lire ce code c'est qu'il faut pas que tu l'utilises.
   Static Total = SizeOf(_InputConfiguration) - 1
   Protected Loop
   
   For loop = 0 To Total
      If PeekB(@_Player1_Input + loop)
         PokeB(@_Player1_Input + Total + loop + 1, #False)
      Else
         PokeB(@_Player1_Input + Total + loop+ 1, #True)
      EndIf
      
      If KeyboardPushed(PeekA(@_Player1_InputConf + loop ))
         PokeB(@_Player1_Input + loop, #True)
      Else
         PokeB(@_Player1_Input + loop, #False)
      EndIf
      
      If PeekB(@_Player2_Input + loop)
         PokeB(@_Player2_Input + Total + loop + 1, #False)
      Else
         PokeB(@_Player2_Input + Total + loop+ 1, #True)
      EndIf
      
      If KeyboardPushed(PeekA(@_Player2_InputConf + loop ))
         PokeB(@_Player2_Input + loop, #True)
      Else
         PokeB(@_Player2_Input + loop, #False)
      EndIf
   Next
   
EndProcedure

Macro PlayerInput(PlayerID,InputID,InputMode = #Input_Normal)
   _Player#PlayerID#_Input\InputID And (_Player#PlayerID#_Input\InputID#Released Or InputMode)
EndMacro
;}

;{ Load settings
;- bon, vu que c'est que le squelette d'un jeu, les seuls settings que j'ai, c'est la conf des inputs des joueurs...
With _Player1_InputConf
   \Up = #PB_Key_Up
   \Down = #PB_Key_Down
   \Left = #PB_Key_Left
   \Right = #PB_Key_Right
   \A = #PB_Key_Pad0
   \B = #PB_Key_Pad1
   \Start = #PB_Key_RightShift
EndWith

With _Player2_InputConf ; adapté à un clavier azerty, parce que c'est probablement ce que vous avez tous sur ce forum
   \Up = #PB_Key_Z
   \Down = #PB_Key_S
   \Left = #PB_Key_Q
   \Right = #PB_Key_D
   \A = #PB_Key_L
   \B = #PB_Key_M
   \Start = #PB_Key_Return
EndWith
;}

;{ General Function
Procedure Exit() ; Gérer la sortie du jeu (sauvegarder? Tout ça tout ça...)
   End
EndProcedure
;}

;{ Open the window
If Not OpenWindow(0,0,0,1280,720,#MyGame,#PB_Window_ScreenCentered|#PB_Window_SystemMenu) : MessageRequester(#MyGame + " Error","Cannot open a window.") : End : EndIf
If Not OpenWindowedScreen(WindowID(0),0,0,1280,720) : MessageRequester(#MyGame + " Error","Failed to create a DirectX Context. Check if DirectX is correctely installed.") : End : EndIf
SetFrameRate(60)
BindEvent(#PB_Event_CloseWindow,@Exit(),0)
;}

;{ Load binaries
LoadImage(0,#PB_Compiler_Home+"Examples\3D\Data\PureBasicLogo.bmp")
CreateSprite(#Sprite_Splash,1280,720) ;<- bon, ça aussi c'est mal... Mais j'ai toujours la flème :D
StartDrawing(SpriteOutput(#Sprite_Splash))
Box(0,0,1280,720,$84695A)
DrawImage(ImageID(0),640-ImageWidth(0)/2,360 - ImageHeight(0)/2)
StopDrawing()
FreeImage(0)
;}

;{ State Functions

Procedure InGame_Render()
   ;Affichage du jeu
EndProcedure

Procedure OnePlayer(Reset = #False)
   ;Calcul de ce qu'il se passe dans le jeu
   
   InGame_Render() ; là, le jeu est framebased, mais si il est timebased, il faudra peut être skipper l'étape d'affichage en fonction du temps...
EndProcedure

Procedure Pause(Reset = #False)
   InGame_Render()
   
   ; Affichage et gestion du menu pause par dessus le jeu.
   
EndProcedure

Procedure TwoPlayer(Reset = #False)
   ;Calcul de ce qu'il se passe dans le jeu
   
   InGame_Render() ; là, le jeu est framebased, mais si il est timebased, il faudra peut être skipper l'étape d'affichage en fonction du temps...
EndProcedure

Declare SplashScreen(Reset = #False)

Procedure Option(Reset = #False)
   Static Mode
   If Reset : mode = 0 : EndIf
   
   If PlayerInput(1,Up,#Input_Released)
      Mode - 1 : If mode = -1 : mode = 2 : EndIf
   EndIf
   
   If PlayerInput(1,Down,#Input_Released)
      Mode + 1 : mode % 3
   EndIf
   
   ClearScreen(0)
   
   StartDrawing(ScreenOutput())
   DrawText(640 - TextWidth(#MyGame)/2,100,#MyGame,$FFFFFF)
   If Mode = 2
      DrawText(640 - TextWidth("Antialiazing : X6480")/2,400,"Antialiazing : X6480",$FFFFFF)
      DrawText(640 - TextWidth("Graphics mode : Over Ultra Burned to the max")/2,450,"Graphics mode : Over Ultra Burned to the max",$FFFFFF)
      DrawText(640 - TextWidth("Exit")/2,500,"Exit",$00FFFF)
   ElseIf mode
      DrawText(640 - TextWidth("Antialiazing : X6480")/2,400,"Antialiazing : X6480",$FFFFFF)
      DrawText(640 - TextWidth("Graphics mode : Over Ultra Burned to the max")/2,450,"Graphics mode : Over Ultra Burned to the max",$00FFFF)
      DrawText(640 - TextWidth("Exit")/2,500,"Exit",$FFFFFF)
   Else
      DrawText(640 - TextWidth("Antialiazing : X6480")/2,400,"Antialiazing : X6480",$00FFFF)
      DrawText(640 - TextWidth("Graphics mode : Over Ultra Burned to the max")/2,450,"Graphics mode : Over Ultra Burned to the max",$FFFFFF)
      DrawText(640 - TextWidth("Exit")/2,500,"Exit",$FFFFFF)
   EndIf
   StopDrawing()
   
   If PlayerInput(1,Start,#Input_Released) And Mode = 2
      GameState = @SplashScreen()
      SplashScreen(#True)
   EndIf
   
EndProcedure

Procedure TitleScreen(Reset = #False)
   Static Mode
   If Reset : mode = 0 : EndIf
   
   If PlayerInput(1,Up,#Input_Released)
      Mode - 1 : If mode = -1 : mode = 2 : EndIf
   EndIf
   
   If PlayerInput(1,Down,#Input_Released)
      Mode + 1 : mode % 3
   EndIf
   
   ClearScreen(0)
   
   StartDrawing(ScreenOutput())
   DrawText(640 - TextWidth(#MyGame)/2,100,#MyGame,$FFFFFF)
   If Mode = 2
      DrawText(640 - TextWidth("One Player")/2,400,"One Player",$FFFFFF)
      DrawText(640 - TextWidth("Two Players")/2,450,"Two Players",$FFFFFF)
      DrawText(640 - TextWidth("Options")/2,500,"Options",$00FFFF)
   ElseIf mode
      DrawText(640 - TextWidth("One Player")/2,400,"One Player",$FFFFFF)
      DrawText(640 - TextWidth("Two Players")/2,450,"Two Players",$00FFFF)
      DrawText(640 - TextWidth("Options")/2,500,"Options",$FFFFFF)
   Else
      DrawText(640 - TextWidth("One Player")/2,400,"One Player",$00FFFF)
      DrawText(640 - TextWidth("Two Players")/2,450,"Two Players",$FFFFFF)
      DrawText(640 - TextWidth("Options")/2,500,"Options",$FFFFFF)
   EndIf
   StopDrawing()
   
   If PlayerInput(1,Start,#Input_Released)
      If Mode = 2
         GameState = @Option()
         Option(#True)
      ElseIf mode
         GameState = @TwoPlayer()
         TwoPlayer(#True)
      Else
         GameState = @OnePlayer()
         OnePlayer(#True)
      EndIf
   EndIf
EndProcedure

Procedure SplashScreen(Reset = #False)
   Static Alpha.f
   If Reset : Alpha = 0 : EndIf
   
   DisplayTransparentSprite(#Sprite_Splash,0,0,Alpha)
   
   Alpha + 0.5
   
   If Alpha > 50
      GameState = @TitleScreen()
      TitleScreen(Reset)
   EndIf
EndProcedure

GameState = @SplashScreen()
;}

; Main Loop
Repeat
   ExamineKeyboard()
   CheckInput()
   
   CallFunctionFast(GameState,#False)
   
   FlipBuffers() ; il faut pas le mettre là si le jeu est timebased
   
   ; là, y'a deux écoles : on peut soit checker un event par frame en se disant que "l'utilisateur n'est pas bionique" ou faire correctement une loop pour vider la pile.
   While WindowEvent() : Wend
ForEver
Aussi, ça a été codé un peu vite fait et un peu de mémoire, donc c'est pas idéal non plus; j'ai commenté ce qui me semblait pas découler d'une logique de base; si t'as des questions, tu peux essayer de les poster.
Si je devais le reprendre aujourd'hui, je dirais qu'il faut caser tout ça dans des modules pour que ça devienne plus lisible...
Dernière modification par poshu le jeu. 21/août/2014 12:09, modifié 2 fois.
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Organiser un code pour le jeu

Message par graph100 »

@Poshu : magnifique ! Merci beaucoup pour cet exemple qui envoi du poulet !

Effectivement c'est vraiment bien organisé.
En revanche je ne comprend pas pourquoi la fenêtre se ferme tout de suite quand on le lance... !?
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
poshu
Messages : 1138
Inscription : sam. 31/juil./2004 22:32

Re: Organiser un code pour le jeu

Message par poshu »

Ça m'apprendra à coder des trucs sans les tester >_<;;; ça vient du bindevent ligne 128, j'avais légèrement oublié de mettre un @, ahahahah (<- manque de talent +1000) J'ai corrigé le code au dessus :D
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Organiser un code pour le jeu

Message par graph100 »

:lol:

Ben il manque une autre erreur, qui masquait celle que tu as trouvé. (j'avais testé mais ça ne changeait pas le problème).

Il faut changer :

Code : Tout sélectionner

CallCFunctionFast(GameState,#False)
par

Code : Tout sélectionner

CallFunctionFast(GameState,#False)
PB n'utilise pas la convention CallCFunctionFast() avec ses propres procédures.
Je te laisse modifier ton code :mrgreen:
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Répondre