PureBasic:Realiser un RPG2D/Combats, fondus enchaînés et coffre


PureBasic:Realiser_un_RPG2D

<< Précédent | Sommaire | Suivant >>




Prérequis

Difficultée estimée de cette étape: moyenne


Pré-requis:

  • Bonne connaissance du PureBasic (allocations dynamiques, pointeurs et gestion des entrées/sorties)
  • Avoir compris le fonctionnement du système d'événements.


Cet article va apporter une toute nouvelle fonctionnalité: la gestion des combats. Il s'agira de la plus grosse partie de cette étape. Toutefois, d'aures petits ajouts viendront s'y ajouter comme les fondus enchaînés, la gestion des coffres et de l'écran de fin de jeu.

Sommaire

[modifier] Introduction

Ce tutoriel est incomplet, il manque la gestion des fondues enchainées et des combats. Je n'ai pas le temps de faire l'adaptation complète, aussi si quelqu'un souhaite poursuivre qu'il ne s'en prive pas.

Je voulais tout de même faire l'adaptation du code pour la version 4.0 de PureBasic, et le tester avec les six cartes que M. Cool a créé.

Je poste les sources des fois que quelqu'un souhaite se plonger dedans pour poursuivre le tutoriel.

[modifier] Fondus enchaînés

Cette partie n'est pas encore faite. (Un volontaire ? )


Ce système va être réutilisé lors de la conception des combats afin de fournir une transition dynamique entre la carte et le combat lui-même.


[modifier] Coffre

Avant de commencer, demandons-nous ce qu'est un coffre dans un jeu: il s'agit d'un élément du décor qui est dynamique: il s'agit d'une tuile qui change dans notre carte lorsque le joueur appuie sur la touche d'action face à ce dernier.

Pour réaliser un coffre, il nous faut donc un nouvel événement: EVENT_CHANGETILE. Cet événement permettra de modifier la carte. Il sera très utile lors de la conception du jeu afin de fournir une carte plus dynamique: ouvrir un passage sur la carte, faire disparaître ou apparaître un décor est désormais à notre portée!


[modifier] Ajout d'un nouvel événement

L'ajout de l'événement s'effectue comme d'habitude:

On ajoute le nouvel événement au type énumérés contenant la liste des événements gérés (dans events.pbi):

;Type d'évènement : e_event_type
Enumeration
  #EVENT_NULL
  #EVENT_TELEPORT
  #EVENT_DIALOG   
  #EVENT_BATTLE
  #EVENT_SHOP
  #EVENT_INN
  #EVENT_CHANGETILE
EndEnumeration

On ajoute plus bas le type paramètre de notre événement:

Structure s_event_param_changetile 
  x.l
  y.l
  newtile.l
EndStructure

Les paramètres sont simples à comprendre: lorsque l'événement est activé, la tuile à la position (x,y) prend la valeur newtile.

Profitons-en pour ajouter le prototype de la fonction associée à l'événement:

Declare DoEventChangetile(*event.s_event, *map.s_map)


Il faut ensuite modifier les fonctions d'écriture et lecture afin de pouvoir sauvegarder et charger notre nouvel événement (dans events.pb):

Procedure ReadEvent(*event.s_event)
  Define.s_event_param_teleport   *Ptparam_telport
  Define.s_event_param_dialog     *Ptparam_dialog
  Define.s_event_param_battle     *Ptparam_battle
  Define.s_event_param_shop       *Ptparam_shop
  Define.s_event_param_inn        *Ptparam_inn
  Define.s_event_param_changetile *Ptparam_changetile
  Define                          *buffer
  Define.long                     *Ptr
  Define.s FichierSon, Fichier, dialogue
  Define.l i, j
  
  InitEvent(*event)
   
  *event\type = ReadLong(0)
  If *event\type = #EVENT_NULL : ProcedureReturn :  EndIf 
  
  *event\onaction    = ReadLong(0)
  *event\proba       = ReadByte(0)
  *event\player_anim = ReadLong(0)
  *event\is_unique   = ReadByte(0)
  
  FichierSon = Space(256)
  ReadData(0, @FichierSon, 63)
  *event\sound=LoadSound(#PB_Any, FichierSon)
     
  Select *event\type
     
    Case #EVENT_NULL
     
    Case #EVENT_TELEPORT
        
      *event\param = AllocateMemory(SizeOf(s_event_param_teleport))
      *Ptparam_telport = *event\param
      
      Fichier = Space(256)
      ReadData(0, @Fichier, 63)
      
      If Len(Trim(Fichier)) = 0
        *Ptparam_telport\filename = #NULL$
      Else
        *Ptparam_telport\filename = Fichier
      EndIf 
      
      *Ptparam_telport\startX = ReadLong(0)
      *Ptparam_telport\startY = ReadLong(0)
     
    Case #EVENT_DIALOG
      *event\param    = AllocateMemory(SizeOf(s_event_param_dialog))
      *Ptparam_dialog = *event\param
      
      dialogue = Space(256)
      ReadData(0, @dialogue, 255)
      
      *Ptparam_dialog\dialog = dialogue
     
    Case #EVENT_BATTLE
      *event\param = AllocateMemory(SizeOf(s_event_param_battle))
      *Ptparam_battle = *event\param
      *Ptparam_battle\n_monstre = ReadLong(0)

      *buffer = AllocateMemory(SizeOf(byte) * 63)
      ReadData(0, *buffer, 63)
      
      ;If buffer[0] = 0
      ;  ((struct s_event_param_battle*)event->param)->fond=NULL;
      ;Else
      ;  ((struct s_event_param_battle*)event->param)->fond=strdup(buffer);
      ;EndIf
      
      *buffer = AllocateMemory(SizeOf(byte) * 63)
      ReadData(0, *buffer, 63)
      
      ;If buffer[0] = 0
      ;  ((struct s_event_param_battle*)event->param)->fondu=NULL;
      ;Else
      ;  ((struct s_event_param_battle*)event->param)->fondu=strdup(buffer);
      ;EndIf
      
      *Ptparam_battle\monstres = AllocateMemory(*Ptparam_battle\n_monstre * SizeOf(s_monstre))

      For i = 0 To *Ptparam_battle\n_monstre - 1
        With *Ptparam_battle\monstres
        \hp           = ReadLong(0)
        \hpmax        = ReadLong(0)
        \mp           = ReadLong(0)
        \mpmax        = ReadLong(0) 
        \vitesse      = ReadLong(0)
        \force        = ReadLong(0)
        \dexterite    = ReadLong(0)
        \precision    = ReadLong(0)
        \intelligence = ReadLong(0)
        \n_attaques   = ReadLong(0)
        \attaques     = AllocateMemory(\n_attaques * SizeOf(long))       

        For j = 0 To \n_attaques - 1
          ReadLong(0) ; stocker les valeurs lues dans \attaques
          ;fread(&((struct s_event_param_battle*)event->param)->monstres[i].attaques[i],SizeOf(unsigned int), 1, f);
        Next j
        EndWith
        
        *buffer = AllocateMemory(SizeOf(byte) * 63)
        ReadData(0, *buffer, 63)
        ;If(buffer[0]==0)
        ;  ((struct s_event_param_battle*)event->param)->monstres[i].surf=NULL;
        ;Else
        ;  ((struct s_event_param_battle*)event->param)->monstres[i].surf=SDL_LoadBMP(buffer);
        ;  SDL_SetColorKey(((struct s_event_param_battle*)event->param)->monstres[i].surf, SDL_SRCCOLORKEY,SDL_MapRGB(((struct s_event_param_battle*)event->param)->monstres[i].surf->format,255,255,255));
      Next i

       
    Case #EVENT_SHOP
      *event\param           = AllocateMemory(SizeOf(s_event_param_shop))
      *Ptparam_shop          = *event\param
      *Ptparam_shop\n_item   = ReadLong(0)
      *Ptparam_shop\itemId   = AllocateMemory(*Ptparam_shop\n_item * SizeOf(LONG))
      *Ptparam_shop\coutItem = AllocateMemory(*Ptparam_shop\n_item * SizeOf(LONG))
      
      For i = 0 To *Ptparam_shop\n_item - 1
        *Ptr   = *Ptparam_shop\itemId + i * SizeOf(LONG)
        *Ptr\l = ReadLong(0)
        *Ptr   = *Ptparam_shop\coutItem + i * SizeOf(LONG)
        *Ptr\l = ReadLong(0)
	    Next i
        
      *Ptparam_shop\prixVente = AllocateMemory(#MAX_ITEMS * SizeOf(LONG))
      
      For i = 0 To #MAX_ITEMS-1
        *Ptr   = *Ptparam_shop\prixVente + i * SizeOf(LONG)
        *Ptr\l = ReadLong(0)
      Next i
    
    Case #EVENT_INN
      *event\param      = AllocateMemory(SizeOf(s_event_param_inn))
      *Ptparam_inn      = *event\param
      *Ptparam_inn\cout = ReadLong(0)
    
    Case #EVENT_CHANGETILE
      *event\param                = AllocateMemory(SizeOf(s_event_param_changetile))
      *Ptparam_changetile         = *event\param
      *Ptparam_changetile\x       = ReadLong(0)
      *Ptparam_changetile\y       = ReadLong(0)
      *Ptparam_changetile\newtile = ReadLong(0)
    
  EndSelect
EndProcedure
Procedure WriteEvent(*event.s_event, bg_sound.s)
  Define.s_event_param_dialog   *Ptparam_dialog
  Define.s_event_param_teleport *Ptparam_telport
  Define.s_event_param_inn      *Ptparam_inn
  Define.s_event_param_shop     *Ptparam_shop
  Define.long                   *Ptr
  Define                        *buffer
  Define i
    
  *buffer = AllocateMemory(256)
    
  WriteLong(0, *event\type)
  If *event\type = #EVENT_NULL : ProcedureReturn : EndIf 
  
  WriteLong(0, *event\onaction)
  WriteByte(0, *event\proba)
  WriteLong(0, *event\player_anim)
  WriteByte(0, *event\is_unique)
  WriteData(0, @bg_sound, Len(bg_sound))
  WriteData(0, *buffer, 63 - Len(bg_sound))
  
  Select *event\type
     
    Case #EVENT_NULL
     
    Case #EVENT_TELEPORT
    	*Ptparam_telport = *event\param
    	If *Ptparam_telport\filename <> #NULL$
    		WriteData(0, @*Ptparam_telport\filename, Len(*Ptparam_telport\filename))
	  	EndIf  
    	WriteData(0, *buffer,63 - Len(*Ptparam_telport\filename))
    	WriteLong(0, *Ptparam_telport\startX)
    	WriteLong(0, *Ptparam_telport\startY)
     
    Case #EVENT_DIALOG
    	*Ptparam_dialog = *event\param
    	If *Ptparam_dialog\dialog <> #NULL$
	    	WriteData(0, @*Ptparam_dialog\dialog, Len(*Ptparam_dialog\dialog))
    	EndIf  
    	WriteData(0, *buffer, 255 - Len(*Ptparam_dialog\dialog))

    Case #EVENT_BATTLE
;           fwrite(&((struct s_event_param_battle*)event->param)->n_monstre, SizeOf(unsigned int), 1, f);
;       
;       memset(&buffer,0,SizeOf(buffer));
;       If(((struct s_event_param_battle*)event->param)->fond!=NULL)
;         strcpy(buffer,((struct s_event_param_battle*)event->param)->fond);
;       fwrite(&buffer,63,SizeOf(char),f);
;  
;       memset(&buffer,0,SizeOf(buffer));
;       If(((struct s_event_param_battle*)event->param)->fondu!=NULL)
;         strcpy(buffer,((struct s_event_param_battle*)event->param)->fondu);
;       fwrite(&buffer,63,SizeOf(char),f);
;  
;       For(i=0;i<((struct s_event_param_battle*)event->param)->n_monstre;i++)
;       {
;         fwrite(&((struct s_event_param_battle*)event->param)->monstres[i].hp,
;                SizeOf(unsigned int), 1, f);
;         fwrite(&((struct s_event_param_battle*)event->param)->monstres[i].hpmax,
;                SizeOf(unsigned int), 1, f);
;         fwrite(&((struct s_event_param_battle*)event->param)->monstres[i].mp,
;                SizeOf(unsigned int), 1, f);
;         fwrite(&((struct s_event_param_battle*)event->param)->monstres[i].mpmax,
;                SizeOf(unsigned int), 1, f);
;         fwrite(&((struct s_event_param_battle*)event->param)->monstres[i].vitesse,
;                SizeOf(unsigned int), 1, f);
;         fwrite(&((struct s_event_param_battle*)event->param)->monstres[i].force,
;                SizeOf(unsigned int), 1, f);
;         fwrite(&((struct s_event_param_battle*)event->param)->monstres[i].dexterite,
;                SizeOf(unsigned int), 1, f);
;         fwrite(&((struct s_event_param_battle*)event->param)->monstres[i].precision,
;                SizeOf(unsigned int), 1, f);
;         fwrite(&((struct s_event_param_battle*)event->param)->monstres[i].intelligence,
;                SizeOf(unsigned int), 1, f);
;         fwrite(&((struct s_event_param_battle*)event->param)->monstres[i].n_attaques,
;                SizeOf(unsigned int), 1, f);
;         For(j=0;j<((struct s_event_param_battle*)event->param)->monstres[i].n_attaques;j++)
;           fwrite(&((struct s_event_param_battle*)event->param)->monstres[i].attaques[i],
;                  SizeOf(unsigned int), 1, f);
;  
;         memset(&buffer,0,SizeOf(buffer));
;         strcpy(buffer,"battlers/051-Undead01.bmp");
;         fwrite(&buffer,63,SizeOf(char),f);
;       }
;       Break;
      
     
    Case #EVENT_SHOP
      *Ptparam_shop = *event\param
      WriteLong(0, *Ptparam_shop\n_item)
      For i = 0 To *Ptparam_shop\n_item - 1
        *Ptr=*Ptparam_shop\itemId + i * SizeOf(LONG)
        WriteLong(0, *Ptr\l)
        *Ptr=*Ptparam_shop\coutItem + i * SizeOf(LONG)
        WriteLong(0, *Ptr\l)
	    Next i	
      
      For i = 0 To #MAX_ITEMS - 1
        *Ptr=*Ptparam_shop\prixVente + i * SizeOf(LONG)
        WriteLong(0, *Ptr\l)
      Next i        
   
    Case #EVENT_INN
      *Ptparam_inn = *event\param
      WriteLong(0, *Ptparam_inn\cout)
      
    Case #EVENT_CHANGETILE
;       fwrite(&((struct s_event_param_changetile*)event->param)->x, SizeOf(unsigned int), 1, f);
;       fwrite(&((struct s_event_param_changetile*)event->param)->y, SizeOf(unsigned int), 1, f);
;       fwrite(&((struct s_event_param_changetile*)event->param)->newtile, SizeOf(unsigned int), 1, f);

        
  EndSelect
EndProcedure

Il ne s'agit donc que d'ajouter 3 fread()/fwrite() dans nos fonctions afin de charger les paramètres. Rien de compliqué jusqu'à présent!

Il faut également penser à libérer les paramètres dans la fonction FreeEvent()

Procedure FreeEvent(*event.s_event)
  
  Define.s_event *suivant
    
  *Suivant.s_event
   
  If *event = 0 : ProcedureReturn : EndIf
   
  *event = *event\Next
  
  While *event
      
    *Suivant = *event\Next
    
    If *event\sound : FreeSound(*event\sound) : EndIf    

    Select *event\type
    
      Case #EVENT_NULL
          
      Case #EVENT_TELEPORT
        FreeMemory(*event\param)
          
      Case #EVENT_DIALOG
        FreeMemory(*event\param)
          
      Case #EVENT_BATTLE
        FreeMemory(*event\param)
          
      Case #EVENT_SHOP
        FreeMemory(*event\param)
          
      Case #EVENT_INN
        FreeMemory(*event\param)

      Case #EVENT_CHANGETILE 
        FreeMemory(*event\param)

    EndSelect
    
    FreeMemory(*event)
    
    *event = *Suivant
  Wend
EndProcedure


Désormais, écrivons la fonction appellée lors du déclenchement de l'événement:

Procedure DoEventChangetile(*event.s_event, *map.s_map)
  Define.s_event_param_changetile *Ptparam_s_changetile
  *Ptparam_s_changetile = *event\param
  DataMap(GET_TILE(*Ptparam_s_changetile\x, *Ptparam_s_changetile\y, *map)) =   *Ptparam_s_changetile\newtile
EndProcedure

Il ne reste plus qu'à modifier DoEvent pour appeler la fonction que nous venons d'écrire lorsqu'un événement de type CHANTILE se déclenche:

Procedure DoEvent(*event.s_event, *libevent.s_lib_event, *map.s_map, *libsprite.s_lib_sprite, *player.s_player,*gui.s_gui)
  Define.s_event_param_shop *Ptparam_shop 
  Define.s_event_param_inn  *Ptparam_inn
  
  If *event = #Null : ProcedureReturn 0 : EndIf
  If *event\type = #EVENT_NULL : ProcedureReturn 0 : EndIf
  If *event\sound : PlaySound(*event\sound) :  EndIf        

  Select *event\type
      
    Case #EVENT_TELEPORT
      DoEventTeleport(*event, *libevent, *map, *libsprite)
      ProcedureReturn 1
        
    Case #EVENT_DIALOG
      DoEventDialog(*event, *gui, *map, *libsprite)
        
    Case #EVENT_BATTLE
      DoEventBattle(*event, *libevent, *map, *libsprite)
        
    Case #EVENT_SHOP
      DoEventShop(*event, *map, *libsprite, *player, *gui)
        
    Case #EVENT_INN
      DoEventInn(*event, *map, *libsprite, *player, *gui)
          
    Case #EVENT_CHANGETILE
      DoEventChangetile(*event, *map)
            
  EndSelect    
  
  If *event\is_unique
      
    ;suppr. de l'événement 
    Select *event\type
        
      Case #EVENT_NULL
          
      Case #EVENT_TELEPORT
        FreeMemory(*event\param)
          
      Case #EVENT_DIALOG
        FreeMemory(*event\param)
          
      Case #EVENT_BATTLE
        FreeMemory(*event\param)
          
      Case #EVENT_SHOP
        *Ptparam_shop = *event\param
        FreeMemory(*Ptparam_shop\itemId)
        FreeMemory(*Ptparam_shop\coutItem)
        FreeMemory(*Ptparam_shop\prixVente)
        FreeMemory(*event\param)
          
      Case #EVENT_INN
        FreeMemory(*event\param)
      
      Case #EVENT_CHANGETILE
        FreeMemory(*event\param)  
            
    EndSelect
    *event\type = #EVENT_NULL
    *event\onaction = #EVENT_ACTION_AUTO
    ;*event\param = #Null
  EndIf
  
  ProcedureReturn 0
    
EndProcedure

Il est également nécessaire d'ajouter un cas au switch supprimant les événements s'ils sont uniques.

Une fois ces modifications effectuées, vous pouvez utiliser RPG 2D Generator afin de générer des niveaux comportant ce type d'événement.

[modifier] Conception du coffre (carte et événement)

Pour concevoir le coffre, il faut donc réaliser le travail suivant:

  1. on place un tile de coffre à un endroit de la carte
  2. on place un événement de type changetile afin de pouvoir l'ouvrir.

L'événement devrait ressembler à cela dans le générateur:

code à créer

Il s'agit d'un événement associé à un coffre situé à la position (2,3).

[modifier] Game Over

Dès lors que l'on implémente un système de combat, notre joueur peut mourir. Nous allons prévoir cela en implémentant une petite fonction affichant l'image de fin à l'écran et en jouant une musique.

Code a créer

[modifier] Système de combat tour par tour

[modifier] Principe général

Le principe du combat est le suivant: chaque opposant choisit chacun son tour une attaque et la lance.

Il s'agit d'une version très simplifiée des systèmes présents dans les RPG actuels, libre à vous de l'améliorer. Les combats opposants plus de deux combatants ne sont pas non plus gérés même si les types le permette. Libre à vous d'améliorer le système!


[modifier] Ajout des fichiers fight.pb et fight.pbi

Il est nécessaire pour commencer d'ajouter deux fichiers à notre projet: fight.pb et fight.pbi qui contiendront les fonctions associées au système de combat.

;/*
;** fight.pb
;**
;** Système de combat tour par tour.
;**
;*/
XIncludeFile "fight.pbi"
;/*
;** fight.pbi
;**
;** Système de combat tour par tour.
;**
;*/

A compléter

L'en-tête du fichier contient également quelques macros définissant la position des sprites des monstres et des joueurs selon leur n° dans l'équipe et leur taille. Il n'y a pas grand chose à comprendre ici, ces formules ayant été trouvées de manière empirique après quelques essais.

[modifier] Gestion des attaques

Nous allons devoir concevoir un système gérant:

  1. la liste des attaques du jeu avec leurs caractéristiques
  2. la liste des attaques disponibles pour chaque joueur

Note: les attaques des monstres seront gérés à la section suivante.

Dans ce but, nous allons ajouter les types nécessaires dans le fichier player.pbi:

Code a créer

Les prototypes des fonctions que nous allons écrire sont:

Declare InitLibAttaque(*lib_attaque.s_lib_attaque)
Declare FreeLibAttaque(*lib_attaque.s_lib_attaque)
Declare ChargeAttaques(*lib_attaque.s_lib_attaque)


Il reste à définir ces fonctions dans player.pb:

Code a créer

Nous pouvons charger et libérer les attaques, il faut désormais à chaque joueurs leurs attaques. Deux champs sont nécessaires dans les statistiques de chaque joueur (dans events.pbi):

structure s_stat_player
A compléter
EndStructure

[modifier] Gestion des monstres

La gestion des monstres est équivalente à celle des joueurs à quelques exceptions près puisque nous n'avons pas à gérer leur évolution lors de la partie.

Le type définissant un monstre est (dans player.pbi):

structure s_monstre
A compléter
EndStructure

Les prototypes nécessaires sont:

Declare InitMonstre(*monstre.s_monstre)
Declare FreeMonstre(*monstre.s_monstre)

Les monstres sont initialisés et libérés par ces fonctions (dans player.pb)

Code a créer


[modifier] Affichage des animations

L'affichage des animations fonctionne grâce à un système de variables statiques: à chaque fois que la fonction est appellée, on vérifie si l'animation a changé depuis la dernière fois. Si c'est le cas, on initialise la nouvelle animation. Dans le cas contraire l'image suivante de l'animation est affichée.

La fonction renvoit le numéro de l'image affichée ou -1 si l'animation est finie.

Code a créer


[modifier] Affichage des dégâts

L'affichage des dégâts fonctionne d'une façon similaire à la fonction précédente. Dans ce cas, il faut mettre reinit à vrai pour que la fonction soit réinitialisée. Sinon les dégâts continuent d'être affichés à l'écran. Les trois premiers paramètres ne sont pas pris en compte si l'on n'est pas en train de réinitialiser la fonction.

Code a créer

[modifier] Affichage des joueurs et des monstres

L'affichage des joueurs et des monstres et une simple boucle for qui effectue une copie des surfaces en mémoire.

Code a créer
Code a créer

[modifier] Réaliser la fonction gérant le combat

La fonction gérant le combat est assez complexe car il faut:

  1. afficher la scène via les fonctions écrites juste avant
  2. gérer le menu
  3. gérer les tours (est-ce à l'ia ou au joueur de jouer?)
  4. vérifier si le combat est fini

Si le joueur gagne la partie, il obtient 100 pièces d'or. Il s'agit d'une récompense inclue dans le code et qui n'est pas paramétrable actuellement.

Code a créer

La fonction DoFight() gère le combat et le fait précéder du rendu spécifier dans les paramètres de l'événement.

Code a créer

[modifier] Gestion de l'événement associé

Les lecteurs les plus perspicaces auront remarqué que le code de la première section ne modifie pas que l'événement CHANGETILE. Le code concernant l'événement BATTLE a également changé afin de concorder avec le type ci-dessous:

Structure a créer

Le fondu contient le chemin du schéma de transition (cf fondus enchaînés). Le fond contient le chemin vers le décor de fond durant la bataille. Le nombre de monstres et un tableau contenant les monstres est également fourni.

Je reprécise ci-dessous quelques morceaux de code concernant cet événement particulier. Cependant, ces changements étaient déjà présent au début de l'article lors de la description du système permettant la gestion des coffres.


Dans ReadEvent():

Code a créer

Dans WriteEvent():

Code a créer


[modifier] Modification de la fonction principale

La seule modification dans la fonction principale est l'ajout du chargement des attaques ainsi que leur libération.

Compléter le fichier main.pb


[modifier] Notes concernant la mise à niveau pour la version 4.0

Les codes des tutoriels précédents sont réalisés avec la version 3.94, celui ci est mis à jour pour fonctionner avec la version 4.0.

Les principales modifications pour fonctionner avec la version 4.0 sont :

  • ClearScreen() : Il n'y a plus qu'un paramètre couleur
  • TransparentSpriteColor() : Il n'y a plus qu'un paramètre couleur
  • FrontColor() : Il n'y a plus qu'un paramètre couleur
  • Locate() : Cette commande est supprimée
  • DrawText() : Cette commande intègre la position qui était autrefois dans Locate()
  • TextHeight() : Remplace l'API GetTextExtentPoint32_()
  • TextWidth() : Remplace la commande TextLengh(), c'est la même chose, il n'y a que le nom qui change
  • Toutes les commandes de la bibliothèque File ont un paramètre supplémentaire. Ce nouveau paramètre permet de préciser le numéro du fichier concerné.
  • Utilisation de With EndWith , pour montrer que ça existe :)
  • Utilisation des macros
  • EnableExplicit : Cette commande n'était pas indispensable, mais elle est conseillée.

Et j'en ai profité pour remplacer certaines couleurs par les constantes déjà définies dans les résidents , comme la couleur noire = #Black , ou blanche = #White ou encore la couleur rouge = #Red.

[modifier] Démo n°6: combats tour par tour, fondus enchaînés et coffre

Cette nouvelle démo apporte un monde bien plus étendu (6 cartes au lieu de 2), des combats contre deux types de monstres, la gestion des fondus enchaînés et un coffre. Enfin pas encore, seulement si un volontaire trouve du temps pour finir l'adaption du code original.

Image:Rpg2d combats.jpg

Image:Rpg2d_combats2.jpg