Jeu Risk Star Wars

Transcription

Jeu Risk Star Wars
Risk Star Wars
Antoine BELIN (belin_a)
Christopher TAUPIN (taupin_c)
Patrice DE SAINT STEBAN (de-sai_p)
Thibault ROBIN (robin_t)
le 21 Juin 2005
1
Unbound
Value
Star Wars Risk
Soutenance Finale
Table des matières
1 Introduction
1.1
1.2
1.3
1.4
Présentation du groupe . . . . . . . . . . . . . . . .
1.1.1 Antoine, allias Send' . . . . . . . . . . . . .
1.1.2 Christopher, allias Lord Gunator . . . . . .
1.1.3 Patrice, allias Patou... . . . . . . . . . . . .
1.1.4 ...et le dernier de la liste : Thibault ! ! ! . . .
Nos premiers pas . . . . . . . . . . . . . . . . . . .
1.2.1 Idée du Projet . . . . . . . . . . . . . . . .
1.2.2 Présentation du projet . . . . . . . . . . . .
Les règles du jeu établis lors de la 1ière soutenance
1.3.1 Menu du Jeu . . . . . . . . . . . . . . . . .
1.3.2 Répartition et déplacement des Troupes . .
1.3.3 Phases de Combat . . . . . . . . . . . . . .
1.3.4 Fin de la Partie . . . . . . . . . . . . . . . .
Les prévisions pour nos diérentes échéances . . . .
1.4.1 Découpage du projet . . . . . . . . . . . . .
1.4.2 Répartition . . . . . . . . . . . . . . . . . .
2 Elaboration des graphismes
2.1
2.2
2.3
2.4
Introduction . . . . . . . . . . . . . . . .
La carte galactique . . . . . . . . . . . .
2.2.1 Pourquoi l'utilisation des calques
Le panneau de lancement . . . . . . . .
2.3.1 Quitter . . . . . . . . . . . . . .
2.3.2 Options . . . . . . . . . . . . . .
2.3.3 Jouer . . . . . . . . . . . . . . .
Création des sprites . . . . . . . . . . . .
2.4.1 Les sprites des planètes . . . . .
2.4.2 Les sprites d'unités . . . . . . . .
3 L'achage graphique
3.1
3.2
4.2
EPITA
.
.
.
.
.
.
.
.
.
.
L'Achage Graphique [Direct X sous Direct
3.1.1 Les Classes et Objets Delphi . . . .
3.1.2 Procédures de la classe Graphique .
Place à l'achage... . . . . . . . . . . . . . .
4 Le moteur de jeu
4.1
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Draw]
. . . .
. . . .
. . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
L'éditeur XML . . . . . . . . . . . . . . . . .
4.1.1 Les procédures de lecture XML . . . .
Les premières fonctions . . . . . . . . . . . . .
4.2.1 Constantes, Types et Enregistrements
4.2.2 Procédure de Distribution Planétaire .
2
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4
4
4
5
5
5
5
5
5
6
6
7
7
8
8
8
9
11
11
11
11
11
12
12
14
15
15
16
18
18
18
19
24
32
32
33
38
38
39
InfoSup B2
Unbound
Value
4.3
4.2.3 Fonction-Procédure d'Achage Planétaire
4.2.4 Génèse . . . . . . . . . . . . . . . . . . . .
4.2.5 Répartition des unités . . . . . . . . . . .
4.2.6 Procédure de combat . . . . . . . . . . . .
4.2.7 Finalité du Programme . . . . . . . . . .
Le moteur de jeu . . . . . . . . . . . . . . . . . .
5 L'intelligence articiel
5.1
5.2
Star Wars Risk
Soutenance Finale
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
Le déploiement des troupes
La phase d'attaque
6 La mise en place du son
48
48
49
50
7 Notre site web
7.1
7.2
40
40
42
43
44
44
Site Publique (http ://risk.star.wars.free.fr/))
. . . . . . . . .
Administration Interne (http ://risk.star.wars.free.fr/admin/)
52
52
52
8 L'installation et la désinstallation
53
9 Conclusion
54
EPITA
3
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
1 Introduction
Ce jeu, inspiré du célèbre jeu de société Risk, et de sa version dérivée du
Seigneur des Anneaux , se déroulera dans l'univers mythique de Star Wars.
Le but du jeu est d'accomplir la mission donnée en début de partie ou de
conquérir par la force des armes la maîtrise de la galaxie toute entière..
L'issue des combats est déterminée par des jets de dés. La partie se joue
entre 2,3 ou 4 joueurs, ces derniers pouvant d'aronter sur le même ordinateur, via réseau ou être gérés par un ordinateur.
Ce cahier des charges représentera le groupe, les prévisions des diérentes
phases du projet, ainsi que le matériel dont nous aurons besoin.
Alors que la force soit avec nous !
1.1 Présentation du groupe
En apprennant que l'on devait réaliser un projet informatique, il nous a
fallut constituer notre propre groupe ! Ce ne fut pas chose facile, car nous
nous connaissions alors très peu. Cependant, après le séminaire, quelques
anités s'étaient déjà opérées : deux groupes de deux se sont alors formés.
Encore fallait-t'il que le sujet plaise à tous ! Lorsqu'il fut trouvé, le groupe
nal se constitua. Depuis, les membres du groupe ont appris à mieux se
connaître. Ce groupe est resté inchangé pour les exposés en méthodologie.
Le nom du groupe nous posa problème, il fut résolu lors d'un TP d'algo.
Une phrase s'achait beaucoup trop souvent à notre goût sur notre écran :
Unbound Value ! ! D'abord synonyme de profond agacement, elle symbolisa
par la suite la tentative de compréhension d'un problème dépassant l'entendement, puis un symbole de victoire lorsque ce message disparaissait enn.
Le groupe fut ainsi dénitivement créé.
1.1.1 Antoine, allias Send'
J'habite dans une petite ville située à la limite du 91 et du 78. Mes
passions restent simples. J'aime lire et écouter toute sorte (ou presque) de
musique. J'adore faire du sport, spécialement les sports de raquettes, qui
demandent un esprit individuel assez développé, mais surtout les sports
d'équipes, qui m'apportent beaucoup dans ma vie collective.
Hélas, je ne peux plus en faire autant que je le souhaiterais, à cause du
manque de temps et de la longueur des trajets. Enn, j'adore regarder de
bons lms le soir et passer un peu de temps avec un groupe d'amis extraordinaire.
EPITA
4
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
se produira sur un plateau représentant la galaxie, cette dernière étant découpée en diérentes régions. Diérentes phases de jeu rythmeront la partie.
En eet, chaque joueur déploiera ses troupes pour écraser ses ennemis, mais
il devra ensuite encaisser les phases de combat qui lui seront proposées par
ses ennemis. L'issue des combats sera déterminée par des jets aléatoires de
dés. Celui qui remporte sa mission ou qui conquiert la galaxie toute entière
a gagné la partie.
Le jeu se déroulera entre 2, 3, 4, 5 ou 6 joueurs, ces derniers pouvant
joués sur un même ordinateur, en réseau ou être générés par l'ordinateur.
1.3 Les règles du jeu établis lors de la 1ière soutenance
Nous avons cherché à harmoniser nos points de vue sur les aspects graphiques du jeu. Pour ce faire nous avons décidé de mettre au point un autre
chier en format LaTeX. Antoine a rédigé ce chier sur lequel il a exprimé sa
propre vision du jeux. Puis ce chier a été révisé par les autres membres du
groupe et a été remanié en conséquence. Ce chier nous a permis d'éviter de
se poser des questions inutiles et de pouvoir se concentrer sur les questions
de fond. Il nous a également permis une progression plus rapide pour toute
la partie graphique de notre jeux.
Même si ce chier n'a pas été suivi à la lettre, les choix devant être décidés
tout le long de l'année ont été rapidement mis en place grâce à ce travail
préliminaire.
1.3.1 Menu du Jeu
Après le lancement du jeu, le menu principal de commande du jeu s'achera. Il comportera diérents onglets, à savoir :
: Lance la nouvelle partie ou la partie en cours que l'on souhaite
charger.
Quitter : Comme son nom l'indique, il permet de quitter proprement le jeux.
Options : C'est l'une des plaques tournantes du jeux. Plusieurs paramètres
sont à régler.
Jouer
- Le contrôle du volume. Cependant, le volume se règle également dans
le jeu, il n'est donc pas utile de le régler dans le panneau d'options.
- Donnée primordiale à règler : le choix du nombre de joueurs pour la
partie, allant de 2 à 6 joueurs.
- Le choix du nom de la partie.
- Autre moment important : décider quel joueur sera humain ou articiel.
EPITA
6
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
- Le choix du nom des joueurs
- Le bouton "Charger", qui permet de revenir au moment où l'on a laissé
la partie avant de quitter.
- Le bouton "Réinitialisation" : Il n'apparaît qu'après l'utilisation du
bouton "Charger", et permet de remettre à zéro les données établies.
- Enn, le bouton "Retour" qui permet de revenir au menu principal.
Deux joueurs seulement ont été prévus lors de la rédaction de ce chier.
Néanmoins, la création d'autres joueurs pourrait se faire rapidement si nous
avons terminé le jeux pour deux joueurs.
1.3.2 Répartition et déplacement des Troupes
Après avoir cliquer sur le bouton jouer, le joueur peut alors se familiariser
avec la répartition aléatoire des diérentes planètes lui ayant été attribuées.
Une fois ceci eectué, il doit placer à sa guise sur ses planètes le nombre de
troupes xées lui étant imparties. Il apparaît alors dans ce que l'on appellera
par la suite le cadran 1, une zone comportant le nombre d'unités disponibles, un emplacement modiable par le joueur an d'ajouter, un bouton
de validation local, validant une répartition du nombre souhaité d'unités, le
transférant vers les planète souhaitées.
Comment les répartir ? ? ? C'est très simple : les planètes que le joueur possède sont entourées par quatre triangles de couleur, permettant l'identication facile. De plus, les planètes adverses sont alors grisées. Enn, vous
remarquerez que dans le coin à droite de chacune des planètes, amies comme
ennemies, se trouvent un chire un rouge : il représente le nombre de ottes
présentes sur la planète. Pour ce faire, il sut donc de cliquer sur les planètes où vous désirez poster vos troupes. Lorsque vous avez terminé, cliquez
sur le bouton suivant pour commencer la phase tant attendu de conquête.
Attention : même si vous n'avez pas placé TOUTES vos troupes, le bouton
suivant engendrera un changement de phase : ne cliquez donc pas avant avoir
vérié.
Enn, il est nécessaire de laisser un intervalle de temps à chaque action
de l'IA.
1.3.3 Phases de Combat
Le système de combat sera similaire à la répartition, à ceci prêt qu'il
visera une planète adverse. Au moins une unité devra toujours rester sur
la planète de départ, alors que les autres seront engagées dans l'arène des
combats. Au terme d'un combat de dés entre les deux eectifs en présence,
la planète cible changera ou non d'appartenance. De petites scènes video
ont été ajoutées, explicitant l'issue du combat. Par ailleurs, les phases de
EPITA
7
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
combat et de déplacement pourront s'entrelacer, car seule la contrainte des
unités gelées permettra de mettre un terme aux actions du joueur, lorsqu'il
n'aura plus de possibilités de déplacement. L'enchaînement des phases se
déroulera de la manière suivante : Déploiement des renforts alliés, Attaques
alliées, Changement de Main, Déploiement des renforts adverses, Attaques
adverses, Changement de Main
.
1.3.4 Fin de la Partie
La victoire est donnée à celui qui possèdera toutes les planètes de la
galaxie.
1.4 Les prévisions pour nos diérentes échéances
Voici le plan que nous avons établi lors de la rédaction du cahier de
charge. Comme vous pourrez le constater, les prévisions ont été quelque peu
modiées au cour des diérentes soutenances, ce qui ne nous a pas empéché
de terminer de façon honorable notre projet...
1.4.1 Découpage du projet
Nos Modules Nous avons tenté de scinder le plus possible notre projet en
diérentes tâches, ce qui nous permettra de répartir plus aisément les rôles
au cours de l'année.
En voici la liste :
Main
Joueur
Réseau
Interface Homme/
Machine (IMH)
IA
Joueur IA
Conguration
Site Web
Programme principal initialisant et gérant les
autres programmes.
Associe les modules de joueur.
Protocole d'émission / réception d'informations
entre joueurs. A faire en dernier lieu.
Prend en compte les actions menées
par le joueur et les traduit pour la machine.s
Intelligence Articielle (Règles, déroulement du
jeu).
Joueur géré par la machine.
Modie dynamiquement la conguration du jeu
(comprend les sauvegardes)
L'IHM comprend entre autres : la gestion des périphériques, la gestion des
Achages à l'écran , le Menu du jeu (avec ses animations et ses commandes
de menus), et le son. C'est donc une des plus grande parties de notre projet.
EPITA
8
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
Diagramme des Modules
Ci contre le diagramme de tous les principaux
modules envisagés, ainsi que leurs interactions.
1.4.2 Répartition
Nous avons décidé de travailler par groupe de deux, an, pensons nous,
d'avancer plus rapidement lors de moments un peu plus délicat. Il est évident
que le groupe se réunira une fois par semaine pour pouvoir suivre les avancées du second groupe. Les modules abordés par chacun au cours de ce projet
sont :
Antoine : Site web, Main, Joueur, IA, Joueur IA
Christopher : IHM, Réseau, Conguration
Patrice : Site web, Main, Joueur, IA, Joueur IA
Thibaut : IHM, Réseau, Conguration
1re soutenance
Delphi
Documentation
Site Web
Librairie graphique
Initiation graphique
Boucle principale
Patrice Antoine Thibault Christopher
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
-
2e soutenance
Boucle principale
Conguration
Joueur
Achage graphique
Gestion des périphériques
Patrice Antoine Thibault Christopher
+
+
+
-
+
+
+
-
+
+
+
+
+
+
3e soutenance
IA
Joueur IA
Joueur IHM
Joueur graphique
EPITA
Patrice Antoine Thibault Christopher
+
+
-
+
+
-
9
+
+
+
+
+
+
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
Soutenance nale
Réseau
Test + débugage
Menu
Setup
Animations + son
EPITA
Patrice Antoine Thibault Christopher
+
+
-
+
+
-
10
+
+
+
+
+
+
+
+
+
+
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
2 Elaboration des graphismes
2.1 Introduction
Bienvenue dans l'univers mythique de Star Wars, alors que la célèbre
carte s'ache devant vous, accompagnée des planètes les plus célèbres de la
galaxie.
La carte comprend une galaxie (pour information la galaxie voisine Andromeda m31x), image de base de 2048 pixels sur 2077. En calques ont été
rajoutés les planètes (dont la disposition est tirée des sources ocielles de
lucaslm), les secteurs, dessinés arbitrairement an de les faire concorder à
l'esprit du jeu, quelques noms des régions les plus connues, les cinq grandes
routes commerciales et enn les liaisons entre les planètes.
2.2 La carte galactique
2.2.1 Pourquoi l'utilisation des calques
Les calques orent l'énorme avantage de modier rapidement et sans détérioration l'image générale : ils peuvent être supprimés, retouchés, ou insérés
à volonté, ce qui a permis naturellement d'apporter quelques modications
nécessaires dues à l'avancement du jeu. En l'occurrence, les planètes sont
implémentées par le code sous forme de sprites, ainsi que leurs noms. De la
sorte, ils ont pu être supprimées du fond de carte, et être placés dans des
palettes de sprites. Il ne reste plus que de la carte les noms de régions, les
limites de ces régions, ainsi que les liaisons :
2.3 Le panneau de lancement
Le jeu commençant à se structurer, il nous a fallut naturellement implémenter le panneau de lancement de notre jeu. Ce dernier n'étant pas
forcément très élaboré, trois boutons susent au bon déroulement de la partie. Le bouton "Quitter" ne devrait pas poser trop de problèmes : il permet
seulement de quitter proprement le jeu.
Le bouton "Lancer le Jeu" permet, vous l'avez compris, de débuter la
partie. Cependant, avant de commencer la partie, il est nécessaire de procéder à quelques réglages, d'où le troisième bouton "Options". En cliquant sur
ce dernier, un autre écran s'ache sous vos yeux, permettant de congurer
à votre guise votre jeu. Tout d'abord, une fenêtre permet de déterminer en
quelle résolution vous désirez lancez le jeu. C'est également ici que se trouve
le bouton nécessaire au réglage du volume. Enn, on y sélectionne le nombre
de joueurs nécessaires à la partie. Cela peut allez de 2 à 6 joueurs, qu'il soit
EPITA
11
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
humain ou articiel.
Les boutons ont été implémentés sous forme d'images TBitmap, à l'instar
du template de la console. Ceci évidemment dans un but d'esthétisme et de
confort pour le joueur. Le fait de mettre des images comme boutons n'a pas
sut, ce pourquoi j'ai poussé le vice jusqu'à prendre en compte le clic sur le
bouton, c'est à dire que l'image du bouton change pendant chaque clic (la
classe...).
2.3.1 Quitter
Ici, en partant du bas, premier bouton, le bouton quitter, qui comme dit
précédemment ferme l'application à partir d'un simple "close" : procedure
TForm1.Image10MouseDown(Sender : TObject ; Button : TMouseButton ;
Shift: TShiftState; X, Y: Integer);
begin
Image11.Visible := true;
end;
procedure TForm1.Image10MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Image11.Visible := false;
sleep(50);
close;
end;
2.3.2 Options
Le second bouton, options, envoie vers une nouvelle fenêtre, contenant la
conguration de base du jeu :
procedure TForm1.Image8MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Image9.Visible := true;
end;
procedure TForm1.Image8MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Image9.Visible := false;
sleep(50);
Form2.visible := true;
end;
EPITA
12
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
Ensuite à partir de la fenêtre de conguration des options de jeu, le bouton retour fonctionne exactement comme les autres, ferme cette fenêtre et
revient à la fenêtre principale de la console.
An de ne pas gérer de tests superus qui permettraient d'éviter que de
fausses valeurs dans les menus déroulants (gérés par des ComboBox Delphi)
soient prises en compte lors du lancement, comme par exemple un texte tapé
par le joueur au lieu qu'une option du menu déroulant soit choisie, ou encore
une option non choisie, il a déjà fallu mettre les champs des ComboBox style
sur "csOwnerDrawVariable" (an de ne pas laisser l'édition activée), et Item
Index sur une valeur par défaut, en entrant dans ce champ l'entier relatif
à la valeur souhaitée. Aussi, pour éviter de gérer un champ supplémentaire
dans les menus déroulants des joueurs (qui aurait été l'option "désactivé"),
an de gérer les cas à moins de 6 joueurs, un test a été mis en place de la
sorte :
procedure TForm2.ComboBox8Change(Sender: TObject);
begin
if ComboBox8.Text = '2 Joueurs' then
begin
ComboBox2.Visible := true;
J1.Visible := true;
Edit1.Visible := true;
ComboBox3.Visible := true;
J2.Visible := true;
Edit2.Visible := true;
ComboBox4.Visible := false;
J3.Visible := false;
Edit3.Visible := false;
ComboBox5.Visible := false;
J4.Visible := false;
Edit4.Visible := false;
ComboBox6.Visible := false;
J5.Visible := false;
Edit5.Visible := false;
ComboBox7.Visible := false;
J6.Visible := false;
Edit6.Visible := false;
end;
EPITA
13
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
{etc pour les autres nombres de joueurs...}
2.3.3 Jouer
Enn, le bouton jouer, qui lance le jeu. C'est le bouton qui nous a posé
le plus de soucis. Initialement, il était prévu de créer pour la console de lancement un exécutable à part, qui devait servir d'initialisation du jeu avant
son réel lancement, ceci pour coller un peu à l'esprit de la séparation du
programme en diverses classes d'objet, et de la séparation très méthodique
des dossiers. Ainsi, la console devait comprendre un dossier à part...
Seulement, c'était sans compter les problèmes qui ont suivi avec la procédure windows ShellExecute, qui lance un exécutable en prenant en compte
un large panel de paramètres. Deux problèmes ont surgi, sur lesquels j'ai
malheureusement bloqué pendant plusieurs semaines sans trouver de solution viable... Le premier de ces problèmes et sans doute le plus bloquant,
consistait à générer une erreur à chaque lancement de l'exécutable principal
("riskstarwars.exe") , erreur d'exception windows suivie d'une erreur interne
au programme. Etonnant étant donné que le programme se lance très bien
manuellement... J'ai essayé de toucher aux paramètres de la procédure, entrer diérentes méthodes, mais rien n'y a fait. Le second problème résidait
dans l'obligation de placer dans les paramètres de la fonction ShellExecute le
chemin d'accès à l'exécutable riskstarwars.exe. Pour que la procédure prenne
en compte correctement le chemin d'accès, j'étais obligé de placer le chemin
complet par adressage total. Or il est logique de penser que l'utilisateur ne
souhaitera pas obligatoirement installer le jeu dans le répertoire par défaut.
J'ai donc bien tenté de placer des adresses locales, cherché comment placer
ces adresses locales, mais pas moyen de trouver quoi que ce soit qui fonctionne (rien ne se lance).
Donc pour palier à ce problème, nous avons résolu d'intégrer la console
de lancement directement dans le programme principal. Le bouton jouer
accompagné de ShellExecute :
procedure TForm1.Image6MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Image7.Visible := true;
end;
procedure TForm1.Image6MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
EPITA
14
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
Image7.Visible := false;
sleep(50);
//ShellExecute(0,'Open','D:\Archives\Autres Documents\Projet\Implémentation
\Risk Star Wars\RiskStarWars\riskstarwars.exe',nil,Nil,SW_MAXIMIZE);
end;
2.4 Création des sprites
Les planètes seront comprises dans le chier racine sous forme de sprite,
an d'être achées convenablement suivant les aléas du jeu. Lorsque par
exemple une unité sera sélectionnée par le joueur, seules les planètes accessibles par l'unité seront achées dans leur forme normale, alors que les autres
seront grisées.
Les noms des planètes ont été crées sous plusieurs couleurs, mais nous
avons plutôt décidé d'entourer les planètes de quatre triangles de couleur
an de connaitre qui possède la dite planète
Les liaisons sont intégrées au fond de carte, n'ayant pas besoin d'être
modiées pour le bon fonctionnement du jeu. Il en va de même pour les
limites de secteurs et les noms de régions .
2.4.1 Les sprites des planètes
Les planètes sont donc mises sous forme de palettes de sprites, comme le
reste des éléments achés ponctuellement. Le fait d'avoir choisi de ne pas
laisser les planètes en images de fond est dû à notre décision de modier
l'état des planètes suivant les sélections eectuées à l'écran par le joueur. En
eet, les planètes pourront être achées à l'écran sous trois formes, à savoir :
Etat normal, lorsque aucune planète n'est sélectionnée, ainsi qu'un
quelconque autre élément.
Etat Gelé : lors des diérentes phases de jeu, le joueur ne peut pas
toujours cliquer sur toutes les planètes de la carte. Par exemple, lors de
la distribution des renforts, il n'est pas utile de cliquer sur les planètes
ennemies, vous le comprendrez aisément. Pour que le joueur ait une
vision claire et rapide de ses capacités, les planètes inutiles seront en
état dit gelé, c'est à dire plus terne que l'état normal.
Etat Surbrillance : Est décrété lorsque le curseur passe au dessus d'une
planète non "gelé". Cet état renforce donc, la visualisation des possibilités des joueurs en question. Un carré orangé se dessine alors autour
de la dite planète.
Dans la palette de sprites de planètes, ces dernières sont positionnées les
unes après les autres à des intervalles de distance réguliers, formant de cette
manière une sorte de tableau de sprites. Les cases dans ce cas précis font
EPITA
15
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
70 x 70 pixels. Les planètes sont classées par ordre alphabétique, et dans
l'implémentation, il sura de créer une fonction mathématique linéaire de
parcours de la palette, comme pour un tableau, et indiquer au programme à
quelle planète correspond quelle distance de parcours.
De plus, les planètes peuvent, comme vu plus haut , subir des modications d'état graphique (normales, gelées ou surbrillance), ce qui implique
donc d'introduire également dans la palette les mêmes planètes, mais suivant les états états : l'état normal et l'état gelé. Deux tableaux de 7 colonnes
chacune ont donc été réalisées.
Une palette de sprites de noms a également été prévue, mais comme nous
avons nalement trouvé le moyen d'acher directement du texte en partant
des fonctions windows de Delphi, nous avons pu acher les noms ded planètes grâce à ce texte.
Au départ les sprites sont tous séparés les uns des autres, c'est à dire qu'ils
ont été créés séparément à partir des calques de la carte, donnant ainsi une
image par planète, et deux images par nom de planète (pour deux joueurs).
Mais charger à l'écran séparément chacun de ces sprites permet de ne pas
implémenter de fonction de parcours d'une éventuelle palette, mais demande
à Direct X de charger un grand nombre de sprites continuellement, alors
qu'avec une palette, il n'aurait que celle-ci à charger. De plus, une fonction
mathématique de parcours rend un code bien plus propre qu'une association
de chier à chaque sprite (il y en aura 60 pour les planètes, et pour le moment 120 pour leurs noms de couleurs diérentes avec deux joueurs, soit 360
si on monte jusqu'à six joueurs, au total 420) deviendrait vite insupportable
à gérer. D'où l'intérêt des palettes de sprites.
Ce qui nous a posé beaucoup de soucis pendant quelques temps est l'achage du texte. En eet, nous ne trouvions pas le moyen d'acher du texte,
car Direct X ne présente pas de fonction appropriée à cette eet. Il était
prévu de créer une police en palette de sprites destinée à être achée, mais
ce moyen en restait néanmoins très lourd, et peu adapté (sauf pour les noms
de planètes). Nous avons tout de même ni par trouver le moyen d'acher
ces polices de caractères en utilisant simplement les fonctions windows de
Delphi.
2.4.2 Les sprites d'unités
An de mieux visualiser le nombre d'unités présentes sur chaque planète,
en plus du nombre qui sera aché à côté de la planète, sera aché un petit
icône d'unité de la couleur du joueur à qui appartient les forces en présence,
EPITA
16
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
qui pourra varier selon le nombre d'unités présentes. Pour le moment comme
convenu : rouge pour l'Alliance Rebelle, et bleu pour l'Empire Galactique.
EPITA
17
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
3 L'achage graphique
3.1 L'Achage Graphique [Direct X sous Direct Draw]
Il a été décidé an d'optimiser grandement les performances du jeu d'implémenter toute la partie code sous forme de classes d'objets Delphi. De cette
manière, nous avons rudement et proprement découpé les pages de codes sous
diérentes classes, à savoir :
- Classe Graphique, qui regroupe tout ce qui a trait à DirectDraw, aux
sprites et à leur achage. Toutes les surfaces DirectDraw sont implémentées à partir de cette classe, et en constituent les objets.
- Classe Main, qui comprend les principales procédures du programme,
procédures constituant son squelette et son initialisation.
- Classe Cong, regroupant les procédures d'enregistrement et de gestion
des paramètres de jeu.
- Classe Joueur, comprenant les procédures liées à la gestion des périphériques, et donc constituant en grande partie l'interface joueur/machine
(IHM).
3.1.1 Les Classes et Objets Delphi
La Programmation Orientée Objets, mieux connue sous l'acronyme de
P.O.O, est très largement répandue et utilisée actuellement. Les objets répondent à ce besoin, en apportant une foule de possibilités très puissantes
qui en font un passage presque obligé dans la majorité des gros projets développés sous Delphi.
Concrètement, un objet est une donnée possédant une structure complexe. On utilisera les objets en utilisant des variables Pascal Objet, comme
cela se fait déjà avec les autres données classiques telles les chaînes de caractères ou les pointeurs. Ces variables contiennent, puisque c'est leur principe
de base, des données et du code Pascal Objet permettant de les traiter.
C'est une des nouveautés marquantes des objets : on peut y stocker des données mais aussi des instructions Pascal Objet. es données consistent en des
variables de n'importe type (y compris des objets). Le code Pascal Objet
est réparti dans des procédures et fonctions nommées méthodes (c'est leur
dénomination dans le monde des objets).
Une classe, un peu comme le fait un type pour une variable, détermine
entièrement la structure des objets de cette classe. Plus précisément, c'est
la classe qui dénit les méthodes et les données (mais pas leurs valeurs)
contenues dans les futurs objets de cette classe. Elle dénit les noms et les
types des données mais pas leurs valeurs.
Chaque objet a ses données dont les noms et types sont déterminées par
la classe, mais dont les valeurs sont indépendantes pour chaque objet.
EPITA
18
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
3.1.2 Procédures de la classe Graphique
Au départ nous comptions acher de façon classique les sprites, c'est à
dire en les collant sur fond de vert (0,255,0). Comme Direct Draw n'ache
que des formes rectangulaires, il s'agit de colorier de cette couleur les zones
à ne pas acher, et de l'indiquer dans les procédures d'achage. Les images
bitmaps ont donc été crées sur fond de Vert 255. Mais il peut résulter quelques
problèmes suivant les cartes graphiques et les conguration individuelles des
utilisateurs, qui peuvent coder les couleurs diéremment, comme par exemple
sur 15 bits, ou encore agir de façon non attendue sur ces mêmes couleurs, et
donc sur ce Vert 255. Il en résulterait donc que Direct Draw ne les acherait
pas, ce pourquoi nous avons utilisé de nouvelles procédures qui permettent
de choisir la couleur de transparence diéremment : le moteur graphique
choisit donc la couleur du premier pixel de la surface graphique à acher
comme couleur de transparence pour le panneau de contrôle, sachant que ce
pixel ne doit pas être aché. De même pour les autres éléments graphiques,
en prenant des pixels qui ne doivent pas apparaître.
Une grande partie des fonctions d'initialisation ont évidemment dues être
trouvées sur la toile.
Types et Variables de la classe :
type
Tgraphique = class
private
FDD: IDirectDraw;
// Interface 1 de DirectDraw
FDD2: IDirectDraw2;
// Interface 2 de DirectDraw
FPrimary: IDirectDrawSurface;
// Surface Primaire representant l'ecran
FBack: IDirectDrawSurface;
// Surface representant le BackBuffer
FCarte: IDirectDrawSurface;
// Surface Hors-Ecran (Offscreen) contenant notre fond
FPanneau: IDirectDrawSurface;
FSprite: IDirectDrawSurface;
// Surface Hors-Ecran contenant notre sprite
public
Pos_x, Pos_y, deplacement_x, deplacement_y: Integer;
procedure DDInitilization(Handle : THandle);
// Inialisation de DirectDraw
procedure LoadBP(var surface : IDirectDrawSurface; chemin : String);
procedure AfficheBP(var surface :
IDirectDrawSurface; x, y, posx, posy, tailleh, taillev : Integer);
EPITA
19
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
procedure DDDisplay;
// Affichage
procedure aff_text(str : String; x, y : Integer);
procedure aff_rect(x1,y1,x2,y2 : Integer);
procedure DDFinalization;
// Libération des objets
end;
var
graph : Tgraphique;
Toute cette implémentation a servi à initialiser les diérents types que
Direct Draw a besoin pour fonctionner. Ces types sont inscrits par défaut
dans les headers directX à installer dans le répertoire lib de Delphi.
procedure Tgraphique.DDInitilization(Handle : THandle);
var
DDSD: TDDSurfaceDesc; // variable de Description de Surface
begin
DirectDrawCreate(nil, FDD, nil);
// Recupere l'interface 1 de DirectDraw dans FDD depuis la DLL
FDD.QueryInterface(IID_IDirectDraw2, FDD2);
//Recupere l'interface 2 de DirectDraw dans FDD2 depuis l'interface 1
FDD2.SetCooperativeLevel(Handle, DDSCL_EXCLUSIVE + DDSCL_FULLSCREEN
+ DDSCL_ALlOWREBOOT);
// Mode Exclusif et Plein ecran
FDD2.SetDisplayMode(WIDTH_SCREEN, HEIGHT_SCREEN, BIT_DEPTH, 0, 0);
// Change de resolution
DDSD.dwSize := SizeOf(TDDSUrfaceDesc);
// Met a jour la taille du Record
DDSD.dwFlags := DDSD_CAPS + DDSD_BACKBUFFERCOUNT;
// indique les champs à consulter lors de la creation de la surface:
CAPS et BACKBUFFERCOUNT
DDSD.ddsCaps.dwCaps := DDSCAPS_COMPLEX
+ DDSCAPS_FLIP + DDSCAPS_PRIMARYSURFACE;
// Capacités de la surface
DDSD.dwBackBufferCount := 2;
// Un seul backBuffer associe à la surface primaire
FDD2.CreateSurface(DDSD, FPrimary, nil);
// Creation de la surface primaire
DDSD.ddsCaps.dwCaps := DDSCAPS_BACKBUFFER;
// Capacite de Back Buffer
FPrimary.GetAttachedSurface(DDSD.ddsCaps, FBack);
// Creation du BackBuffer associé a la surface primaire
EPITA
20
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
loadBP(FCarte, NAME_BACKGROUND);
loadBP(FPanneau, PANNEAU_DE_CONTROLE);
loadBP(FSprite, BOUTON_QUITTER);
// Assignation d'une couleur de transparence (RGB 0 0 0)(Noir)
Pos_x:=0;
Pos_y:=0;
end;
Cette procédure est simplement la procédure qui permet d'initialiser tout
ce qui aura trait à DirectX, an de permettre à DirectDraw d'accéder à tout
ce qui lui sera nécessaire.
procedure Tgraphique.LoadBP(var surface : IDirectDrawSurface; chemin : String);
var wrkbmp:tbitmap;
hret:hresult;
ddsd:ddsurfacedesc;
TempSurface: IDirectDrawSurface;
begin
wrkbmp := tbitmap.Create;
surface := nil;
if not FileExists(chemin) then exit;
wrkbmp.LoadFromFile(chemin);
//creating surface
fillchar(ddsd,sizeof(ddsd),0);
ddsd.dwSize := sizeof(ddsd);
ddsd.dwFlags := ddsd_caps or ddsd_height or ddsd_width;
ddsd.ddsCaps.dwCaps := ddscaps_offscreenplain or ddscaps_videomemory;
ddsd.dwWidth := wrkbmp.Width;
ddsd.dwHeight := wrkbmp.Height;
hret := FDD2.CreateSurface(ddsd,TempSurface,nil);
if hret<>dd_ok then begin
//Erreur_msg('create particle surface');
exit;
end;
try
{we can only get a direct draw surface 3 interface through
the QueryInterface
method of the direct draw surface object}
TempSurface.QueryInterface(IID_IDirectDrawSurface, surface);
finally
{now that we have the direct draw surface 3 object, the
EPITA
21
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
temporary direct draw
surface object is no longer needed}
TempSurface := nil;
end;
//loading bitmap
//result := ddloadbitmap(FDD2,chemin,wrkbmp.Width,wrkbmp.Height);
//if result = nil then Erreur_msg('ddloadbitmap');
CopyBitmap(surface, wrkbmp, 0, 0, wrkbmp.Width, wrkbmp.Height);
//setting the color key for the offscreen surface (upper left corner pixel color)
hret:=ddsetcolorkey(surface,rgb(getrvalue(wrkbmp.Canvas.Pixels[0,0]),
getgvalue(wrkbmp.Canvas.Pixels[0,0]),getbvalue(wrkbmp.Canvas.Pixels[0,0])));
if failed(hret) then begin
//Erreur_msg('ddsetcolorkey');
exit;
end;
//wrkint:=wrkbmp.Width div 16;
wrkbmp.Free;
end;
Cette procédure permet de charger une image de type bitmap dans la
mémoire attribuée par Direct Draw.
procedure Tgraphique.DDDisplay;
var
R1,R2: TRect;
begin
AfficheBP(FSprite,10,10,0,0,64,64);
aff_text('Salut', 10,10);
R1 := Rect(Pos_x, Pos_y, WIDTH_SCREEN_IMG+Pos_x,
HEIGHT_SCREEN_IMG-HEIGHT_PANNEAU_BAS+Pos_y);
// Rectangle de selection faisant tout l'ecran
R2 := Rect(0, 0,WIDTH_SCREEN , HEIGHT_SCREEN - HEIGHT_PANNEAU_BAS + 30);
FBack.Blt(@R2, FCarte, @R1, DDBLT_WAIT, nil);
// copie du contenu de la surface FBackground dans le BackBuffer
R1 := Rect(0, 0, WIDTH_PANNEAU_BAS, HEIGHT_PANNEAU_BAS);
// Rectangle de selection faisant tout l'ecran
R2 := Rect(0, HEIGHT_SCREEN - HEIGHT_PANNEAU_BAS,WIDTH_SCREEN,HEIGHT_SCREEN);
FBack.Blt(@R2, FPanneau, @R1, DDBLT_WAIT or DDBLT_KEYSRC , nil);
aff_rect(700,60,750,90);
EPITA
22
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
FPrimary.Flip(nil, DDFLIP_WAIT);
// Basculement du contenu du BackBuffer dans la surface Primaire
=> affichage
end;
La procédure Tgraphique.DDDisplay copie les images entrées dans la mémoire (FBackground) par le biais de rectangles de sélection, vers le BackBuer (un intermédiaire qui permet de ne pas acher directement à l'écran,
sans quoi il y aurait conit avec ses propres routines). Les images copiées
sont ensuite achées à l'écran : ici le panneau de contrôle.
procedure Tgraphique.aff_text(str : String; x, y : Integer);
var
h_DC : HDC;
font : HFONT;
TempSurface : IDirectDrawSurface;
ddsd : ddsurfacedesc;
fx:TDDBltFX;
R : TRECT;
begin
fillchar(ddsd,sizeof(ddsd),0);
ddsd.dwSize := sizeof(ddsd);
ddsd.dwFlags := ddsd_caps or ddsd_height or ddsd_width;
ddsd.ddsCaps.dwCaps := ddscaps_offscreenplain or ddscaps_videomemory;
ddsd.dwWidth := WIDTH_SCREEN_IMG;
ddsd.dwHeight := HEIGHT_SCREEN_IMG;
FDD2.CreateSurface(ddsd,TempSurface,nil);
FillChar(fx, SizeOf(fx), 0); // clear the structure
fx.dwSize := SizeOf(fx);
// and set its dwSize field
fx.dwFillColor := RGB(0,255,0);
// set the colour for our fill
TempSurface.Blt(nil, nil, nil, DDBLT_WAIT or DDBLT_COLORFILL, @fx);
ddsetcolorkey(TempSurface,rgb(0,255,0));
if TempSurface.GetDC(h_DC) = DD_OK then
begin
font := CreateFont
(45, 0, 0, 0, FW_BOLD, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 'verdana');
SelectObject(h_DC,font);
SetBkColor(h_DC, RGB(0, 255, 0));//RGB(150, 150, 150)
SetTextColor(h_DC, RGB(0, 0, 0));
TextOut(h_DC, 0, 0,pchar(str),strlen(pchar(str)));
DeleteObject(font);
R := Rect(0,0,WIDTH_SCREEN_IMG,HEIGHT_SCREEN_IMG) ;
FCarte.BltFast(x,y, TempSurface, @R, DDBLTFAST_SRCCOLORKEY);
EPITA
23
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
TempSurface.ReleaseDC(H_DC);
end;
end;
Procédure permettant d'acher du texte.
procedure Tgraphique.DDFinalization;
begin // incrementation du compteur de reference pour liberation (COM)
if assigned(FCarte) then
FCarte._AddRef;
if assigned(FPanneau) then
FPanneau._AddRef;
if assigned(FSprite) then
FSprite._AddRef;
if assigned(FBack) then
FBack._AddRef;
if assigned(FPrimary) then
FPrimary._AddRef;
if assigned(FDD2) then
FDD2._AddRef;
if assigned(FDD) then
FDD._AddRef;
end;
Enn, la procédure permettant de mettre n à la routine engrandée par
l'initialisation de DirectX.
Toute cette implémentation de base au niveau de l'achage par directX
permet maintenant d'acher la carte en fond d'écran, de se déplacer sur cette
même carte grâce aux fonctions exposées lors de la première soutenance,
mais aussi d'acher un rectangle d'indication de position sur la minimap du
panneau de contrôle. De plus, grâce aux procédures d'achage des images
bitmap, nous pourrons maintenant acher tous les éléments graphiques disponibles.
3.2 Place à l'achage...
Le troisième chier appelé est le chier graphique.pas. Comme son nom
l'indique, cette partie du programme va gérer toute la partie achage du
jeu. Tout d'abord, elle va enregistrer les coordonnées de la souris. Par de
multiples opérations, elle va ensuite gérer le déplacement de la map, ainsi
que toutes les actions qu'engendrent les cliques aux divers endroits de l'écran
EPITA
24
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
à divers moments du jeu.
Ce qui va suivre permet d'envoyer à l'écran les renseignements textuels
dont le joueur a besoin. Une form de la taille de l'écran est entièrement remplis de noir. Puis, en fonction des besoins, la form va se remplir de pixels de
couleurs formant le texte que l'on souhaite aché.
Dernière étape : la superposition. La map est achée à l'écran, puis
le panneau d'achage, et enn la form précédente, APRES UN LEGER
CHANGEMENT. En eet, tous les pixels noirs de la form NE SONT PAS
CALQUES SUR LE RESTE. Ainsi, seul s'ache le message que l'on souhaitait.
Dernier élément à prendre en compte : L'achage est sujet à maintes erreurs, et les fonctions imbriquées nous empêchent de les détecter rapidement.
Pour éviter cela, si une erreur survient, la fonction s'arrête avec une variable
conservant l'identiant de l'erreur. Toutes les fonctions qui possédaient cette
fonction à leur tour vont s'arrêter en conservant l'identiant. Ce dernier est
ainsi conservé en remontant jusqu'à une fonction Erreur qui termine proprement le programme et ache l'identiant en question.
Voici la partie hautement digeste ! ! ! Bon courage... :
function Tgraphique.init_texte : Hresult;
var
ddbltfx : TDDBLTFX;
ddsd: TDDSurfaceDesc;
begin
fillchar(ddsd,sizeof(ddsd),0);
//creating surface
ddsd.dwSize := sizeof(ddsd);
ddsd.dwFlags := ddsd_caps or ddsd_height or ddsd_width;
ddsd.ddsCaps.dwCaps := ddscaps_offscreenplain or ddscaps_videomemory;
ddsd.dwWidth := WIDTH_SCREEN;
ddsd.dwHeight := HEIGHT_SCREEN;
result := FDD2.CreateSurface(ddsd,Ftexte,nil);
if result<>dd_ok then
exit;
FillChar( ddbltfx, SizeOf( ddbltfx ), 0 );
//ZeroMemory( @ddbltfx, SizeOf( TDDBLTFX ) );
ddbltfx.dwSize := SizeOf( ddbltfx );
ddbltfx.dwFillColor := RGB(0,0,0);//dwColor;
result := Ftexte.Blt( nil, nil, nil, DDBLT_COLORFILL, @ddbltfx );
if result<>dd_ok then
EPITA
25
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
exit;
result := DDSetColorKey(Ftexte, RGB(0,0,0));
if result<>dd_ok then
exit;
//Création des police d'affichages !
{CreateFont(
int nHeight,// logical height of font
int nWidth,// logical average character width
int nEscapement,// angle of escapement
int nOrientation,// base-line orientation angle
int fnWeight,// font weight
DWORD fdwItalic,// italic attribute flag
DWORD fdwUnderline,// underline attribute flag
DWORD fdwStrikeOut,// strikeout attribute flag
DWORD fdwCharSet,// character set identifier
DWORD fdwOutputPrecision,// output precision
DWORD fdwClipPrecision,// clipping precision
DWORD fdwQuality,// output quality
DWORD fdwPitchAndFamily,// pitch and family
LPCTSTR lpszFace // pointer to typeface name string
);}
//petite police rouge
ptrg.font := CreateFont(13,11,0,0,0 ,0,0,0,0,OUT_CHARACTER_PRECIS
,0,0
,FF_MODERN,'Courier New');
ptrg.transparent := True;
ptrg.couleur := RGB(255,0,0); //Rouge
//Grande police rouge
grdrg.font := CreateFont(22,18,0,0, FW_BOLD,0,0,0,0,OUT_CHARACTER_PRECIS ,0,0
,FF_MODERN,'Comic');
grdrg.transparent := True;
grdrg.couleur := RGB(255,0,0); //Rouge
//petite police verte
ptgr.font := CreateFont(13,11,0,0,0 ,0,0,0,0,OUT_CHARACTER_PRECIS
,0,0
,FF_MODERN,'Courier New');
ptgr.transparent := True;
ptgr.couleur := RGB(0,255,0); //vert
//Grande police verte
grdgr.font := CreateFont(22,12,0,0,FW_BOLD ,0,0,0,0,OUT_CHARACTER_PRECIS
,0,0
,FF_MODERN,'Courier New');
grdgr.transparent := True;
grdgr.couleur := RGB(0,255,0); //vert
//Info bulle
EPITA
26
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
infbll.font := CreateFont(16,12,0,0,0 ,0,0,0,0,OUT_CHARACTER_PRECIS
,0,0
,FF_MODERN,'Times new Roman');
infbll.transparent := False;
infbll.couleur := RGB(2,2,2); //gris
infbll.backcolor := RGB(200,200,0); //Jaune
//, grdrg, ptgr, grdgr, infbll
result := dd_ok;
end;
___________________________________________________________________
function Tgraphique.verif_coord(px,py : Integer) : Boolean;
begin
result := (abs(px - coord.cxy.x) < 30) AND (abs(py - coord.cxy.y) < 30);
end;
___________________________________________________________________
function Tgraphique.info_planete(var Planete : T_tplanete) : Hresult;
var
i : byte;
begin
for i := 1 to NB_PLANETE do
if verif_coord(Planete[i].x, Planete[i].y) Then
begin
result := aff_text(Planete[i].nom,
point(coord.xy.x + 32,coord.xy.y), infbll );
if result <> DD_OK Then
exit;
result := aff_text(inttostr(Planete[i].unite) +
' unités', point(coord.xy.x + 32,coord.xy.y + 14), infbll );
if result <> DD_OK Then
exit;
result :=
aff_text(gettypejoueur(Jeu.Joueur.joueur[Planete[i].joueur].typejoueur)
+ ' : ' + Jeu.Joueur.joueur[Planete[i].joueur].nom
, point(coord.xy.x + 32,coord.xy.y + 28), infbll );
if result <> DD_OK Then
exit;
if coord.clic_souris then
affich_pan_dr(i);
end;
if (coord.pxy.x > 2) and (coord.pxy.x < 14) and (coord.pxy.y > 42)
EPITA
27
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
and (coord.pxy.y < 58) then
result :=
aff_text(' Piste suivante ', point(coord.xy.x + 22,coord.xy.y), infbll )
else if (coord.pxy.x > 2) and (coord.pxy.x < 14) and (coord.pxy.y > 59)
and (coord.pxy.y < 70) then
result :=
aff_text(' Piste précédente ', point(coord.xy.x + 22,coord.xy.y), infbll );
if result <> DD_OK Then
exit;
result := DD_OK
end;
___________________________________________________________________
function Tgraphique.affich_pan_dr(plan : byte) : Hresult;
var
i : integer;
begin
if (Jeu.Tour.Etape = DEPLOYEMENT) AND (Jeu.Tour.unite > 0)
AND (Jeu.Tour.Joueur = Jeu.Planete[plan].Joueur) Then
begin
Jeu.Planete[plan].unite := Jeu.Planete[plan].unite + 1;
Jeu.Tour.unite := Jeu.Tour.unite - 1;
end
else
if (Jeu.Tour.Etape = COMBAT)
AND (NOT Jeu.Tour.Attaque.IsComba) Then
begin
if (Jeu.Planete[plan].Joueur = Jeu.Tour.Joueur)
AND (Jeu.Joueur.joueur[Jeu.Planete[plan].Joueur].typejoueur = HUMAIN)
AND (Jeu.Tour.Attaque.planete_depart = 0) AND (Jeu.Planete[plan].unite > 1)
Then Jeu.Tour.Attaque.planete_attaque := plan
else
if (Jeu.Tour.Attaque.planete_attaque <> 0)
AND (Jeu.Planete[plan].Joueur <> Jeu.Tour.Joueur) then
begin
i:=0;
while (i <= NB_LIAISONS)
AND(Jeu.Planete[plan].liaisons[i]<>Jeu.Tour.Attaque.planete_attaque)do
begin
i := i+1;
end;
if i <= NB_LIAISONS then
Jeu.Tour.Attaque.planete_defence := plan;
EPITA
28
InfoSup B2
Unbound
Value
end;
end;
Star Wars Risk
Soutenance Finale
end
___________________________________________________________________
function Tgraphique.efface_texte : Hresult;
var
ddbltfx: TDDBLTFX;
begin
//Efface tous les texte !!!
FillChar( ddbltfx, SizeOf( ddbltfx ), 0 );
//ZeroMemory( @ddbltfx, SizeOf( TDDBLTFX ) );
ddbltfx.dwSize := SizeOf( ddbltfx );
ddbltfx.dwFillColor := RGB(0,0,0);
result := Ftexte.Blt( nil, nil, nil, DDBLT_COLORFILL, @ddbltfx );
if result<>dd_ok then begin
//Erreur_msg('create particle surface');
exit;
end;
result := dd_ok;
end;
___________________________________________________________________
procedure Tgraphique.mini_map;
var
x, y : word;
begin
x := coord.pxy.x;
y := coord.pxy.y;
if (x <> 0) AND (y <> 0) AND
(x >= LONGUEUR_G) AND (x <= LONGUEUR_G + WIDTH_MINIMAP ) AND
(y >= LONGUEUR_B) AND (y <= LONGUEUR_B + HEIGHT_MINIMAP ) Then
//le curseur est sur la mini-map !
begin
x := x - LONGUEUR_G;
if x >= WIDTH_MINIMAP - WIDTH_SCREEN_MINIMAP Then
x := WIDTH_MINIMAP - WIDTH_SCREEN_MINIMAP;
pos_x := x*WIDTH_IMG div WIDTH_MINIMAP;
y := y - LONGUEUR_B;
if y >= HEIGHT_MINIMAP - HEIGHT_SCREEN_MINIMAP Then
y := HEIGHT_MINIMAP - HEIGHT_SCREEN_MINIMAP;
pos_y := y*HEIGHT_IMG div HEIGHT_MINIMAP;
EPITA
29
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
end;
end;
___________________________________________________________________
function Tgraphique.afficher : Hresult;
begin
//Gérer la souris
result := getsouris;
if result <> DI_OK Then
exit;
result := RestoreSurfaces;
//restauration des surfaces Direct Draw si on a perdu les surfaces !
if result <> DD_OK Then
exit;
result := efface_texte;
if result <> DD_OK Then
exit;
//modifier les coordonnée
deplacement;
if coord.clic_souris Then
gestion_clic;
//gérer l'affichage du texte
aff_text(getetat(Jeu.Tour.Etape),
conv_pxy_xy(point(190,50)),ptrg); //étape du jeu
aff_text(Jeu.Joueur.joueur[Jeu.Tour.Joueur].nom,
conv_pxy_xy(point(190,64)),ptrg); //étape du jeu
if Jeu.Tour.unite > 0 Then
aff_text(inttostr(Jeu.Tour.unite) + ' unité(s) à répartir',
conv_pxy_xy(point(190,78)),ptgr);
if Jeu.Tour.Attaque.planete_defence <> 0 Then
aff_text(Jeu.Planete[Jeu.Tour.Attaque.planete_attaque].nom
+ ' attaque ' + Jeu.Planete[Jeu.Tour.Attaque.planete_defence].nom
, conv_pxy_xy(point(190,78)),ptgr);
if Jeu.Tour.Attaque.gain_attaque <> 0 Then
aff_text('Attaquant perd ' + inttostr(Jeu.Tour.Attaque.gain_attaque)
+ ' unité(s)', conv_pxy_xy(point(190,92)),ptgr);
if Jeu.Tour.Attaque.gain_defence <> 0 Then
aff_text('Défenceur perd ' + inttostr(Jeu.Tour.Attaque.gain_defence)
+ ' unité(s)', conv_pxy_xy(point(190,106)),ptgr);
aff_text('QUITTER', conv_pxy_xy(point(240,123)), grdgr);
EPITA
30
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
aff_text(Music.sound_title, conv_pxy_xy(point(40,135)), ptrg);
aff_text('>', conv_pxy_xy(point(4,45)), grdrg);
aff_text('<', conv_pxy_xy(point(4,60)), grdrg);
//aff_musique_position(Music.sound_get_pos);
if (Jeu.Tour.Attaque.planete_attaque <> 0) then
begin
aff_text(Jeu.Planete[Jeu.Tour.Attaque.planete_attaque].nom
, conv_pxy_xy(point(420,50)), ptgr);
aff_text('vs', conv_pxy_xy(point(445,60)), ptgr);
end;
if (Jeu.Tour.Attaque.planete_defence <> 0) then
aff_text(Jeu.Planete[Jeu.Tour.Attaque.planete_defence].nom,
conv_pxy_xy(point(420,70)), ptgr);
aff_planete(Jeu.Planete);
info_planete(Jeu.Planete);
result := flip;
if result <> DD_OK Then
exit;
end;
___________________________________________________________________
function Tgraphique.conv_pxy_xy(xy : Tpoint) : Tpoint;
begin
result.x := WIDTH_SCREEN*xy.x div WIDTH_SCREEN_IMG;
result.y := HEIGHT_SCREEN*xy.y div HEIGHT_SCREEN_IMG +
(HEIGHT_SCREEN - HEIGHT_PANNEAU_BAS*HEIGHT_SCREEN div HEIGHT_SCREEN_IMG);
end;
//modifier cette fonction pour récuperer les coordonées de direct input
function Tgraphique.getsouris : Hresult;
begin
result := Inp.coord(coord.xy, coord.clic_souris );
if result <> DI_OK Then
exit;
coord.pxy := conv_xy_pxy( coord.xy );
coord.cxy := conv_xy_cxy( coord.xy );
end
EPITA
31
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
4 Le moteur de jeu
4.1 L'éditeur XML
Petit programme annexe créé par Patrice, l'éditeur XML de planètes permet de gérer un type spécique de chier XML, prédéni avec les balises adéquates, comprenant les soixante planètes elles aussi prédénies à partir des
balises <planète> et </planète>, pouvant être associées de façon homologue
aux balises <tr> et </tr>. A l'intérieur de ces balises, sont implémentées les
balises <nom> et </nom>, <coords> et </coords>, ainsi que <liaisons>
et </liaisons>, qui peuvent être associés aux balises standards HTML <td>
et </td>, mais qui constituent en plus une sorte d'enregistrement dans un
tableau :
- <Planète>. Constitue la structure XML d'une planète, et englobe
toutes les données internes telles que les coordonnées, le nom et les
liaisons.
- <Nom>. Introduit le nom de la planète, de type string, mais référé à
un index de type entier (un nombre par planète).
- <Coords>. Introduit les coordonées de la planète, de type entier.
- <Liaisons>. Introduit un autre enregistrement de laisons pour la planète spéciée, de type enregistrement d'entiers (les index des autres
noms de planètes).
<nb_planete>60</nb_planete>
<Planete>
<nom>Abregado-Rae</nom>
<coordx>739</coordx>
<coordy>1186</coordy>
<liaisons>
<liaison>4</liaison>
<liaison>14</liaison>
<liaison>15</liaison>
<liaison>25</liaison>
<liaison>51</liaison>
</liaisons>
</Planete>
<Planete>
<nom>Alderaan</nom>
<coordx>1209</coordx>
<coordy>894</coordy>
<liaisons>
<liaison>11</liaison>
<liaison>12</liaison>
<liaison>37</liaison>
EPITA
32
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
</liaisons>
</Planete>
...
...
L'éditeur XML de planètes est capable de lire ce chier, mais ensuite de le
transformer une fois les modications eectuées.
Il comprend donc une sous-fenêtre achant les diérentes planètes (à
partir de la balise <planète>). Une autre sous-fenêtre ache une case modiable, qui est le nom de la planète. De même ensuite pour chaque coordonnée
x et y. La troisième sous-fenêtre est en fait légèrement diérente, comportant
un menu déroulant. Ce menu déroulant permet de choisir un nombre égal à
cinq liaisons vers d'autres planètes. Ce menu déroulant ache donc les noms
de toutes les planètes entrées pour le moment, an de créer des liaisons (le
chier XML de départ est xé à 60 planètes et donc 60 balises <planète>
dénies, an que la première sous-fenêtre ache 60 possibilités modiables,
même vides).
De la sorte, chaque planète se voit associée ses caractéristiques propres et
nécessaires pour le jeu (ici déterminées par les programmeurs). Ainsi, La base
de données concernant les planètes est prête à être utilisée. Aucun problème
majeur n'a par ailleurs été rencontré lors de l'implémentation de cet éditeur,
sauf peut-être un petit bug qui faisait que les liaisons étaient mal acceptées
et souvent "remodelées" à la convenance de l'éditeur... Le bug fut bien sûr
corrigé...
4.1.1 Les procédures de lecture XML
Les procédures qui gèrent la lecture des chiers XML, entre autres le chier planétaire, ou encore les chiers de sauvegarde des données, utilisateur
et logicielles, ou bien d'autres achages comme pour les planètes, seront implémentées très bientôt, c'est à dire dès la seconde soutenance passée.
Voici quelques extraits du code de l'éditeur :
T_planete = record
//type de donnée pour mettre toutres
nom : String;
//les informations sur les planetes
x : Integer;
y : Integer;
liaisons : array[1..NB_LIAISONS] of Integer;
end;
T_tplanete = array[1..NB_PLANETE] of T_planete;
var
Formxml : TFormxml;
EPITA
33
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
Planete : T_tplanete;
tab_liaison : array[1..NB_LIAISONS] of Integer;
tab_liaison_nb, item_modif : Integer;
Il s'agit ici de l'implémentation des types dénis par l'éditeur XML. Ces
types se réfèrent à ce qui a été dit plus haut au niveau des balises.
procedure get_balise(var xml, nom, contenu : String);
//renvoie le nom de la balise courante (1ere Trouvée)
var
bal : String;
pos, posf : Integer;
begin
while (length(xml) <> 0) AND (xml[1] <> '<') do delete(xml,1,1);
pos := 2;
nom := '';
while (length(xml) <> 0) AND (xml[pos] <> '>') do //recupère le nom de la balise
begin
nom := nom + xml[pos];
inc(pos);
end;
inc(pos);
bal := '</'+nom+'>';
posf := AnsiPos(bal, xml);
//posf := posf - length(bal);
contenu := MidStr(xml, pos, posf - length(bal));
xml := rightStr(xml, length(xml) - posf - length(bal) + 1);
end;
La procédure principale get balise permet simplement de lire les strings
xml, d'enlever les balises et de retourner l'intérieur de ces balises.
procedure load_planete(var Planete : T_tplanete; xml : String);
var
contenu, nom, planetecontenu : String;
nb, i : Integer;
begin
nb := 1;
while xml <> '' do
begin
get_balise(xml, nom, planetecontenu);
//writeln(xml);
while planetecontenu <> '' do
begin
get_balise(planetecontenu, nom, contenu);
EPITA
34
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
//writeln(contenu);
get_planete(Planete, nb, nom, contenu);
end;
nb := nb + 1;
end;
end;
Cette procédure permet de charger les informations liées à une planète
dans la forme graphique.
procedure readxml_planete(name : String);
var
filexml : TextFile;
lig, xml, contenu, nom, planetecontenu : String;
nb, i : Integer;
begin
AssignFile(filexml, name);
reset(filexml);
xml := '';
while not eof(filexml) do
begin //cette boucle répètera la lecture d'une ligne tant
que nous n'aurons pas atteint la fin du document EOF
readln(filexml,lig);//à chaque fois que l'on utilisera
readln on passera à la ligne suivante.
xml := xml + supespas(lig); // ajoute notre ligne au memo
end;
closefile(filexml);
try
get_balise(xml, nom, contenu);
if nom = 'nb_planete' then
begin
load_planete(Planete, xml);
end
else
MessageDlg('ERREUR DE FORMAT DU XML !', mtInformation,[mbOk],0);
except
MessageDlg('ERREUR DE FORMAT DU XML !', mtInformation,[mbOk],0);
end;
end;
Procédure achant les propriétés d'un planète.
procedure get_planete
(var Planete : T_tPlanete; nb : Integer; nom, contenu : String);
var
EPITA
35
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
liai : String;
i : Byte;
begin
if nom = 'nom' Then Planete[nb].nom := contenu;
if nom = 'coordx' Then
Try
Planete[nb].x := StrToInt(contenu);
Except
Planete[nb].x := 0;
end;
if nom = 'coordy' Then
Try
Planete[nb].y := StrToInt(contenu);
Except
Planete[nb].y := 0;
end;
if nom = 'liaisons' Then
for i := 1 to NB_LIAISONS do
begin
Try
liai := '';
if (contenu <> '') Then
get_balise(contenu, nom, liai);
if (liai <> '') Then
Planete[nb].liaisons[i] := StrToInt(liai)
else
Planete[nb].liaisons[i] := 0;
Except
on EConvertError do
Planete[nb].liaisons[i] := 0;
else
Planete[nb].liaisons[i] := 0;
end;
end;
end;
Get planète permet de mémoriser les informations entrées pour la planète
sélectionnée.
function set_balise(nom, contenu : String) : String;
begin
result := '<' + nom + '>' + contenu + '</' + nom + '>';
end;
EPITA
36
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
function set_planete(var Planete : T_tplanete; nb : Byte) : String;
var
str : String;
i : Byte;
begin
result := #13#10#9 + set_balise('nom', Planete[nb].nom) + #13#10#9;
result := result + set_balise('coordx', inttostr(Planete[nb].x)) + #13#10#9;
result := result + set_balise('coordy', inttostr(Planete[nb].y)) + #13#10#9;
str := #13#10#9;
for i := 1 to NB_LIAISONS do
if (Planete[nb].liaisons[i] <> 0 ) Then
str := str + #9 +
set_balise('liaison', inttostr(Planete[nb].liaisons[i])) + #13#10#9;
result := result + set_balise('liaisons', str) + #13#10#9;
end;
Procédure permettant de régler les balises dans le XML.
procedure savexml_planete(var Planete : T_tplanete; name : String);
var
filexml : TextFile;
lig, xml, contenu, nom, planetecontenu : String;
i : Byte;
begin
AssignFile(filexml, name);
Rewrite(filexml);
writeln(filexml, set_balise('nb_planete', IntToStr(NB_PLANETE)));
for i := 1 to NB_PLANETE do
begin
writeln(filexml, set_balise('Planete', set_planete(Planete, i)));
end;
closeFile(filexml);
end;
Sauvegarde du chier XML.
Procedure reset_planete(var Planete : T_tplanete);
var
i, j : Integer;
begin
for i := 1 to NB_PLANETE do
begin
Planete[i].nom := '';
Planete[i].x := 0;
Planete[i].y := 0;
EPITA
37
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
for j := 1 to NB_LIAISONS do
Planete[i].liaisons[j] := 0;
end;
end;
Remet les paramètres d'une planète par défaut.
4.2 Les premières fonctions
An de visualiser l'allure générale du code règlant les règles du jeux, nous
avons réalisé une ébauche de jeu fonctionnant sous mode console. Ainsi, le
traitement et la mise en place des fonctions de base (exposées par la suite
dans l'ordre d'implémentation sous Delphi 7) ont été facilités et le travail en
a été restreint à l'implémentation du code même. De cette manière, le travail
a pu être centré sur les diérentes fonctions de départ du jeu sans prendre en
compte une quelconque interface graphique inutile au tout début du projet. Il
faut préciser que ces fonctions ont été créées indépendamment des fonctions
d'initialisation graphique, à partir de DirectX, qui, elles, permettront de
lancer notre propre achage et de le lier par la suite aux autres fonctions du
jeu.
4.2.1 Constantes, Types et Enregistrements
Le nombre total de planètes sera xé à 60, car 60 est divisible par 2, 3,
4, 5 et 6 entraînant la possibilité d'une répartition des planètes entre 2, 3, 4,
5 ou 6 joueurs, ce qui conduit naturellement le nombre de joueurs maximum
à 6(oui oui,on est très fort en calcul mental).
Le nombre de liaisons par planète est xé à cinq, car au delà, la carte
devient une véritable toile d'araignée, et en dessous, le jeu risque de se bloquer, notamment dans le noyau galactique, où la concentration de planètes
est conséquente.
Un type enregistrement a été mis en place pour le moment, qui est le
type T-planete. De la sorte, chaque planète se voit associer plusieurs variables, soit plus précisément 6 :
- La première concerne le nom de la planète, de type string.
- La seconde prend en compte l'abscisse de la planète sur la carte (utile
à la sélection de la planète). Type integer.
- La troisième prend en compte l'ordonnée de la planète sur la carte
(complément à l'abscisse, utile à la sélection de la planète). Type integer.
- La quatrième prend en compte un tableau des liaisons vers les planètes
voisines désignées. C'est cette variable que suivra la fonction de déplaEPITA
38
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
cement des unités, an de savoir vers quelle planètes elles peuvent être
transférées.
- La cinquième annonce soit le nom du joueur, de type string, ou le
numéro du joueur, de type integer.
- La sixième variable annonce le nombre d'unités présentes sur la planète.
Un tableau regroupant les soixante planètes a également été conçu pour
la suite du projet (Array of T-planete).
T_planete = record
//type de donnée pour mettre toutes
nom : String;
//
les information sur les planete
x : Integer;
y : Integer;
liaisons : array[1..NB_LIAISONS] of Integer;
joueur : Byte;
unite : Byte;
end;
T_tplanete = array[1..NB_PLANETE] of T_planete;
4.2.2 Procédure de Distribution Planétaire
La procédure de distribution répartit les planètes entre les joueurs. Elle se
lance donc dès le début d'une partie, et associe chaque planète à un joueur
spécique. Elle compte le nombre de joueurs, puis passe au joueur 1, lui
associe une planète de manière aléatoire, puis passe au joueur 2, fait de
même, et recommence jusqu'à ce qu'il ne reste plus de planète à associer.
Cette procédure utilise deux boucles : l'une fait alterner les deux joueurs,
l'autre, imbriquée, décompte les planètes attribuées.
Procedure joueur_init(var Planete: T_tplanete; joueur: Byte);
var
n: Byte;
i: Byte;
m: Byte;
p: Byte;
begin
Randomize();
p:= NB_PLANETE div joueur;
for n:= 1 to joueur do
//boucle sur les joueurs
for i:=1 to p do // cette boucle choisis a chaque boucle une planete
begin
repeat
// boucle jusqu'a trouver une planete
m:= Random(NB_PLANETE)+1;
until Planete[m].joueur=0;
EPITA
39
InfoSup B2
Unbound
Value
end;
Star Wars Risk
Soutenance Finale
Planete[m].joueur:= n;
end;
4.2.3 Fonction-Procédure d'Achage Planétaire
Cette fonction ache les planètes appartenant au joueur juste après la
répartition. Elle boucle les planètes et regarde à quel joueur elles appartiennent, une par une, et les ache le cas échéant. Elle propose ensuite par
une procédure au joueur de sélectionner une des planètes lui appartenant.
Procedure IHM(var Planete: T_tplanete);
var
i: Byte;
begin
writeln('Repartition des planetes');
for i:= 1 to NB_PLANETE do
begin
writeln(i,') ',Planete[i].nom,'(Joueur ',Planete[i].joueur,')');
end;
end;
4.2.4 Génèse
Cette dernière procédure, qui est en fait la première à agir, crée les planètes et leur associe une place dans le tableau de planètes (T-tab). Ainsi,
elle passe la main à la fonction de distribution.
Procedure init();
var
Planete : T_tplanete;
//variable qui contient toutes les infos
i: Byte;
//variable de boucle
begin
Writeln('');
Writeln('');
writeln('
------------------');
Writeln('
- Risk Star Wars -');
writeln('
------------------');
Planete[1].nom := 'Coruscant'; //initialisation de toutes les
Planete[1].liaisons[1] := 2;
//Planettes avec leurs liasons
Planete[1].liaisons[2] := 3;
Planete[1].liaisons[3] := 7;
Planete[1].liaisons[4] := 8;
EPITA
40
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
Planete[2].nom := 'Tatoine';
Planete[2].liaisons[1] := 1;
Planete[2].liaisons[2] := 3;
Planete[2].liaisons[3] := 10;
Planete[2].liaisons[4] := 5;
Planete[3].nom := 'Endor';
Planete[3].liaisons[1] := 1;
Planete[3].liaisons[2] := 2;
Planete[3].liaisons[3] := 6;
Planete[3].liaisons[4] := 12;
Planete[4].nom := 'Bakura';
Planete[4].liaisons[1] := 9;
Planete[4].liaisons[2] := 11;
Planete[4].liaisons[3] := 5;
Planete[4].liaisons[4] := 2;
Planete[5].nom := 'Dagobah';
Planete[5].liaisons[1] := 3;
Planete[5].liaisons[2] := 2;
Planete[5].liaisons[3] := 8;
Planete[5].liaisons[4] := 6;
Planete[6].nom := 'Géonosis';
Planete[6].liaisons[1] := 3;
Planete[6].liaisons[2] := 5;
Planete[6].liaisons[3] := 9;
Planete[6].liaisons[4] := 11;
Planete[7].nom := 'Agamar';
Planete[7].liaisons[1] := 1;
Planete[7].liaisons[2] := 10;
Planete[7].liaisons[3] := 11;
Planete[7].liaisons[4] := 12;
Planete[8].nom := 'Yavin';
Planete[8].liaisons[1] := 1;
Planete[8].liaisons[2] := 5;
Planete[8].liaisons[3] := 9;
Planete[8].liaisons[4] := 11;
Planete[9].nom := 'Naboo';
Planete[9].liaisons[1] := 4;
Planete[9].liaisons[2] := 6;
Planete[9].liaisons[3] := 8;
Planete[9].liaisons[4] := 10;
Planete[10].nom := 'Dathomir';
Planete[10].liaisons[1] := 2;
Planete[10].liaisons[2] := 7;
Planete[10].liaisons[3] := 9;
EPITA
41
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
Planete[10].liaisons[4] := 12;
Planete[11].nom := 'Dantoine';
Planete[11].liaisons[1] := 4;
Planete[11].liaisons[2] := 6;
Planete[11].liaisons[3] := 7;
Planete[11].liaisons[4] := 8;
Planete[12].nom := 'Dath';
Planete[12].liaisons[1] := 3;
Planete[12].liaisons[2] := 7;
Planete[12].liaisons[3] := 10;
Planete[12].liaisons[4] := 0;
for i:= 0 to NB_PLANETE do
begin
Planete[i].joueur := 0;
Planete[i].unite := 1;
end;
joueur_init(Planete,NB_JOUEUR);
IHM(Planete);
readln;
Writeln('Répartition des troupes');
for i:=1 to NB_JOUEUR do
begin
writeln('Joueur ',i);
joueur_unite(Planete,10,i); //repartition initial des troupes
end;
main(Planete);
//passe la main à la fonction main
end;
4.2.5 Répartition des unités
Cette procédure est naturellement nécessaire pour la partie renfort. Elle
nous indique le nombre de troupes disponible, puis passe en revue chaque
planète en demandant au joueur combien d'unités il désire positionner sur
cette planète. De plus, le nombre d'unités restantes est à chaque fois réafcher, et l'on ne peut mettre plus d'unités que ce qui nous est permis. On
ne pouvais revenir sur une planète que nous avions déjà "visitée" et on ne
pouvait choisir la planète désirée : elle nous était obligatoirement desservie.
Elle sera donc bien évidemment révisée pour les besoins du jeu.
Procedure joueur_unite(var Planete : T_tplanete; unite , joueur : Word);
var
i, num : Byte;
EPITA
42
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
begin
writeln('-------------- Distribution des unite -------------');
for i:= 1 to NB_PLANETE do
begin
if (Planete[i].joueur = joueur) and (unite > 0) Then
begin
writeln('Il vous reste ', unite, ' unites a repartir.');
write(Planete[i].nom, ' :',Planete[i].unite,' unites + ');
readln(num);
if unite <= num then
begin
Planete[i].unite := Planete[i].unite + unite;
unite := 0;
end
else
begin
Planete[i].unite := Planete[i].unite + num;
unite := unite - num
end;
end;
end;
Writeln('Fin de la répartition');
end;
4.2.6 Procédure de combat
Elle permet d'attaquer une planète adverse grâce à un eet de randomisation, ce qui remplacera les dés dans le jeu de plateau.
procedure joueur_comba(var Planete: T_tplanete; plan_att, plan_def: Byte);
var
de, unite_att, inute_def : Byte;
annul : Boolean;
begin
Randomize();
annul := True;
repeat
writeln('Joueur ', Planete[plan_att].joueur,
' : Combien d_unite voulait vous utilisé (1-',
Planete[plan_def].unite - 1, ') ?');
readln(unite_att);
until unite_att < Planete[plan_att].unite;
unite_def := Planete[plan_def].unite;
Planete[plan_att].unite := Planete[plan_att].unite - unite_att;
EPITA
43
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
while annul AND (unite_att > 0) AND (unite_def > 0) do
begin
writeln('Attaque de la planete ', Planete[plan_def].nom);
de := Random(3);
if de = 0 Then
begin
unite_def := unite_def - 2;
writln('Joueur ', Planete[plan_def].joueur, ' pert 2 unite');
end;
else if de = 1 Then
begin
unite_att := unite_att - 2;
writln('Joueur ', Planete[plan_att].joueur, ' pert 2 unite');
end;
else
begin
unite_att := unite_att - 1;
unite_def := unite_def - 1;
writeln('Chacun joueur pert une unite');
end;
if unite_att=0 then
begin
writeln('Joueur ', Planete[plan_att].joueur, ' pert 2 a gagne !');
Planete[plan_def]
end;
end;
end;
4.2.7 Finalité du Programme
Ce petit programme nous a donc permis une approche relative du problème, mais néanmoins signicative. Bien que cette application soit extrêmement limitée, elle nous a permis de poser de solides bases et d'avoir un très
net aperçu de ce qui servira de ciment à toute l'implémentation découlant
de ces fonctions de base. Ce programme peut s'approcher de la procédure
ultérieure qui initialisera le début d'une partie de notre jeu.
4.3 Le moteur de jeu
Premier chier appelé : le chier joueur.pass, où sont réunis toutes les
fonctions et procédures relatives aux règles du jeu. C'est dans ce chier que
sont répertoriées et déterminées toutes les actions. Par exemple, c'est grâce
à ce chier que l'on peut déployer ces troupes, attaquer les planètes ennemis,
etc...
EPITA
44
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
Ce chier consiste lui aussi en une boucle qui va déterminer dans quelle
phase de jeu le joueur ce trouve et le rediriger vers les actions possibles.
Lorsque la phase est terminée, le programme reboucle et redirigeant le joueur
vers la phase qui s'ensuit. Tant que la phase n'est pas terminée, le programme
va réaccompagner le joueur jusqu'à ce qu'il juge avoir terminer la phase.
Un élément à tenir compte : tous les joueurs sont incrémentés d'un chire,
allant, cela va de soit, de 1 à 6. De plus, une variable est attribuée à chaque
joueur. Cette variable est un booléen qui permet de déterminer si un joueur
joue ou pas. Pour être plus claire, si des joueurs ne sont pas présents au début
de la partie (exemple : la partie se déroule à trois joueurs, donc les joueurs 4,5
et 6 ne jouent pas), ce booléen est vraie. Les autres joueurs ont leur variable
à faux. Si un joueur perd en cour de partie, sa variable passe également à vrai.
Ainsi, à chaque fois que le joueur actif signale que ça phase de redéploiement est terminée, le programme va vérier si le joueur suivant, c'est à dire
le joueur comportant le chire suivant, a sa variable à faux. Dans ce cas, le
programme reboucle avec ce joueur qui démarre alors sa phase de déploiement. Dans le cas contraire, la boucle recommence avec le joueur suivant.
Remarques : Si c'était le joueur possédant le chire le plus haut des
joueurs encore en lice, la boucle reboucle avec le "premier" de la liste. De
plus, si le joueur laissant sa place est redésigné car tout les autres ont leur
booléen a vraie, le joueur a donc ni la partie.
Voici quelques fonctions revêtant une importance extrême :
procedure TJeu.Tourjeu;
begin
if Tour.Etape = DEPLOYEMENT Then
jeu_deployement
else
if Tour.Etape = COMBAT Then
jeu_combat
else
jeu_deplacement;
if Tour.Fin then
begin
if Tour.Etape = DEPLOYEMENT Then
fin_deployement
else
if Tour.Etape = COMBAT Then
EPITA
45
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
fin_combat
else
begin
fin_deplacement;
repeat
Tour.Joueur := Tour.Joueur + 1;
if (Tour.Joueur > 6) then
Tour.Joueur := 1;
until not Jeu.Joueur.joueur[Tour.Joueur].perdu;
Inc(Tour.Tour);
reinitialise;
end;
Tour.Fin := False;
inc_etape(Tour.Etape);
finjeu;
end;
appeljoueur;
end;
___________________________________________________________________
procedure TJeu.definir_de(var de_a, de_a1, de_a2, de_a3, de_d, de_d1, de_d2 : Byte);
begin
randomize();
de_a := 3;
if Planete[Tour.Attaque.planete_attaque].unite - 1 < 3 Then
de_a := Planete[Tour.Attaque.planete_attaque].unite - 1;
if de_a <= 0 then //pas assez d'unité pour jouer
begin
Tour.Attaque.planete_attaque := 0;
Tour.Attaque.planete_defence := 0;
Tour.Attaque.resultat := PLUS_DUNITE;
Tour.Attaque.continuer := False;
end;
de_d := 2;
if Planete[Tour.Attaque.planete_defence].unite < 2 then
de_d := 1;
de_a1 := de;
de_d1 := de;
if de_a > 1 Then
de_a2 := de
else
de_a2 := 0;
if de_a > 2 Then
EPITA
46
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
de_a3 := de
else
de_a3 := 0;
de_d1 := de;
if de_d > 1 Then
de_d2 := de
else
de_d2 := 0;
end;
___________________________________________________________________
procedure TJeu.faire_comba;
var
de_a, de_a1, de_a2, de_a3, de_d, de_d1, de_d2 : Byte;
begin
Tour.Attaque.tour := Tour.Attaque.tour + 1;
Tour.Attaque.resultat := COMBAT_NON_FINI;
Tour.Attaque.IsComba := True;
definir_de(de_a, de_a1, de_a2, de_a3, de_d, de_d1, de_d2);
if max(de_d1, de_d2) >= max3(de_a1, de_a2, de_a3)
Then //le defenceur gagne une unité !
comba_repartir(tour.attaque.gain_defence, tour.attaque.gain_attaque,
Tour.Attaque.planete_defence, Tour.Attaque.planete_attaque)
else //sinon c'est l'attaquand !
comba_repartir(tour.attaque.gain_attaque, tour.attaque.gain_defence,
Tour.Attaque.planete_attaque, Tour.Attaque.planete_defence);
if (de_d > 1) AND (de_a > 1) Then //Si chaque joueur à + de 2 dé !
begin
if min(de_d1, de_d2) >= moy3(de_a1, de_a2, de_a3)
Then //le defenceur gagne une unité !
comba_repartir(tour.attaque.gain_defence, tour.attaque.gain_attaque,
Tour.Attaque.planete_defence, Tour.Attaque.planete_attaque)
else //sinon c'est l'attaquant !
comba_repartir(tour.attaque.gain_attaque, tour.attaque.gain_defence,
Tour.Attaque.planete_attaque, Tour.Attaque.planete_defence);
end;
Tour.Attaque.continuer := False;
end;
EPITA
47
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
5 L'intelligence articiel
Jouer avec des amis à se casser la gure dans toute la galaxie pendant 2
ou 3 heures, c'est bien ! ! ! Encore faut-il en trouver un... Et c'est là que l'idée
géniale nous éclaira ! Jouer avec son PC, s'en faire un ami ! ! ! Bon d'accord,
je vais un peu trop loin... Donc, place à l'IA.
5.1
Le déploiement des troupes
Tout d'abord, un bref récapitulatif : notre jeu se déroule en fonction de
tours de jeu, qui lui même est scindé en diérentes parties : la répartition
des troupes nouvellement créées et la phase d'attaque. Nous n'avons pas eu
le temps matériel de nous occuper de la phase de redéploiement, même si
nous pensons que l'impllémentation aurait été rapide.
En réalité, tout se décide durant la phase de déploiement. La première
phase consiste à lister l'ensemble des planètes qu'il possède. Ensuite, et c'est
la partie la plus importante, il va calculer pour chacune d'elle un Heuristique, un coecient qui sera basé sur plusieurs critères, et qui permettra de
savoir quelle planète est susceptible d'être la plus intéressante pour lancer
une oensive. Puis les planètes sont trièes selon leur coecient heuristique.
Ainsi, celle qui a le plus fort coecient est celle qui OBLIGATOIREMENT
attaquera lors de ce tour...
Chacune des planètes possédées par l'ordinateur se trouvant en contact
de ces planètes ennemies et ne possèdant qu'une unité recevra automatiquement une deuxième unité lors de la phase de déploiement. Les autres unités
alouées lors du début du tour seront réparties en fonction des planètes qui
attaqueront lors de ce tour. Ex : la planète possédant le plus fort coecient
possédera 5 troupes sur son territoire si la planète ennemie en possède 3,
an attaquer dans des conditions agréables... Il est évident de l'IA posséde
un nombre limité de recrue, ce qui nous donne une chance de gagner...
EPITA
48
InfoSup B2
Unbound
Value
5.2
Star Wars Risk
Soutenance Finale
La phase d'attaque
La phase d'attaque est plus facile à gérer. Le choix de la ou des planètes
allant attaquer ayant déja été réalisé, l'IA va directement passer à l'attaque.
Il va tout de même s'arranger pour laisser des troupes an de défendre proprement la planète. A l'issue du premier tour de combat, il va vérier s'il est
intéressant de réattaquer la planète. Il ne s'arrêtera que lorsque la planète
sera prise ou lorsqu'il ne jugera plus utile de l'attaquer. Il est évident qu'il
ne va pas s'acharner s'il a moins de troupes sur sa planète que sur la planète
ennemie...
Au niveau même de l'attaque, l'IA est obligée d'attaquer avec le plus
grand nombre de troupes possible, à savoir 3 s'il peut attaquer avec 3 troupes
ou plus, 2 s'il n'en a que 2, et 1 s'il décide que cela en vaut la peine... Si
vous connaissez le jeu en version plateau, vous savez que l'issue du combat
dépend du résultat d'un jet de la part des diérents partis. A votre grand
étonnement, j'en suis sûr, cela se passera de la même manière dans notre
jeu ! ! ! Les dès seront simulés par la sortie d'un nombre aléatoire. Si le défenseur à deux troupes ou plus, deux dès imaginaires sont jetés, dont chaque
résultat est conservé. L'attaquant lui, oppose soit deux unités, auquel cas il
"lancera" deux dés, soit trois unités ou plus, et un 3ème dé est ajouté. Le
maximum des résultats du défenseur est comparé au maximum des résultats
de l'attaquant, et le minimum du défenseur est opposé au médium ou au
minimum selon que l'attaquant ait placé trois troupes ou deux. Lorsque le
défenseur n'a qu'un dè à opposer, la deuxième phase ne se réalise pas. Pour
chacune des comparaison, le défenseur perd une unité si son jet est STRICTEMENT inférieur au jet adverse. Dans le cas contraire, c'est l'attaquant
qui perd une unité.
EPITA
49
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
6 La mise en place du son
Que serait un jeu Star Wars sans sa musique incontournable ? ? ? Cette
musique que tout le monde fredonne après avoir regardé un des lms mythiques. Nous nous devions d'insérer dans notre jeu les chefs d'oeuvre de
John Williams. Cependant, cela nous ce t pas sans diculté...
Pour ce faire, nous avons utilisé fmod, un logiciel qui permet de lire en
screan tous les mp3 que nous décidons d'insérer dans sa bibliothèque. Il permet la lecture de beaucoup de format de musique et facilite grandement la
gérance de la musique. De plus, de nombreux services annexes sont disponibles, telles que la récupération du spectres des diérentes musique. Cela
nous a permis une très grande liberté dans le choix et dans l'installation de
la musique.
La musique nous paraissant décidément incontournable, nous avons décidé d'insérer un juke box dans la partie droite de notre boite de commande.
Plusieurs fonctions sont prévues et implémentées, telles que l'initialisation
de la musique, le passage à la musique précédente ou suivante, la mise en
pause ou l'arrêt de la musique, et la visualisation du titre de la musique sur
le moment écoutée.
Cependant, nous avons été confronté à beaucoup de problèmes quand à
la mise en place dans le jeu même. Tout d'abord, nous avons fait en sorte
d'ouvrir un canal à chaque fois que la musique précédente devait s'arrêter,
ce canal recevant la musique suivante. Petit problème : à chaque boucle,
le code était fait en sorte que la musique précédente était soit disant terminé à chaque boucle, ce qui signiait qu'à chaque boucle du jeu, un canal
était ouvert, SANS REFERMER LE CANAL PRECEDENT. Conclusion :
beaucoup de résultats forts désagréables. De plus en plus de canaux s'ouvraient, produisant en quelques instants un grésillement. Mais ce n'était pas
le plus dramatique. Car lorsqu'un canal s'ouvre, la musique est charger dans
la mémoire virtuelle du jeu. Conclusion nale : la mémoire nissait par être
surchargée, entrainant une erreur critique (reboot). Le problème a été résolu
en lançant la musique suivante sur le même canal(simple, mais ecace).
Un autre problème qui nous a dérangé pendant plusieurs heures était en
réalité une condition toujours réalisée, entrainant ainsi un passage à la chanson suivante à chaque tour de boucle : dicile dans ces conditions d'écouter
proprement une musique ! ! !
EPITA
50
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
Pour la soutenance nale, le spectre orne désermais le tableau de commande du jeu, et des bruitages tels que des paroles de R2D2 ont été rajoutés.
EPITA
51
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
7 Notre site web
Notre site comporte deux parties principales : une est réservée au public,
l'autre à l'administration du site. Voici sans plus attendre la brève récapitulation du travail fait.
7.1
Site Publique (http ://risk.star.wars.free.fr/))
Le site publique est maintenant en ligne, à l'adresse url décrite dans le
sous-titre. Il est optimisé pour une résolution de 1024 par 728, et connaît
actuellement quelques problèmes avec le navigateur Internet Explorer au niveau d'un mauvais dimensionnement des cellules vis à vis des images de fond
(dans la barre de titre). Il fonctionne parfaitement sous le navigateur Firefox,
et n'a pas été testé sous d'autres.
Le site est séparé en plusieurs sections :
- L'onglet Accueil, où les nouvelles sont éditées à partir de l'éditeur de
News interne.
- L'onglet Groupe, où le groupe de projet est présenté.
- L'onglet Projet, où le projet est présenté.
- l'onglet Tuto DirectX, qui est un tutorial en construction sur DirectX,
et plus particulièrement DirectDraw.
- L'onglet Téléchargement, où les diérentes versions de nos exécutables
et de nos sources sont disponibles, ainsi que les rapports de soutenance
et le cahier des charges, plus d'autres documents écrits.
- L'onglet de Liens, qui apporte tout simplement des liens utiles vers
d'autres projets précédents ou actuels, des sites complets sur DirectX
ou Delphi, le site de l'EPITA (si si...), etc...
7.2
Administration Interne (http ://risk.star.wars.free.fr/admin/)
Le site publique est entièrement géré par une structure php d'administration, qui permet de garder une seule page htlm qui concerne le squelette
du site (Header, barre de séparation et autres objets graphiques), sans avoir
à le modier pour chaque page. L'administration permet également de gérer
tout le contenu du site, grâce à tout un système d'édition php de news et
d'articles. Chaque article peut être gérer séparément par deux options distinctes : supprimer et modier. Un nouvel article peut être introduit avec
une option supplémentaire : créer. De plus, chaque article correspond à l'un
des onglets du site publique. Il est également possible à partir de cette interface d'administration depuis la première soutenance de correspondre par
messages entre les membres inscrits sur cette même interface.
EPITA
52
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
8 L'installation et la désinstallation
Nous avons utilisé le logiciel inno setup 5, nous permettant de créer facilement des programmes d'instalation et de désinstalation. De plus, il représente
l'énorme avantage d'être gratuit...
EPITA
53
InfoSup B2
Unbound
Value
Star Wars Risk
Soutenance Finale
9 Conclusion
Voilà, nous arrivons nalement à l'échéance nale. Nous avons eu la
chance que chacun, avec ses possiblités, aide jusqu'au bout pour la réalisation du projet.
Concrètement, qu'est ce que ce travail de groupe nous a apporté durant
le long de l'année ? Et bien justement, réaliser ce qu'est un travail de groupe.
Il nous a fallut apprendre à tenir des échéances, à accepter nos retards et à
rebondir pour le rattraper. Lorsque nous nous heurtions à des dicultés, il
nous a fallut prendre notre mal en patience puis, une fois le problème résolu,
mettre les bouchées doubles pour rattraper ce que l'on avait prévu de faire.
Nous avons appris également à nous mobiliser entièrement sur un projet. Pour preuve, alors que le projet peinait à avancer lors de la première et
deuxième soutenances, la cadence et les résultats se sont grandement accrus
lors des deux dernières soutenances, nous stimulant encore plus dans notre
démarche. Notre façon de penser a peu à peu changer au cours des mois,
demandant de plus en plus de résultats concrets.
Enn, nous avons appris à discuter et à trouver des solutions intermédiaires à des divergences d'opinion entre les membres du groupe, chose que,
pauvres français, avons bien du mal à mettre en pratique...
Concrétement, comment a évoluer notre projet ? Nous avons pris beaucoup de retard en début d'année, aussi avons nous dû abandonner quelques
idées, notamment la possibilité de jouer en réseau, la troisième étape de redéploiement, ou bien encore le fait de choisir le nombre d'unités conquérant
une planète ennemie.
En revanche, la perception de notre jeu ayant légérement changer vers
l'esthétisme, nous avons rajouté des lms, des clips et des musiques. L'un
dans l'autre, nous pensons avoir tout de même fourni un projet d'assez bonne
qualité, même si malheureusement il ne répondait pas tout à fait au cahier
des charges initial.
EPITA
54
InfoSup B2

Documents pareils