[tutoriel] introduction à la création d'un jeu 2D

Informations pour bien débuter en PureBasic
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

[tutoriel] introduction à la création d'un jeu 2D

Message par blendman »

salut

Voici le début d'un tutoriel pour la création d'un jeu 2D en purebasic.

Introduction

Réaliser un jeu 2d en purebasic est très simple. Il y a de très nombreuses fonctions fournies pour cela.

Tout d'abord, il faut savoir qu'un jeu s’exécute plutôt dans un screen (via OpenScreen() pour le plein-écran, ou OpenWindowedScreen() pour un jeu en mode fenêtre).

Ensuite, on utilise en purebasic, et de manière transparente :
- directX sous windows
- OpenGL sous linux (depuis la 4.61, avant c'était SDL)

Dans un jeu 2D, on utilise des images. Ces images sont des jpg, des bmp ou des png qui peuvent être transparents pour ces derniers.
On utilise dans le jeu ce que l'on nomme des sprites (ou sprite3D aussi en purebasic). Ce sont des sortes de plans sur lesquels on dessine nos images importées.

L'utilisation de sprite() est donc possible, mais l'utilisation de sprite3D() est préférable, car ceux-ci vous permettront plus de choses (transformation, rotation..) et sont beaucoup plus performants.

L'organisation du code

Il s'agit d'un enchainement très classique et assez simple.
On peut retrouver ce type d'organisation pour la plupart des programmes (jeu ou applications).

Évidemment, vous pouvez organiser votre code comme vous le souhaitez, mais certaines choses sont nécessaires avant l’exécution de la boucle du jeu (déclaration des structures/constantes, initialisation, openwindow/screen avant le loading des sprites, etc.).

Code : Tout sélectionner

- déclaration des constantes, enumeration, variables
- déclaration des structures
- déclaration des procédures, des macros
- initialisation (initsprite()..)
- ouverture de la fenêtre et/ou de l'écran
- loading des ressources
- initialisation si besoin de certaines variables (par exemple : ouverture de la sauvegarde du jeu, etc..)
- lancement du jeu (boucle du jeu)
Concernant les procédures, on peut les mettre au début (après les structures par exemple), ou à la fin du code (après la boucle), mais il faudra les déclarer avec le terme :

Code : Tout sélectionner

declare 
Ensuite, on peut utiliser des données qu'on intègre aussi si on le souhaite, ou préférer laisser les données (images, texte) à l'extérieur du programme.
Pour utiliser ces données (data), il faut utiliser les datasection/enddatasection.



Exemple de base de jeu

- création d'un personnage
- création de pnj/ennemis
- création d'une "caméra" virtuel
- création de la map (carte)

action :
- déplacement du personnage (clavier)
- scrolling, en faisant attention à ne pas dépasser les bords.

C'est un exemple très basique, mais il peut être utile pour la compréhension de quelques fonctions d'un jeu (scrolling, camera..)

Le code :

Code : Tout sélectionner

;{ les constantes
; commencent toutes par # et sont invariables
#window = 0; pour la fenêtre
#loadsprite = 0; juste pour savoir si on charge les images ou non (dans la partie "ouverture de la fenêtre")

Enumeration ; pour les sprites
  ; les enumeration permettent d'énumérer facilement plusieurs constantes qui se suivent et se définissent d'elles-mêmes
  #perso1 ; vaut "0"
  #pnj1 ; vaut 1 
  #pnj2 ; vaut 3
  #mob1 ; vaut 4
  #mob2 ; vaut 5, etc....
EndEnumeration
;}

;{ structures
;{ carte
Structure stCarte ; pour créer une carte (map)
  width.w : height.w
  nom.s : numero.a
EndStructure
Global carte.stCarte
; j'utilise des globales pour pouvoir passer chaque élément (carte, camera, player, pnj), sans soucis dans les procédures. 
; on pourrait utiliser des pointeurs pour ça (*carte.stcarte), mais ce n'est pas pour débutant, donc on utilisera les globales ici. 

With carte ; j'initialise la carte
  \nom = "Les Plaines Dherb"
  \numero = 1; par ex, c'est la carte N°1
  \width = 4000  ; 4000 pixels de large
  \height = 3000 ; 3000 pixels de haut
EndWith 
;}
;{ pnj, ennemi
Structure stPnj ; pour les ennemis/pnj..
  ; on met les champs que l'on veut ici, si on utilise  ":", on gagne des lignes ;)
  sprite.w; l'image du sprite utilisé
  x.w : y.w ; position
  nom.s : race.s 
EndStructure
; on créé un tableau global pour 40 pnjs/ennemis
Global Dim pnj.stpnj(39) ; de 0 à 39, ça fait 40, on créé un tableau avec 40 pnjs
 
; on initialise nos pnj/ennemi
For i = 0 To ArraySize(pnj())
  With pnj(i)
    \nom = "pnj"+Str(i); str() sert à transformer une variable en texte
    \sprite = #pnj1 + Random(1) ; random() sert à sortir un nombre au hasard (nombre défini en paramètre)
    \x = Random(carte\width)-32; position x au hasard en fonction de la largeur de la carte - la taille du sprite
    \y = Random(carte\height)-32; position y au hasard en fonction de la hauteur de la carte - la taille du sprite
  EndWith  
Next i
;}
;{ player
Structure StPlayer Extends stPnj ; une structure pour le joueur 
  ; on ne peut pas utiliser le define dans une structure
  ; extends, permet de créer une structure qui utilise les champs d'une autre structure (c'est une sorte de copier-coller des champs)
; on hérite des champs de stpnj, c'est à dire : nom, sprite, x, y et race
  classe.s ; la classe du personnage
  vitesse.a ; vitesse de déplacement du personnage
EndStructure
Global player.StPlayer 

With player ; j'initialise le joueur
  \classe = "elfe"
  \nom ="Roberto"
  \race = "elfe bleu turquoise"
  \sprite = #perso1
  \vitesse = 3
  \x = 50+random(50)
  \y = 50+random(50)
EndWith
;}
;{ camera
Structure Stcamera ; pour créer une caméra virtuelle
  x.w : y.w
EndStructure
Global camera.Stcamera 
;}
;}

;{ declaration des procedures (ce sont des fonctions qu'on peut utiliser))
; on declare 1 procedure, car on l'a écrite en bas du code.
Declare AddSprite(sprite,size,color)
;}

;{ macros : ce sont un peu comme des procedures, sauf que le code est copié à chaque fois
Macro BorneValeurMini(x,val)
  If x < val : x = val : EndIf ; pour vérifier si on n'est pas <0
EndMacro
Macro BorneValeurMaxi(x,val)
  If x > val : x = val : EndIf ; pour empêcher d'être supérieur à une valeur, par exemple pour ne pas dépasser la taille de la map
EndMacro
;}

;{ initialisation : on initialise les libs utilisées (directX sous windows, OpenGL sous linux, les sprites, sprite3D et clavier)
InitSprite()
InitSprite3D()
InitKeyboard()
;}

;{ ouverture de la fenêtre
OpenWindow(#window,0,0,800,600,"Base Jeu Scrolling",#PB_Window_ScreenCentered|#PB_Window_MaximizeGadget)
OpenWindowedScreen(WindowID(#window),0,0,800,600,0,0,0,#PB_Screen_SmartSynchronization)
UseJPEGImageDecoder() : UsePNGImageDecoder() ; pour charger des jpg ou des png (avec canal alpha)
;{ charger tes images/sprite
If #loadsprite = 1
; si vous voulez charger des images , changer le chemin c:/images/ton_perso1.jpg , c:/images/ton_perso2.png et c:/images/ton_perso3.png
  LoadSprite(#perso1,"c:/images/ton_perso1.jpg", #PB_Sprite_Texture); si c'est un jpg, pas de canal alpha
  CreateSprite3D(#perso1,#perso1)
  LoadSprite(#pnj1,"c:/images/ton_perso2.png", #PB_Sprite_Texture|#PB_Sprite_Alpha); c'est un png, on peut avoir un canal alpha
  CreateSprite3D(#pnj1,#pnj1)
  LoadSprite(#pnj2,"c:/images/ton_perso3.png", #PB_Sprite_Texture|#PB_Sprite_Alpha); c'est un png, on peut avoir un canal alpha
  CreateSprite3D(#pnj2,#pnj2)
  ;}
;{ créer un sprite (si besoin)
Else
  AddSprite(#perso1,32,RGB(125,0,0)); le joueur
  AddSprite(#pnj1,32,RGB(0,125,0)); les pnjs
  AddSprite(#pnj2,32,RGB(0,0,125)); les pnjs
EndIf
;}
;}

;{ boucle repeat
Repeat
  event = WindowEvent() ; on attend un évènement dans la fenêtre et on stocke celui dans la variable event 
  ; que je n'ai pas déclarée d'ailleurs, et que je déclare ici même=
  Select event ; on va vérifier quel évènement a lieu
    Case #PB_Event_CloseWindow; si on clique sur la croix
      quit = 1 ; on quitte
  EndSelect
  
  ExamineKeyboard(); nécessaire pour voir si tu utilises le clavier
  ;{ déplacement du joueur
  If KeyboardPushed(#PB_Key_Right) And player\x < carte\width
     player\x + player\vitesse
     camera\x = player\x - 800/2 ; la résolution du jeu/2 ; mise à jour de la camera
     BorneValeurMini(camera\x,0)
     BorneValeurMaxi(camera\x,carte\width- 800/2)
  EndIf
  If KeyboardPushed(#PB_Key_Left) And player\x >-16
    player\x - player\vitesse
    camera\x = player\x - 800/2 ; la résolution du jeu/2 ; mise à jour de la camera
    BorneValeurMini(camera\x,0)
    BorneValeurMaxi(camera\x,carte\width- 800/2)
  EndIf
  If KeyboardPushed(#PB_Key_Up) And player\y > -16
    player\y - player\vitesse
    camera\y = player\y - 600/2 ; mise à jour de la camera
    BorneValeurMini(camera\y,0)
    BorneValeurMaxi(camera\y,carte\height- 600/2)
  EndIf
  If KeyboardPushed(#PB_Key_Down)And player\y < carte\height
    player\y + player\vitesse
    camera\y = player\y - 600/2 ; mise à jour de la camera
    BorneValeurMini(camera\y,0)
    BorneValeurMaxi(camera\y,carte\height- 600/2)
  EndIf
  ;}
  
  ;{ affichage du jeu
  ClearScreen(RGB(125,125,125)); on efface l'écran avec du gris
  

  DisplaySprite(#pnj1,200-camera\x,400-camera\y) ; on peut afficher un sprite comme ça, mais je conseille d'utiliser les sprite3D, beaucoup plus rapide et permettent plus de choses.
  ; le sprite n'est pas transparent (mais on pourrait en utilisant DisplayTransparentSprite() ou d'autres fonctions), alors que le sprite 3D sera transparent de base et permet plus de chose

  ; les sprite3D
  Start3D()
  ; d'abord je dessine tous les pnj. j'aurai pu aussi utiliser une list(), ou une map(), mais pour ce 1er exemple, j'ai utilisé un tableau
  For i = 0 To ArraySize(pnj())
    DisplaySprite3D(pnj(i)\sprite,pnj(i)\x-camera\x,pnj(i)\y-camera\y) 
  Next i  
  DisplaySprite3D(#perso1,player\x-camera\x,player\y-camera\y) ; tu peux afficher un sprite comme ça, mais je conseille d'utiliser les sprite3D, beaucoup plus rapide et permettent plus de choses.
  Stop3D()
  StartDrawing(ScreenOutput()) 
  DrawingMode(#PB_2DDrawing_Transparent); on met le mode transparent pour le texte
  DrawText(player\x-camera\x,player\y-camera\y,Str(player\x)+"/"+Str(player\y))
  StopDrawing()
  FlipBuffers(); on "flippe" le buffer, utile pour les jeux vidéos, histoire de ne pas avoir de flickering, tearing (écran déchiré)
  ;}
  Delay(1); on met un petit delay, hsitoire de redonner à l'ordinateur le contrôle :)
Until KeyboardPushed(#PB_Key_Escape) Or quit = 1

End ; pas obligé, mais ça indique qu'on a terminé

;}

;{ les procedures
; creation des sprites
Procedure AddSprite(sprite,size,color)
  CreateSprite(sprite,size,size,#PB_Sprite_Texture); j'utilise #PB_Sprite_Texture, car on va en faire un sprite3D juste après
  CreateSprite3D(sprite,sprite)
  ; on dessine sur le sprite créé (ici, juste un cercle)
  StartDrawing(SpriteOutput(sprite)); on lui indique sur quoi on va dessiner
  Circle(size/2,size/2,size/2,color)
  StopDrawing()
EndProcedure

;}

;{ si besoin, les data sections
DataSection
  image1 :
  ; chemin de ton image
  ; pour l'utiliser, dans la section charger tes images :
  ; CatchSprite(sprite,?image1,#PB_Sprite_Texture|#PB_Sprite_Alpha)
EndDataSection
;}
N'hésitez pas à l'améliorer si vous le souhaitez.
Dernière modification par blendman le mer. 23/mai/2012 12:19, modifié 5 fois.
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: [tutoriel] introduction à la création d'un jeu 2D

Message par blendman »

Réservé partie 2 (menu et GUI)
Dernière modification par blendman le mer. 23/mai/2012 10:00, modifié 1 fois.
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: [tutoriel] introduction à la création d'un jeu 2D

Message par blendman »

Réservé partie 3 (collisions)
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: [tutoriel] introduction à la création d'un jeu 2D

Message par blendman »

Réservé partie 4 (sauvegarde et loading)
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: [tutoriel] introduction à la création d'un jeu 2D

Message par blendman »

réservé partie 5 : gérer des évènements simples
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: [tutoriel] introduction à la création d'un jeu 2D

Message par blendman »

réservé partie 6 (autre informations)
Avatar de l’utilisateur
MetalOS
Messages : 1492
Inscription : mar. 20/juin/2006 22:17
Localisation : Lorraine
Contact :

Re: [tutoriel] introduction à la création d'un jeu 2D

Message par MetalOS »

Dommage que ce tuto n'est pas fini. Tu doit sûrement avoir pas mal de taf Blendman.
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Re: [tutoriel] introduction à la création d'un jeu 2D

Message par Backup »

oui, puis les sprite ont changés , il n'y a plus de SpriteD()

en fait il le sont tous , plus exactement :)
Avatar de l’utilisateur
MetalOS
Messages : 1492
Inscription : mar. 20/juin/2006 22:17
Localisation : Lorraine
Contact :

Re: [tutoriel] introduction à la création d'un jeu 2D

Message par MetalOS »

Pour ma part c'est surtout la partie 2 qui m'intéresse sur les Menu et GUI.
Répondre