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