Directx tuto 4 : faire son moteur de jeu en directdraw

Soyez le premier à donner votre avis sur cette source.

Snippet vu 4 102 fois - Téléchargée 28 fois

Contenu du snippet

            • Vous devez avoir au minimum les connaissances présentes dans mes précédents tutoriaux !! ******


Souvent quand on programme en direct draw on veut faire des jeux, et là plusieurs problèmes se posent !!!
Tout d'abord, dans un jeu (ici jeux de plateforme) il faut quoi ???

1 - Un niveau de jeu
2 - Un personnage qui se déplace dans le niveau
3 - Un décor en interaction avec le personnage

Donc pas beaucoup de chose si on regarde dans cette optique, donc maintenant on va regarder se qu'il faut pour faire un moteur !!

Source / Exemple :


Si nous nous basons sur l'ordre précédemment montré, notre code sera composé de plusieurs fonctions :

1 - Affichage des décors et des personnages
2 - Déplacement du personnage
3 - Interaction avec le personnage

Soit 3 fonctions, mais si nous ne mettons que c'est 3 fonctions, nous n'arriverons à rien.

Donc, je vais vous présenter un ordre différent : 
1 - Gestion du clavier
2 - Gestion de la fermeture du jeu
3 - Fonction relative à l'affichage
4 - Affichage du décor
         Seulement, le décor doit se déplacer en fonction que le personnage avance ou recule

donc : 4 - Affichage du décor et gestion des déplacements
5- Une fonction d'ouverture des fichiers compressés (GIF et JPEG)
         Quoi de plus, le personnage doit pouvoir sauter 
6 - Saut du personnage
7 - Fonction relative au saut
          Si nous faisons comme cela tous paraît correcte sauf que la ça ne fonctionne toujours pas, car à aucun moment nous ne savons à quel en droit se trouve le personnage...
8 - Position personnage

Maintenant nous avons un plan plutôt correct sur la gestion de notre moteur, il ne reste plus qu'a codé cela.

'**** 1 - Gestion du clavier * ***

Disons que notre personnage doit pouvoir aller à gauche à droite, de plus il faut que la touche echap fasse quitter le jeu et que la touche espace fasse sauter le personnage. Donc, 4 touches à configuré, dans votre module vous mettez une fonction qui sera pour le clavier :

Public Function Clavier()

Il faut ensuite acquérir le statut des touches 
    DIdevice.GetDeviceStateKeyboard DIstate
et après il faut géré les différentes touches :

If (DIstate.Key(DIK_ESCAPE) And &H80) Then
 unloadDD
end if

Ici on regarde avec DIstate si la touche echap est enfoncée si oui alors on appelle unloadDD qui sera la fonction pour quitter le jeu.

Ensuite pour les touches flèche de droite et flèche de gauche :
ScrolD et ScrolG seront les variables de vérification si on appuis sur la touche. 
(D pour droite, G pour gauche lol)

Flèche de gauche

ScrolG = IIf(DIstate.Key(DIK_LEFT) And &H80, 1, 0)
Si on appuis sur la fléche de gauche ScrolG = 1 autrement ScrolG = 0
De même pour la flèche de droite sauf que DIK_LEFT devient DIK_RIGHT

ScrolD = IIf(DIstate.Key(DIK_RIGHT) And &H80, 1, 0)
Si on appuis sur la fléche de droite ScrolD = 1 autrement ScrolD = 0
donc en résumer, on fera cela :

Public Function Clavier()
    
    DIdevice.GetDeviceStateKeyboard DIstate 'on rentre les valeurs des touches activées dans 'DIstate
   
    If (DIstate.Key(DIK_LEFT) And &H80) then
    End If
    If (DIstate.Key(DIK_RIGHT) And &H80) then
    End If

    If (DIstate.Key(DIK_SPACE) And &H80) Then
    End If
    
    If (DIstate.Key(DIK_ESCAPE) And &H80) Then unloadDD

End Function

Ainsi, nous avons donc fait une gestion du clavier, certes il faut encore remplir après Then mais ce n'est pas bien compliqué.Pour les différents codes des touches, je les mettrai dans les explications finales.

'**** 2 - Gestion de la fermeture du jeu ****

Pour gérer la fermeture du jeu, il suffit de quelques lignes.

D'abord comme dit ci-dessus la fonction s'appelle unloadDD :

Public Function unloadDD()

Ensuite il faut arrêter l'affichage à l'écran et vider les caches tout en retournant dans le mode vidéo qui était présent avant l'ouverture du jeu.

Public Function unloadDD()
    bRunning = False                           ' Arrête l'affichage à l'écran
    DD.RestoreDisplayMode                  ' Retourne à l'affichage précédent
    
    Set Primary = Nothing                    ' Vide les différents caches
    Set Backbuffer = Nothing                '
    Set DD = Nothing                           '
    Set DX = Nothing                           '
    End                                              ' Ferme le jeu
End Function

Voila la fermeture du jeu est paramétrée !!!

' **** 3 - Fonction relative à l'affichage ****

Comme vous savez tous on utilise ddRect donc on la met dans le module :

Public Function ddRect(ByVal X1 As Long, _
                       ByVal Y1 As Long, _
                       ByVal X2 As Long, _
                       ByVal Y2 As Long) _
                       As RECT
    With ddRect
        .Left = X1
        .Right = X2
        .Top = Y1
        .Bottom = Y2
    End With
End Function

' **** 4 - Affichage du décor et gestion des déplacements ****

Pour afficher une image à l'écran, normalement nous utilisons la commande :
       
 Backbuffer.BltFast dx, dy ,votre_image, ddRect(0, 0, 0, 0), DDBLTFAST_WAIT
donc on part sur cette base.

Il faut que notre fonction affiche l'image à l'écran, mais en la déplacent si le personnage bouge, je l'appel ainsi :
DrawScrolledSurf

D'où :
Public Function DrawScrolledSurf(Surf As DirectDrawSurface7, _
                                 ByVal X, ByVal Y, _
                                 ByVal X1, ByVal X2, _
                                 ByVal Y1, ByVal Y2)
Explication : 
Surf est l'image à affiché correspond à dds de Backbuffer.Bltfast
X correspond à dx, Y à Dy, X1, X2, Y1,Y2 correspondent au ddRect

 'Ici, on gère l'affichage il faut que l'image apparaisse en partie losrqu'elle arrive sur les bords de l'écran pendant les déplacements. 
   
If X < 0 Then              ' si X < 0 donc à gauche de l'écran alors 
        X1 = X1 - X         ' X1 sera diminué de la différence de ce qui sort de l'écran.
        X = 0
    End If
    
' De même si le personnage saute
    If Y < 0 Then
        Y1 = Y1 - Y
        Y = 0
    End If
    
    If X + X2 > 640 Then X2 = X2 - ((X + X2) - 640)     ' Quand X2 atteint une valeur ici 640 alors X2 est remit à sa valeur première
    If Y + Y2 > 480 Then Y2 = Y2 - ((Y + Y2) - 640)     ' De même pour Y2
    
    Backbuffer.BltFast X, Y, Surf, ddRect(X1, Y1, X2, Y2), DDBLTFAST_WAIT Or DDBLTFAST_SRCCOLORKEY     
' On à plus qu'à affiché le tous à l'écran avec la gestion des ColorKey.

End Function

5- Une fonction d'ouverture des fichiers compressés (GIF et JPEG)

La même fonction que donné dans les tutoriaux précédents :

'Pour ouvrir des fichiers gif et jpeg
Public Function CreateSurfaceFromFile(DirectDraw As DirectDraw7, ByVal FileName As String, SurfaceDesc As DDSURFACEDESC2) As DirectDrawSurface7
    Dim Picture As StdPicture
    Dim Width As Long
    Dim Height As Long
    Dim Surface As DirectDrawSurface7
    Dim hdcPicture As Long
    Dim hdcSurface As Long
    
    'On Charge l'image
    Set Picture = LoadPicture(FileName)
    'On convertit les dimensions
    'de vbHimetric vers vbPixel
    Width = CLng((Picture.Width * 0.001) * 567 / Screen.TwipsPerPixelX)
    Height = CLng((Picture.Height * 0.001) * 567 / Screen.TwipsPerPixelY)
       
    'On définit les propriété de la description
    With SurfaceDesc
        If .lFlags = 0 Then .lFlags = DDSD_CAPS
        .lFlags = .lFlags Or DDSD_WIDTH Or DDSD_HEIGHT
        If .ddscaps.lCaps = 0 Then .ddscaps.lCaps = DDSCAPS_OFFSCREENPLAIN
        If .lWidth = 0 Then .lWidth = Width
        If .lHeight = 0 Then .lHeight = Height
    End With
     
    'On crée la surface DirectDraw
    Set Surface = DirectDraw.CreateSurface(SurfaceDesc)

    'On crée de la Mémoire (pour charger l'image)
    hdcPicture = CreateCompatibleDC(0)

    'On sélectionne le Picture et on le copie
    'vers la mémoire crée
    SelectObject hdcPicture, Picture.Handle
      
    'Handle de la surface
    hdcSurface = Surface.GetDC
       
    'On copie l'image contenue dans hdcSurface vers la surface
    StretchBlt hdcSurface, 0, 0, SurfaceDesc.lWidth, SurfaceDesc.lHeight, hdcPicture, 0, 0, Width, Height, vbSrcCopy
   'On libère l'espace mémoire contenue dans hdcSurface
    Surface.ReleaseDC hdcSurface
    DeleteDC hdcPicture
    
    'On transfère la Surface
    Set CreateSurfaceFromFile = Surface
    
    'On vide Tout !
    Set Picture = Nothing
    Set Surface = Nothing
End Function

'**** 6 - Saut du personnage ****

J'utilise le saut avec la méthode des sinus, donc je vais vous expliquez celle-ci.

Public Function SautPerso()

    If Not bJumping Then
        CheckH LeftPerso
' Une fonction qui sera présente dans la form.

        If TopPerso < Hsol Then TopPerso = Hsol

' Pour si notre personnage est trop bas par rapport au sol.
        Exit Function
    End If

    lAngleSaut = lAngleSaut + 5      'L'angle du saut 
            
    CheckH LeftPerso                    
    CheckTopPos TopPerso            'Expliqué plus bas
            
    If lAngleSaut > 180 Or Hsol < TopPerso Then       ' Si le personnage saute
        CheckH LeftPerso                                          ' et qu'il saute trop longtemps
        TopPerso = Hsol                                            
        HImpulse = 0
        lAngleSaut = 0          'alors il y réinitialisation
        bJumping = False        'et on ne saute plus
        Exit Function
    End If
        
    TopPerso = HImpulse - Sin(lAngleSaut / 180 * Pi) * hSaut
'Ici le personnage saute avec la Hauteur de l'impulsion - le sinus (d'où méthode des sinus) de l'angle / 180 pour pouvoir avoir une valeur supérieur a 0 multiplié par Pi qui sera définit plus bas et le tout multiplié par la hauteur du saut.

End Function

Donc il suffit de recréé la position du personnage par rapport au sol pour le faire sauté.
Cette fonction évite de faire :
Topperso = Topperso +0,5    (0,5 en exemple)
puis de faire 
Topperso = Topperso - 0,5    (0,5 toujours en exemple)
et bien sur le tous comprenant des if ...

'**** 7 - Fonction relative au saut ****

Tout simplement Pi !!

Public Function Pi() As Double
    'Atn(1) = 45° = Pi/4 radians
    'donc Pi = Atn(1) × 4
    
    Pi = Atn(1) * 4
End Function

Assez explicite je crois !!!

'**** 8 - Position personnage ****

Il nous faut la position du personnage pour pouvoir faire différente manipulation, tel que la mort du personnage s'il tombe dans un trou.

Function CheckTopPos(TopPos)
If TopPos = Hsol And Hsol > 220 Then  
' Si le personnage et en dessous du sol donc dans un trou ben vous mettez se que 
'vous voullez vu que j'ai pas mit :P
End If
End Function

Voila le moteur est enfin terminé seulement pour que tout fonctionne correctement il faut une ou 2 peut entre même 3 fonctions dans la form même ou votre code est placé : '**** Donc d'abord les mouvements vers la droite : Public Function MoveRight() if ScrolD = 0 then Exit Function 'si on appuis pas sur la fléche de droite ben c pas sa lol CheckH LeftPerso + OffSetX ' On récupère la nouvelle positon du personnage ' OffsetX une variable concernant le déplacement. CheckTopPos TopPerso ' On récupére la position du personnage en hauteur If TopPerso > Hsol Then Exit Function 'Si le personnage et plus haut que le sol ben on laisse tombé ... 'Scrolling des objets LeftTonneau = LeftTonneau - OffSetX 'Tous simplement on enlève OffsetX a la position de l'objet, et vu qu'on la défini avec notre fonction d'affichage tout le reste se fait seul ! End Function '***** Pour les mouvements vers la gauche c'est pareil : Public Function MoveLeft() if ScrolG = 0 then Exit Function 'si on appuis pas sur la fléche de gauche ben c pas sa lol CheckH LeftPerso - OffSetX ' on récupère la nouvelle positon du personnage ' OffsetX une variable concernant le déplacement. CheckTopPos TopPerso ' on récupère la position du personnage en hauteur If TopPerso > Hsol Then Exit Function 'Si le personnage et plus haut que le sol ben on laisse tombé ... 'Scrolling des objets LeftTonneau = LeftTonneau + OffSetX End Function '****** Maintenant la position du personnage par rapport au objet celle qui vous manquez !!!! Public Function CheckH(NewPos) ' Pour exemple : If NewPos + 80 > LeftCaisse And NewPos < LeftCaisse + 108 Then Hsol = 220 - 100 'Donc si le personnage et sur la caisse ben la hauteur du sol augmente comme 'sa le personnage ne traverse pas la caisse !!! Else 'pour mettre une autre objet : If NewPos + 5 > LeftMur And NewPos < LeftMur + 55 Then Hsol = -220 Else If NewPos > LeftGrandTrou And NewPos < LeftGrandTrou + 80 Then Hsol = 220 + 100 Else End if End if End if Remarque : Les if sont les un dans les autres et pas les un à la suite des autres !!! '************************** Voila il ne reste plus que deux choses à faire : MoveRight MoveLeft SautPerso Fire Clavier mettre tous sa dans la boucle d'affichage !! Exemple pour l'affichage d'un objet : DrawScrolledSurf Tonneau, LeftTonneau, TopTonneau, TonneauX1, TonneauX2, 0, 139 Comme vous pouvez le voir toute les données X, Y, X1,X2, Y1, Y2 sont sous forme de variable de type Long !! '************************ Et derniére chose toutes les variables et autre référence utilisé pour ce module (à placé en haut du modul !!) Public Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long Public Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long Public Declare Function StretchBlt Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal dwRop As Long) As Long Public Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long Public DX As New DirectX7 Public DD As DirectDraw7 Public DI As DirectInput Public DIdevice As DirectInputDevice Public DImouse As DirectInputDevice Public Publicouse As DirectInputDevice Public DIstate As DIKEYBOARDSTATE Public Primary As DirectDrawSurface7 Public Backbuffer As DirectDrawSurface7 Public bRunning As Boolean Public lAngleSaut As Long 'Avancement dans le saut Public HImpulse As Long 'Hauteur d'où l'on saute Public Hsol As Long Public OffSetX pour une meilleur utilisation mettez l'initialisation de vos variables dans une fonction ou une sub exterieur à celle utilisée pour l'affichage. Maintenant vous avez un jolie petit moteur qui fonctionne bien.

Conclusion :


Un petit conseil, pour le fond si vous voulez que se soit une image qui se répéte n'utilisez pas la fonction qu'on a écrit met bltfast et mettez dans Move_Right et Move_left ceci :

Pour Move_Left :
LeftFond = LeftFond + OffSetX
X2FondScroll = X2FondScroll - OffSetX
If LeftFond >= ScreenWidth Then
LeftFond = 0
X2FondScroll = FondWidth
End If

Pour Move_Right

LeftFond = LeftFond - OffSetX
X2FondScroll = X2FondScroll + OffSetX
If LeftFond < 0 Then
LeftFond = LeftFond + ScreenWidth
X2FondScroll = LeftFond + FondWidth
End If
If X2FondScroll + LeftFond > ScreenWidth Then X2FondScroll = ScreenWidth - LeftFond

Assez explicite je pense, mais il vous faut les variables :

Public LeftFond As Long
Public X2FondScroll As Long
Public X1FondScroll As Long
Public FondHeight As Long
Public FondWidth As Long
Public ScreenWidth As Long

J'allais oublié les codes des touches avec directx :

Touche classique :

DIK_x touche x (x=0..9,A..Z).
DIK_Fx touche de fonction Fx (x=1..15)
DIK_NUMPADx touche x du pavé num (x=0..9)

Modificateurs :

DIK_LSHIFT Shift gauche
DIK_RSHIFT Shift droit
DIK_LCONTROL Ctrl gauche
DIK_RCONTROL Ctrl droit
DIK_LMENU Alt gauche
DIK_RMENU Alt droit
DIK_CAPITAL verrou capitale

Touches spécials :

DIK_SPACE espace
DIK_PRIOR page précédente
DIK_NEXT page suivante
DIK_HOME début
DIK_END fin
DIK_LEFT flèche gauche
DIK_RIGHT flèche droite
DIK_UP flèche haut
DIK_DOWN flèche bas
DIK_INS insérer
DIK_DEL efface à droite
DIK_RETURN entrée
DIK_TAB tabulation
DIK_BACK efface à gauche

Je crois qu'elles sont présentes sur un autre de mes tuto.

Je pense que ce moteur peut être largement améliorer mais il a le mérite de fonctionner.

Des que je peux je met un zip.

Tout les commentaires sont les bienvenues à part les critiques qui n'ont rien avoir avec le sujet :DD

D'aprés Vlad2i c'est le systeme utilisé dans les jeux worms .....

Je remercie Vlad2i qui m'a vraiment beaucoup appris et aider en direct x !!

Bon allé bonne programmation.

A voir également

Ajouter un commentaire

Commentaires

vlad2i
Messages postés
285
Date d'inscription
mercredi 20 août 2003
Statut
Membre
Dernière intervention
13 février 2005
-
Coucouc fitz :P

Héhé
vlad2i
Messages postés
285
Date d'inscription
mercredi 20 août 2003
Statut
Membre
Dernière intervention
13 février 2005
-
Juste une correction (quote) :

"D'aprés Vlad2i c'est le systeme utilisé dans les jeux worms"

C'est UNE ADAPTATION des systèmes de collision de worms...

(Aujourd'hui fitz a dit qqch d'intelligent : Je remercie Vlad2i, mais étant donné que je ne lui ai rien donné, je vois pas pourquoi il le fait )

(Ca fait qd meme plaisir)
ShadowMaster
Messages postés
184
Date d'inscription
mercredi 27 novembre 2002
Statut
Membre
Dernière intervention
18 août 2005
-
bravo tu regroupe tout les elements pour faire le jeu que l'on desir en direct draw.
Sinon perso j'ajouterais un DoEvents à la fin de la fonction du clavier, de plus si tu n'attend pas de résultat à une function antant utilisé Sub.
ciberrique
Messages postés
591
Date d'inscription
lundi 25 août 2003
Statut
Membre
Dernière intervention
18 juillet 2010
-
Merci ShadowMaster, ton commentaire me fait plaisir !!!
Pour vlad2i je dirais nianianianianianianiania lol non il as raison ce n'est qu'une adaptation et ne croyé pas ses bétises sans lui se moteur n'aurait pu etre !!!

Personnellement je ne vois pas pourquoi tu veux mettre un doevents ShadowMaster et puis bon function ou sub c'est pas extremement grave je pense, mais tu as pas tord du tout !!!

Merci encore.
gandalfkhorne
Messages postés
70
Date d'inscription
dimanche 11 janvier 2004
Statut
Membre
Dernière intervention
1 octobre 2004
-
Peut tu faire un tuto pour la gestion du son, et coment fais ton du 3D si possible.

(tuto 5 et 6 pk pa?)

Thx

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.