N’ayant jamais vraiment sérieusement programmé sous Windows, je me suis tout d’abord trouvé l’IDE/compilateur Delphi 3 et j’ai chargé quelques exemples pour voir comment tout ca marchait. Il y a plusieurs différences avec la programmation sous DOS. La plus importante étant la gestion d ‘évènements qui n’interviennent pas sous DOS, comme la réception de Messages Windows. Ces messages disent par exemple a l’application que la souris a bougée ou que l’utilisateur a tapé sur une touche, et l’application doit gérer du code à exécuter selon le message reçu.
Le jeu sera en fait un mixe des deux mondes, tout d’abord, il créera sa propre fenêtre avec une fonction d'API Windows, et ensuite il dessinera un frame, et gérera les messages, cela jusqu'à la fin du programme.
Par contre, l’éditeur sera une vraie application Windows et les évènements du genre mouse click seront gérés par les procédures des objets delphi. Le dessin des graphismes sera fait uniquement quand il le sera nécessaire.
Sinon, ayant déjà programmé en Pascal, la syntaxe ne me posait pas vraiment de problèmes, et des que je bloquais, je tapais F1 pour amener l’aide de Delphi qui est assez bien faite.
Programmation Graphique
Je passai donc a DirectDraw.
Je telechargai le SDK (software developpement kit) de DirectX 6.1 du site de Microsoft. Ce SDK vient avec un fichier d’aide très détaillée avec des exemples en C. Ayant quelques notions en C, je pouvais traduire quelques passages en Delphi et essayer de les compiler. Problème : le SDK utilisait des headers C (*.h) de DirectX, il me fallait donc les équivalents en Unités Delphi. Je me remis donc sur le net et chercha un peu. En quelques minutes je trouvai exactement ce qu’il me fallait :
Ce site proposait en téléchargement les conversions des headers C en fichiers *.pas compatibles avec Delphi 3+.
A partir de la, j’ai donc commencé à traduire un exemple du SDK en pascal. J’avais beau essayer de trouver ce que j’avais mal traduis, le programme compilait mais j’avais un écran noir et nécessité de redémarrer le PC. Je me suis donc mis à lire toute l’aide du SDK concernant DirectDraw. Le problème etait du a un non-remplissage de ma part d’une structure par des zéros. Certaines fonctions DirectDraw prennent des structures en paramètres qui doivent déjà être entièrement initialisées par des zéros. Ceci résolu le problème.
Je codai donc un petit programme qui faisait rebondir un sprite sur l’écran, en mode plein écran, avec une surface pour l’écran, et une surface dans laquelle dessiner la scène avant de tout copier sur l’écran. DirectDraw est assez bizarre a initialiser mais une fois que c’est fait, la programmation graphique et notamment l’affichage de sprites transparents a l’écran est facile.
Programmation Jeux
Je me mis donc a rechercher des infos sur la programmation de jeux style StarCraft.
Je pensais devoir aller trouver des livres traitant ce sujet, mais un petit tour sur le net suffi largement.
J’ai trouve un super site avec pleins d’infos sur l’IA, les jeux 2d, appelé The Game Programming Megasite, j’ai téléchargé pratiquement toutes les docs trouvés dessus. D’ailleurs j’ai bien fait car le lien ne marche plus aujourd’hui.
Un autre site très intéressant aussi sur une université américaine :
http://www-cs-students.stanford.edu/~amitp/gameprog.html
J’ai appris que ce genre de jeux s’appelle le Tile Based Game, c’est à dire des jeux qui utilisent un système de cases comme une matrice pour les décors. Le Tile est la structure prédominante du jeu.
Ensuite j’ai lance StarCraft pour voir comment les choses etaient faites, par rapport à ce que j’avais lu.
Je suis tout de suite sorti et j’ai lance l’éditeur
de cartes qui vient avec le jeu. Cet éditeur affiche la carte sous
une grille noire qui délimite chaque Tile. On pouvait ainsi voir
tous les différent tiles et comment ils etaient poses pour former
une carte donnant l’impression de reliefs.
Comme aucun de nous n’avait envie de perdre de temps a essayer de faire de jolis décors, on décida de reprendre les images de StarCraft pour les cartes.
Il me fallait donc un moyen assez rapide d’extraire les images du jeu et de pouvoir les rassembler comme on voulait. Je suis donc retourne sur le net en quête d’un extracteur.
J’ai donc trouve un site avec pleins d’outils spécialement conçus pour StarCraft :
Dans ce jeu, tous les fichiers charge pendant le jeu (a part les cartes) sont compresses dans des archives mpq, j’ai donc téléchargé l’extracteur de mpq (MPQ Viewer), et j’ai ouvert le stardat.mpq :
Dedans il y avait apparemment pas de fichiers images pour les tiles. Ils y sont, mais dans des archives *.grp. J’ai donc téléchargé le viewer de grp (CV5).
Avec tout ca et un autre programme appelé TileEdit, j’ai pu reconstituer un fichier bmp avec tous les tiles de type jungle. StarCraft a des cartes de différents genres, comme la neige, ou dans l’espace ou dans des jungles. Pour 42 Minutes Pour Vivre, l’éditeur proposera tous les tiles disponibles directement et l’utilisateur sera libre de créer ce qu’il voudra.
Systèmes De Coordonnées
En lisant les documents trouves sur le net, je m’aperçu
qu’il fallait beaucoup réfléchir à comment aller se
structurer l’engin du jeu avant de se lancer dans le code.
J’ai donc élaboré un plan théorique
qui sera sûrement légèrement modifie plus le projet
avancera, mais qui établi les bases structurelles sur lesquelles
nous pouvons ensuite construire.
Le premier point important est la différenciation
des systèmes de coordonnées qui seront utilise dans la programmation
du jeu.
Il est important de les expliquer et de les différencier
pour éviter des erreurs dans le code plus tard.
Tous ces systèmes sont 2 dimensionnels.
D'abord il faut définir quelques constantes :
NTilesX : le nombre de Tiles (voir cartographie)
en horizontal sur la carte
NTilesY : le nombre de Tiles en vertical.
TilePicWidth : l'épaisseur d'un Tile.
TilePicHeight : la hauteur d'un Tile.
ScreenWidth : le nombre de pixels de l'écran
en horizontal.
ScreenHeight : le nombre de pixels de l'écran
en vertical.
Voici donc les différents systèmes :
La Structure Du Tile
Le Tile est la structure pre-dominante du jeu.
D’après ce que j’ai lu sur le net et vu dans StarCraft,
la structure doit ressembler à ceci :
Tile = record
PosX,PosY : integer;
Walkable : boolean;
Layer1SrcRect : TRect;
HasLayer2 : boolean;
Layer2SrcRect : TRect;
xoffset,yoffset : byte;
UnitList : UnitListPointer;
end;
Un Tile est un carre qui est représente par une
image et des informations.
Cette image est en fait un carré sur un fichier
image général contenant tous les tiles possibles.
PosX et PosY sont les coordonnées monde de ce
tile sur la carte.
Layer1SrcRect est le rectangle source sur ce fichier
image général.
HasLayer2 nous dit si ce Tile est attache à une
image annexe (comme une panoplie d'un arbre).
Si c'est le cas, Layer2SrcRect est le rectangle source
sur un autre fichier qui contient les images annexes, et xoffset et yoffset
sont le décalage horizontal et vertical de cette image par rapport
à l'image du tile.
Exemple: On veut faire un arbre.
Le Tile contenant le tronc de l'arbre a pour PosX,PosY
64,64, la panoplie est un rectangle plus large que le tile, et on veut
donc le centrer par rapport à lui. Si XOffset est mis à 10
et YOffset a 0, la panoplie sera affichée à 64-10,64-0, soit
54,64.
Walkable nous dit si une unité peut se déplacer
sur ce Tile. Par exemple, une unité ne peut pas venir marcher sur
un arbre donc on met walkable a FAUX pour un tile contenant un tronc d'arbre.
UnitList est une liste-chainée composée
de toutes les unités présentées sur ce Tile.
Cartographie
Numériquement, les cartes du jeu sont des fichiers
texte contenant NTilesX,NTilesY et toutes les informations de la structure
Tile pour chaque Tile de la carte (sauf UnitList, qui est recrée
après le chargement de la carte, et PosX et PosY qui sont recalcules
directement au chargement de la carte).
Elle contient aussi le nombre d'unités, ainsi
que leurs types, états et positions en coordonnées monde.
Dans l’engin du jeu, la carte est stockée dans
un tableau deux dimensionnel de Tiles.
L’Engin 2D
Tout ceci nous mène à l’engin 2d. Apres
avoir bien lu toutes les docs que j’avais trouve sur les Tile Based Games,
je me suis lance dans le code de notre futur engin.
J’ai tout d’abord extrait quelques Tiles de terre (32x32
pixels) de StarCraft et les ai mis cote à cote dans un fichier que
j’ai appelé jungle.bmp. Ce fichier est charge dans une surface,
donc quand je veux afficher un tile a l’écran, je spécifie
juste le rectangle sur cette surface source.
J’ai donc fait un petit programme qui affichait sur l’écran
une carte composée de Tiles au hasard parmis ceux existant dans
jungle.bmp.
Quand on bouge la souris a une des extrémités
de l’écran, la carte se met à scroller.
Scroller est en fait changer les positions de départ
de vue de la carte sur l’écran.
Ces positions sont dans des variables globales MapX,MapY.
Donc, a chaque itération de la boucle principale,
le programme regarde s’il doit scroller, ensuite il dessine la carte dans
une BackSurface (zone de mémoire ou tout est dessine avant d’être
flippée sur l’écran) : Il trouve le tile correspondant à
la position MapX,MapY, et dessine tous les tiles du tableau (BackTileMap
: array[0..NtilesX-1,0..NtilesY-1] of Tile) visibles a partir de ce point
sur la BackSurface.