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 12 Mai 2005
1
Unbound
Value
Star Wars Risk
Troisième Soutenance
Table des matières
1 Récapitulation des 1ère et 2ème soutenances
3
2 Le panneau de lancement
5
3 Le Jeu
9
1.1 La 1ère soutenance . . . . . . . . . . . . . . . . . . . . . . . .
1.2 La 2ème soutenance . . . . . . . . . . . . . . . . . . . . . . . .
1.3 Les prévisions pour la 3ème soutenance . . . . . . . . . . . . .
2.1 Quitter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2 Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3 Jouer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.1
3.2
3.3
3.4
Le moteur de jeu . .
L'IA en action . . .
Place à l'achage...
...et pour nir le son
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
3
4
5
6
7
. 9
. 12
. 12
. 20
4 Place au son...
21
5 L'Intelligence Articielle
23
5.1 Le déploiement des troupes . . . . . . . . . . . . . . . . . . . . 23
5.2 La phase d'attaque . . . . . . . . . . . . . . . . . . . . . . . . 24
5.3 Le redéploiement des troupes . . . . . . . . . . . . . . . . . . . 24
EPITA
2
InfoSup B2
Unbound
Value
Star Wars Risk
Troisième Soutenance
1 Récapitulation des 1ère et 2ème soutenances
1.1
La 1ère soutenance
La première soutenance a surtout été marquée par la mise en place du
groupe. Il a fallu nous organiser et mettre en place des règles de conduite
pour toute la durée du projet. Peu de choses ont été faites concrètement sur
le projet, mais cette période a surtout été le temps dévolu à la conception
du jeu. Nous avons donc rééchi à l'ensemble des éléments que l'on désirait
implémanter dans notre jeu. C'est pourquoi notre première tâche a été de
réaliser un chier récapitulant toutes les règles et toutes nos envies au niveau
graphique comme au niveau conceptuelle.
Cependant, rien ne vaut tout de même un peu de concret pour commencer avec ardeur. C'est pourquoi Thibault a réalisé les premières ébauches de
la carte galactique nous servant de support pour l'ensemble du jeu. La map
étant tout de même assez grande, il nous a fallu rapidement nous déplacer
sur la carte, ce qui fut fait par la même occasion. L'achage des calques et
des sprites fut implémenté, et le panneau de contrôle a vu le jour.
L'idée qui nous ait venue pour la réalisation du projet était d'implémanter quelques fonctions de base en mode console, sans se préoccuper davantage
pour le moment de l'aspect graphique. Des enregistrements ont été mis en
place, avec le nom de la planète, ses coordonnées, les liaisons possibles avec
les planètes voisines, à qui appartient la planète, ... Une fonction nous a
permis de répartir toutes les planètes entre les joueurs en début de jeu. Une
autre achait l'ensemble des planètes que possédait un joueur. Une autre
terminait proprement le jeu. Une quatrième créait en elle même les planètes
et les insérait dans un tableau. La répartition des troupes et l'arontement
aléatoire ont été implémantés.
Enn, le début de notre site a vu le jour ; Il sera largement étoé lors de
la seconde soutenance.
1.2
La 2ème soutenance
Lors de la deuxième soutenance, il nous a fallut pratiquement terminer
la carte. La méthode des sprites a été largement utilisée pour tout ce qui
devait s'acher de manière ponctuelle. Pour chaque planète, trois états ont
EPITA
3
InfoSup B2
Unbound
Value
Star Wars Risk
Troisième Soutenance
été réalisés, avec leur sprite respectif : l'état gelé, qui nous permettra visuellement de voir l'impossiblité de cliquer sur cette planète, l'état dit normal,
et l'état dit de surbrillance, lorsque la souris passe sur l'une des planètes à
l'état normal. Des sprites d'unités de diérentes couleurs pour symboliser
les joueurs ont été créés. Il nous a fallut nous poser beaucoup de questions
d'ordre techniques, en particulier pour l'achage de mots sur la carte, ou
tout simplement pour rechercher una ecacité et un temps de chargement
le moins grand possible. Enn, le panneau de contrôle a été mis en place,
entrainant des petites, mais primordiales, modications de la carte.
An d'améliorer les performances du jeu, il a été décidé de former sous
Delphi des classes d'objets, que voici : la classe Graphique, la classe Joueur,
la classe Main, et la classe Cong. Chacune d'entre elles possède des objectifs bien dénis. Ainsi, beaucoup de fonctions ont été implémentées ou
réimplémentées avec ces classes, an notamment de charger correctement et
rapidement la map.
Pour stocker toutes les données relatives au jeu, nous avons décidé d'utiliser le système de chier XML. Un programme que l'on a nommé Editeur
XML (oui le nom est très recherché !) nous permet de gérer ecacement
toutes les données pour chaque planète présente dans le jeu. Il peut bien sur
lire les chiers XML, mais, élément primordial, également le modier.
Comme nous le disions dans le chapitre précédent, c'est lors de la 2ème
soutenance que le site a réellement été développé. Le voici donc près à être
lu par tous les internautes. Bien sûr, il faut maintenant encore l'étoer, mais
tous les onglets sont mis en place. A noter cependant que la partie administrative du site a été programmer pour nous permettre de modier très
rapidement notre site, ce qui est quand même bien pratique...
1.3
Les prévisions pour la 3ème soutenance
L'enjeu était simple : faire en sorte que le jeu fonctionne lors de la 3ème
soutenance ! ! ! Pour ce faire, nous devions installer un moteur graphique complet et opérationnel et créer l'Intelligence Articielle de notre jeu.
EPITA
4
InfoSup B2
Unbound
Value
Star Wars Risk
Troisième Soutenance
2 Le panneau de lancement
Le jeu commence à se structurer, et naturellement il nous a fallut 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 "Conguration". 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 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
d'agréable pour le joueur (qui a dit marketing... ?). 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 (pour la classe)...
2.1
Quitter
Ici, en partant du bas, premier bouton, le bouton quitter, qui comme dit
précédemment femre 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;
EPITA
5
InfoSup B2
Unbound
Value
2.2
Star Wars Risk
Troisième Soutenance
Options
Le second bouton, options, envoie vers une nouvelle fenetre, 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;
Ensuite à partir de la fenêtre de conguration des options de jeu, le
bouton retour fontionne 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 ItemIndex 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;
EPITA
6
InfoSup B2
Unbound
Value
Star Wars Risk
Troisième Soutenance
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;
{etc pour les autres nombres de joueurs...}
2.3
Jouer
Enn, le bouton jouer, qui lance le jeu. C'est le bouton qui a posé le plus
de soucis, et qui d'ailleurs en pose encore actuellement. 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
spéaration 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 éxé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 correcetement le chemin d'accès, j'étais obligé de placer le cheEPITA
7
InfoSup B2
Unbound
Value
Star Wars Risk
Troisième Soutenance
min 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
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;
EPITA
8
InfoSup B2
Unbound
Value
Star Wars Risk
Troisième Soutenance
3 Le Jeu
Tout ce que nous vous avons présenté est bien joli, maus jusque là nous
vous avons jamais présenté le jeu en lui même, ce qui est gênant... Nous
allons donc tenter d'expliciter au mieux le corps même de notre jeu...
Le jeu consiste en une gigantesque boucle principale, qui ne s'arrêtera
que lorsqu'il apparaît une erreur, que le joueur désire quitter le jeu ou qu'un
joueur gagne la partie. Que fait cette boucle ? ? ? Elle appelle les fonctions
subalternes nécessaires au jeu.
3.1
Le moteur de jeu
Première 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... 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 unn 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.
EPITA
9
InfoSup B2
Unbound
Value
Star Wars Risk
Troisième Soutenance
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
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;
EPITA
10
InfoSup B2
Unbound
Value
Star Wars Risk
Troisième Soutenance
___________________________________________________________________
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
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;
EPITA
11
InfoSup B2
Unbound
Value
Star Wars Risk
Troisième Soutenance
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;
3.2
L'IA en action
Le deuxième chier ouvert est le chier IA.pas, qui détermine principalement si le joueur actif du moment est un joueur humain ou articiel. S'il est
articiel, cette partie du programme va gérer toutes les actions que le joueur
peut prendre. Cette partie est détaillée un peu plus bas dans le rapport...
3.3
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
à 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
EPITA
12
InfoSup B2
Unbound
Value
Star Wars Risk
Troisième Soutenance
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
concervant 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
exit;
EPITA
13
InfoSup B2
Unbound
Value
Star Wars Risk
Troisième Soutenance
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
infbll.font := CreateFont(16,12,0,0,0 ,0,0,0,0,OUT_CHARACTER_PRECIS
EPITA
14
InfoSup B2
Unbound
Value
Star Wars Risk
Troisième Soutenance
,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)
and (coord.pxy.y < 58) then
EPITA
15
InfoSup B2
Unbound
Value
Star Wars Risk
Troisième Soutenance
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;
end
EPITA
16
InfoSup B2
Unbound
Value
Star Wars Risk
Troisième Soutenance
end;
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;
end;
EPITA
17
InfoSup B2
Unbound
Value
Star Wars Risk
Troisième Soutenance
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);
aff_text(Music.sound_title, conv_pxy_xy(point(40,135)), ptrg);
EPITA
18
InfoSup B2
Unbound
Value
Star Wars Risk
Troisième Soutenance
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
19
InfoSup B2
Unbound
Value
3.4
Star Wars Risk
Troisième Soutenance
...et pour nir le son
Enn, le chier Audio.pas permet de gérer la musique lors du jeu. Ce
chier est explicitée ci-dessous.
EPITA
20
InfoSup B2
Unbound
Value
Star Wars Risk
Troisième Soutenance
4 Place au 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
21
InfoSup B2
Unbound
Value
Star Wars Risk
Troisième Soutenance
Pour la soutenance nale, le spectre devrait orner le tableau de commande du jeu, et des bruitages tels que des paroles de R2D2 devraient être
rajoutés.
EPITA
22
InfoSup B2
Unbound
Value
Star Wars Risk
Troisième Soutenance
5 L'Intelligence Articielle
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, la phase d'attaque, et la phase de redéploiement des troupes dans l'attente de la riposte adverse. Si nous avons le
temps, nous nous attaquerons à la phase de redéploiement, mais nous avons
préféré parer au plus utile dans le jeu, à savoir le déploiement des troupes et
la phase d'attaque.
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
23
InfoSup B2
Unbound
Value
5.2
Star Wars Risk
Troisième Soutenance
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é.
5.3
Le redéploiement des troupes
Si le temps nous le permet, il est possible d'obtenir un rééquilibrage des
ottes lors de la 3ème phase. Un autre exemple : j'ai une planète qui est
entourée de planètes amicales et qui possède des troupes en surplus, l'ordinateur va envoyer ses troupes dans les planètes limitrophes.
EPITA
24
InfoSup B2

Documents pareils