Le rapport de la soutenance finale

Transcription

Le rapport de la soutenance finale
Rapport de projet
Julien BIRENE
Anthony DESVERNOIS
Pierre MARIAGE
Kévin MATHIEU
SimKingdom
Rapport de projet
Table des matières
1
Introduction
3
2
Le planning
2.1 Soutenance 1 . . .
2.2 Soutenance 2 . . .
2.3 Soutenance 3 . . .
2.4 Soutenance finale
.
.
.
.
3
4
4
4
5
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
6
6
6
10
10
11
16
17
20
20
24
25
27
28
29
30
31
32
3
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Gameplay
3.1 Introduction . . . . . . . . . . . . . . . . . . . . .
3.2 Le menu . . . . . . . . . . . . . . . . . . . . . . .
3.3 L’interface . . . . . . . . . . . . . . . . . . . . . .
3.3.1 Introduction . . . . . . . . . . . . . . . . .
3.3.2 Les éléments permanents . . . . . . . . .
3.3.3 Les fenêtres . . . . . . . . . . . . . . . . .
3.3.4 Remplissage des fenêtres des conseillers .
3.4 Les sous-coeurs du jeu . . . . . . . . . . . . . . .
3.4.1 CoreBatiments . . . . . . . . . . . . . . .
3.4.2 CoreBudget . . . . . . . . . . . . . . . . .
3.4.3 CoreCreature . . . . . . . . . . . . . . . .
3.4.4 CoreCS . . . . . . . . . . . . . . . . . . . .
3.4.5 CoreMinistere . . . . . . . . . . . . . . . .
3.4.6 CorePopulation . . . . . . . . . . . . . . .
3.4.7 CoreScenario . . . . . . . . . . . . . . . .
3.4.8 CoreTech . . . . . . . . . . . . . . . . . . .
3.5 Le Coeur principal . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4
Bâtiments
33
5
Site Web
35
6
Son
36
7
Moteur graphique
37
7.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
8
Moteur physique
41
Page 1
SimKingdom
9
Créatures
9.1 Introduction . . . . . . . . . . . . .
9.2 Parseur mdl . . . . . . . . . . . . .
9.2.1 Structure simplifiée du mdl
9.2.2 Le loader de créature (.mdl)
9.3 Format des bones . . . . . . . . . .
9.4 Attachement des bones aux vertex
9.5 Principe d’animation . . . . . . . .
9.6 Procédure principal de la créature
9.7 L’a-star . . . . . . . . . . . . . . . .
10 Editeur de cartes
Rapport de projet
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
44
44
45
45
46
50
53
53
58
60
69
11 Editeur de bâtiments
73
11.0.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . 73
11.0.2 De l’intérêt de la POO . . . . . . . . . . . . . . . . . . 73
11.0.3 La fonctionnalité avant tout . . . . . . . . . . . . . . . 76
12 Editeur de scénarios
76
13 Conclusion
78
14 Tableau récapitulatif : qui a fait quoi
79
Page 2
SimKingdom
1
Rapport de projet
Introduction
Jamais 3 sans 4 ! Nous voila déjà à la soutenance finale, qui va cloturer
ce projet de première année de l’Epita.
Ce rapport finale a pour but de décrire notre jeu, les différentes parties
qui le compose, explique nos choix, les difficultés que nous avons rencontré et comment nous y avons pallié (ou pas), et ce tout au long de l’année.
Nous l’avons organisé de la manière suivante : chaque partie du jeu
est décrite par les membres du groupe qui ont aidé à sa réalisation (faut
assumer dans la vie). Ainsi, chaque sous-partie indique qui à fait quoi dans
le jeu. Afin de vous facilité la vie, un tableau récapitulatif est disponible à
la fin de ce rapport.
Info sur le rapport
Pour plus de clarté (si si), les différents membres du projets seront nommés par leur user id (UID). A titre indicatif (au cas où vous ne connaîtriez
pas nos UID par coeur) :
BIRENE Julien
DESVERNOIS Anthony
MARIAGE Pierre
MATHIEU Kévin
2
80018
80048
80120
80122
Le planning
+
⊕
*
Légende des tableaux
Non abordé
Ebauché
Avancé
Terminé
Ajout au projet initial
Page 3
SimKingdom
2.1
Soutenance 1
Gameplay
Bâtiments
Site Web
Son
Moteur graphique
Moteur physique
Créatures
Editeur de cartes*
Editeur de batiments*
Editeur de scénarios*
2.2
Anthony Julien
-
Kévin Pierre
⊕
-
-
-
⊕
Soutenance 2
Gameplay
Bâtiments
Site Web
Son
Moteur graphique
Moteur physique
Créatures
Editeur de cartes*
Editeur de batiments*
Editeur de scénarios*
2.3
Rapport de projet
Anthony Julien
+
+
+
⊕
⊕
+
Kévin Pierre
Anthony
⊕
Kévin Pierre
⊕
+
⊕
+
-
Soutenance 3
Gameplay
Bâtiments
Site Web
Son
Moteur graphique
Moteur physique
Créatures
Editeur de cartes*
Editeur de batiments*
Editeur de scénarios*
⊕
Julien
⊕
+
⊕
⊕
⊕
⊕
+
+
⊕
⊕
+
+
⊕
Page 4
SimKingdom
2.4
Rapport de projet
Soutenance finale
Gameplay
Bâtiments
Site Web
Son
Moteur graphique
Moteur physique
Créatures
Editeur de cartes*
Editeur de batiments*
Editeur de scénarios*
Anthony Julien
⊕
⊕
⊕
⊕
⊕
⊕
Kévin Pierre
⊕
⊕
⊕
⊕
⊕
⊕
⊕
⊕
⊕
⊕
Page 5
SimKingdom
3
Rapport de projet
Gameplay
3.1
Introduction
Le gameplay est une partie fondamentale du jeu, qui comprend le menu,
l’interface, les différents sous-coeurs du jeu et enfin le coeur principal.
Nous allons décrire dans cette partie comment ont été codées ces différentes parties du jeu et leurs rôles exacts.
3.2
Le menu
Le menu du jeu à été réaliser de manière relativement simple. La position dans le menu est contenu dans une variable de type entier dénommée
"menu" (dingue). Suivant la valeur de cette variable, on affiche une image
différentes à l’écran.
Ici par exemple on passe de l’image correspondant à la valeur menu =
1 (menu principal) à l’image correspondant à la valeur menu = 8 (crédits).
F IG . 1 – le menu 1
F IG . 2 – le menu 8
Pour récuperer les clics de l’utilisateur, on a tout simplement mappé les
Page 6
SimKingdom
Rapport de projet
différentes images. En fonction de la variable menu on applique les règles
de mappage correspondante.
Ici par exemple vous pouvez voir les règles de mappage pour le menu
principal.
if menu = 1 then {menu base}
begin
if ((xs>=135+((w-800)/2)) and (ys>=110+((h-600)/2))
and (xs<=380+((w-800)/2)) and (ys<=195+((h-600)/2)))
then menu := 2; // jeu libre
if ((xs>=420+((w-800)/2)) and (ys>=110+((h-600)/2))
and (xs<=690+((w-800)/2)) and (ys<=195+((h-600)/2)))
then menu := 5; // scénario
if ((xs>=420+((w-800)/2)) and (ys>=320+((h-600)/2))
and (xs<=690+((w-800)/2)) and (ys<=405+((h-600)/2)))
then menu := 3; // options
if ((xs>=135+((w-800)/2)) and (ys>=450+((h-600)/2))
and (xs<=380+((w-800)/2)) and (ys<=535+((h-600)/2)))
then menu := 8; // crédits
if ((xs>=420+((w-800)/2)) and (ys>=440+((h-600)/2))
and (xs<=690+((w-800)/2)) and (ys<=535+((h-600)/2)))
then menu := 4; // quitter
if ((xs>=120+((w-800)/2)) and (ys>=320+((h-600)/2))
and (xs<=380+((w-800)/2)) and (ys<=405+((h-600)/2)))
then menu := 10; // charger
if ((xs>=420+((w-800)/2)) and (ys>=205+((h-600)/2))
and (xs<=690+((w-800)/2)) and (ys<=295+((h-600)/2)))
then menu := 12; // scores
if ((xs>=135+((w-800)/2)) and (ys>=205+((h-600)/2))
and (xs<=380+((w-800)/2)) and (ys<=295+((h-600)/2)))
then menu := 13; // reseau
end
Le mappage initial du menu (soutenance 2) à été réaliser par 80018. La
quasi totalité des images ont été réalisé par 80122 aidé de 80120.
Toutefois, certains éléments du menu nécessitant une interaction avec
l’utilisateur plus poussé qu’un simple clic, nous avons réaliser des composants à l’image des composants proposé par delphi, mais utilisable sous
OpenGL. Sur l’image qui suit vous pouvez voir le menu des options avec
les composants t_listbox, les composants t_trackbar et le composant t_checkbox.
Sur l’image suivante vous pouvez voir le menu jeu libre avec à nouveau le composant t_listbox et le composant t_edit.
Page 7
SimKingdom
Rapport de projet
F IG . 3 – Le menu des options
F IG . 4 – Le menu jeu libre
Page 8
SimKingdom
Rapport de projet
Ainsi, le menu des options, le champ pseudonyme, ainsi que les listes
des cartes et sauvegardes disponibles ont été réalisé à partir d’occurences
de nos composants.
Bien évidement, nos composants ont été programmé en objet. Le code
qui suit est la déclaration du composant t_checkbox.
T_CheckBox = Class
private
Position_x : integer;
Position_y : integer;
public
Valeur : boolean;
constructor create(mavaleur:boolean);
procedure tracer(pos_x,pos_y:integer);
procedure checked(cgauche:boolean;h,xs,ys:integer);
end;
L’ensemble des composants ainsi que leur implémentation à été réaliser par 80048.
Le clic jouer (peu importe son origine) affiche toujours la même image
de fond, invitant l’utilisateur à appuyer sur entrer pour lancer la partie.
Par contre, le clic à modifier la valeur d’une variable booléenne. Si l’on
était en jeu libre, la variable jouer passe à vrai, si l’on était en chargement,
la variable charger_jeu passe à vrai, . . . . Lorsque l’utilisateur appuie sur
la touche entrée, la classe du jeu est créer. La création de la classe différe
en fonction du mode de jeu souhaité. La musique du mode jeu est lancé
et la fonction principal de la classe jeu est lancée. Le code ci-dessous correspond au différent lancement possible du jeu en fonction de la variable
booléenne correspondante.
if jouer then
begin
Stop_Musique;
jouer_musique('music/maps/map1.wma');
// Lance le Jeu
Jeu := TJeu.Create(Login.Text);
Jeu.Principal(ExtractFilePath(Application.ExeName) + 'Cartes/' +
liste_map[ListMap.Selection]);
Exit;
end;
Page 9
SimKingdom
Rapport de projet
if jouer_scenar then
begin
Stop_Musique;
jouer_musique('music/maps/map1.wma');
Objectif := GetObjectif(ligneScenar[ListeScenario.Selection]);
Jeu := TJeu.Create(Objectif,Login.Text);
Jeu.Principal(ExtractFilePath(Application.ExeName) + 'Cartes/' +
Objectif.Map+'.map');
Exit;
end;
if charger_jeu then
begin
Stop_Musique;
jouer_musique('music/maps/map1.wma');
load.Charger( LigneSave[ListeSave.Selection ] );
Jeu := TJeu.Create(Load,Login.Text);
Jeu.Principal( Load.Map );
Exit;
end;
Bien évidemment, le constructeur de la classe TJeu existe en plusieurs
exemplaires via le mot clef "overload".
La liaison entre le clic jouer et le jeu à été réaliser par 80122 et 80048.
3.3
3.3.1
L’interface
Introduction
L’interface du jeu est une sur-matrice du moteur graphique, c’est-à-dire
que toute l’interface est dessiner dans un bloc compris entre glPushMatrix
et glPopMatrix. Cette matrice à part est un espace bidimensionnel (j’aime
bien ce mot) définit de cette manière :
glfwGetWindowSize(width,height);
glViewport(0,0,width,height);
glPushMatrix();
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
glOrtho(0, width, 0, height, -100,100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
Page 10
SimKingdom
Rapport de projet
gluLookAt(0,0,0,0,0,-100,0,1,0);
3.3.2
Les éléments permanents
Les éléments de l’interface sont des occurences des composants de l’interface, à savoir le composant minimap, ressource, selactiv (indique des
informations sur l’objet selectionné dans la matrice 3D), tab_icone (menu
d’icones déroulant), temps et vitesse. Le fond de l’interface quant à lui est
une image, réalisé par 80120 et 80122.
F IG . 5 – L’interface
L’ensemble des composants de l’interface ont été réalisés par 80048.
Tab Icones
Le code qui suit est la déclaration du composant tab_icones.
Tab_Icone = class
private
x,y,w,h,Ligne : integer;
public
NbElts : integer;
Liste : TListe_Icone;
constructor Create(py,pw,ph,pnb:integer);
Page 11
SimKingdom
Rapport de projet
function Focus(ha,xs,ys:integer):boolean;
function Action(ha,xs,ys:integer;pleft:boolean):integer;
procedure Afficher(la,ha,xs,ys:integer;test:boolean);
end;
Le composant tab_icone prend donc une liste d’icones (de type TListe_Icone),
les affiches et retourne (fonction Action) le numéro de l’élement cliqué, si
élement il y a (elle renvoie -42 sinon).
TMiniMap Le composant minimap permet l’affichage d’une minimap
(halucinant). Il y a 2 affichages possibles pour la minimap :
– L’affichage classique, qui fait apparaitre les batiments du joueurs en
rouge, les arbres en vert, l’eau en bleu, la créature en blanc,. . .
F IG . 6 – La minimap
– L’affichage criminalité, qui fait apparaitre les habitations ou le potentiel de criminalité est élevé en rouge, en vert s’il est faible et en bleu
les batiments administratifs.
F IG . 7 – La minimap en mode criminalité
Voici à présent la déclaration de ce composant :
TMiniMap = class
private
x,y,tc:integer;
Page 12
SimKingdom
Rapport de projet
carte : array [0..100]of array[0..100] of a_case;
public
procedure ajout_objet(px,py,tac:integer;type_objet:string);
procedure set_crim(px,py:integer;b:boolean);
procedure supprimer_objet(px,py:integer);
procedure afficher_normal(px,py:integer;taille_carte:integer);
procedure afficher_crim(px,py:integer;taille_carte:integer);
procedure afficher_cadre(angle_z,x2,y2,zoom:real);
function focus(ha,xs,ys:integer):boolean;
end;
SelActiv Le composant SelActiv est un simple composant qui affiche le
type de batiments (créature, ressource) et des informations le concernant.
Voici ce que ca donne pour un arbre, une maison, une mine d’or, une tour
et une menuiserie.
F IG . 8 – La sélection d’un arbre
F IG . 9 – La sélection d’une maison
Le composant SelActiv à été complété (créature) par 80122.
Ressources Le composant ressources affiche l’état du trésors et le nombre
d’habitant ainsi que la population maximal.
Page 13
SimKingdom
Rapport de projet
F IG . 10 – La sélection d’une mine d’or
F IG . 11 – La sélection d’une tour
F IG . 12 – La sélection d’une menuiserie
F IG . 13 – La barre des ressources
F IG . 14 – La barre de temps (date)
Page 14
SimKingdom
Rapport de projet
Temps Le composant temps permet l’affichage de la date (si si je vous
jure). Voici sa déclaration :
T_Timer = class
private
w,h,x:integer;
mois,annee : integer;
dmois : integer;
public
constructor Create(l,ha,year:integer);
procedure Afficher(x,hauteur:integer;var temps:real;unite_temporel:integer);
function GetMonth():integer;
function GetYear():integer;
procedure SetT(m,a:integer);
end;
Son fonctionnement est basé sur la fonction glfwGetTime et sur la valeur de la variable unite_temporel, qui est déterminée par le composant
vitesse.
F IG . 15 – Le composant vitesse
Vitesse Le composant vitesse permet de régler la valeur de l’unité temporel, et donc la vitesse à laquelle vont défiler les mois et années. Voici sa
déclaration et son implémentation dans l’unité de jeu.
tvitesse = class
private
x:integer;
ha : integer;
defaut : integer;
liste : array[1..4] of string;
public
constructor create(def:integer);
procedure afficher(xx,h:integer);
function focus(hauteur,xs,ys:integer;cgauche:boolean):boolean;
function action(hauteur,xs,ys:integer;cgauche:boolean):integer;
Page 15
SimKingdom
Rapport de projet
end;
//
vitesse.afficher(w-100,124);
vtime := vitesse.action(h,x,y,pleft);
case vtime of
1: MODE_PAUSE := true;
2: unite_temporel := 10;
3: unite_temporel := 5;
4: unite_temporel := 2;
end;
3.3.3
Les fenêtres
La totalité des conseillers du jeu sont accessibles via l’interface et sont
affiché via des fenêtres dans l’interface. Etant donné le nombre de conseiller,
et pour nous faciliter l’existence, nous avons crée un composant fenetre
dont voici la déclaration :
Tfenetre = class
protected
x,y : integer;
largeur,hauteur : integer;
titre : string;
icone : GLuint;
public
ouvert : boolean;
constructor create(ptitre:string;picone:gluint); overload;
constructor create(ptitre:string); overload;
function deplacer(h,pxs,pys,xs,ys:integer):T2i;
procedure fermer(h,xs,ys:integer;cgauche:boolean);
function focus(h,xs,ys:integer):boolean;
procedure afficher(px,py,pw,ph:integer);
function getPos():T2i;
function getTaille():T2i;
end;
Ainsi, chacun de nos conseillers est associé à une fenêtre. Le remplissage de celle-ci est spécifique à chaque conseillers (unité conseillers.pas) et
est géré de la manière suivante (pour le conseiller au culte) :
Page 16
SimKingdom
[...]
Rapport de projet
// Fenêtre Culte
if fen_culte.ouvert then
begin
dopick := false;
fen_culte.afficher(200+dfen_culte.i1,150+dfen_culte.i2,600,450);
fen_culte.fermer(h,x,y,pleft);
dtfen_culte := fen_culte.deplacer(h,pxs,pys,x,y);
dfen_culte.i1 := dfen_culte.i1 + dtfen_culte.i1;
dfen_culte.i2 := dfen_culte.i2 + dtfen_culte.i2;
Ministere.PrintConseil(m5.texte,'e',222+dfen_culte.i1,480+dfen_culte.i2);
Cons_Culte(TCulte,dfen_culte,Eglise,Cathedrale,graph_c1);
end;
De la même manière, le menu pause permettant de quitter le jeu, sauvegarder et revenir au menu est une fenêtre.
F IG . 16 – Le menu échap
La classe fenêtre à été élaborée par 80048.
3.3.4 Remplissage des fenêtres des conseillers
Chaque conseiller affiche des données statistiques correspondant a son
ministère. Ces données sont souvent synthétisé sous forme de graphique.
Le système de graphique est ici encore un composant, dont voici la déclaration.
TGraphique = class
Page 17
SimKingdom
Rapport de projet
private
x,y,largeur,hauteur:integer;
titre,et_ab,et_or:string;
maximum : real;
procedure max(start,nbpts:integer);
function focus(ha,xs,ys:integer):boolean;
procedure vsouris(ha,xs,ys,C:integer;PH,U,r,g,b:real);
procedure zpix(x,y:integer;r,g,b,val:real);
public
liste : array of Array of real;
constructor create(ptitre,pab,por:string);
procedure afficher(px,py,pw,ph:integer;lr,lg,lb:real);
procedure ajouter_pts(courbe:integer;valeur:real);
procedure dessiner_courbe(r,g,b:real;courbe,start,nbpts:integer);
procedure reset_courbe();
end;
On trouve aussi dans les fenêtre conseillers des composants tel que la
t_checkbox et la t_listbox, comme ici :
F IG . 17 – Le premier conseiller
ou encore un t_compteur, qui permet (ici) à l’utilisateur de régler le
taux d’imposition.
Cette partie du remplissage à été effectué par 80048.
Enfin, chaque conseiller affiche un conseil en fonction de la situation.
La gestion de ce message (pré-enregistré) s’effectue dans l’unité CoreMinistere.pas.
Cette partie du jeu à été codé par 80018, 80120 et 80122.
Page 18
SimKingdom
Rapport de projet
F IG . 18 – Le Baron Rodot
F IG . 19 – La conseillère auprès de la populace
Page 19
SimKingdom
3.4
Rapport de projet
Les sous-coeurs du jeu
On dénombre 8 sous-coeurs :
1. CoreBatiments
2. CoreBudget
3. CoreCreature
4. CoreCS
5. CoreMinistere
6. CoreScenario
7. CoreTech
3.4.1
CoreBatiments
Le core batiments et le sous-coeur qui gère les batiments (quelle surprise). L’ensemble des actions du jeux sur les batiments, de leurs constructions à leur destructions ainsi qu’un grand nombre de statistiques utilisent
cette unité, qui comprend donc un grand nombre de procédure et de fonctions. On distingue dans notre jeu 4 type de batiments, codé sous forme
de classe et disposons de caractéristiques communes et de caractéristiques
spécifiques. L’ensemble de ces 4 batiments sont des enfants d’un type TBts
(caractéristiques communes). Voici leurs déclarations :
TBts = class
protected
icone : GLUint;
nom : string;
Prix : UPrix;
function Check(tabcarte : TCarte ; t:string):integer;
public
tx,ty : integer;
function GetIcone():GLUint;
function GetName():String;
function GetPrice():UPrix;
function Construct(x,y,tc:integer):boolean;
procedure ConstrucRemp(x,y,tc: integer; typeB : string);
procedure SetTaille(l,h:integer);
function VRessource(g,p,b:integer):boolean;
end;
TMaison = class(TBts)
Page 20
SimKingdom
Rapport de projet
private
nbh, capacite,unite,nbm : integer;
public
constructor create(G,P,B:integer;Capu,l,h:integer);
procedure Add();
procedure Del();
procedure SetHab(t:integer);
function GetOccupationRate():integer;
function GetHabitants():integer;
function GetCapacity():integer;
function GetMaison():integer;
end;
TBatProd = class(TBts)
private
Workers : integer;
NbBtsProd,Production,ValRessource : Integer;
ListeBtsProd : TabBtsProd;
ListeRessource : TabRessource;
R :integer;
function GetRessource(x,y,r:integer):integer;
public
NeedW,RW:integer;
function PreP(x,y:integer):integer;
constructor Create(G,P,B,ValProd,W,Rr:integer);
procedure Add(x,y:integer);
procedure Del(x,y:integer);
function SetWorkers(t:integer):integer;
procedure Pos_Ressource(ressource:string;TabCarte:TCarte);
function GetProd():integer;
function GetBtsProd():integer;
procedure CheckAll(S,S2,S3:String);
end;
TBatUp = class(TBts)
private
Puissance,nb : integer;
public
constructor Create(G,P,B,Pp:integer);
function GetP():integer;
procedure Add();
procedure Del();
function GetCoef:integer;
Page 21
SimKingdom
Rapport de projet
function GetNb:integer;
end;
TChateau = class(TBts)
private
Capacite : integer;
R, Influence : integer;
place : integer;
ListeBts : TabBtsProd;
ListeRessource : TabR2;
procedure Pos_Ressource();
public
function PreP(x,y:integer):integer;
constructor Create(G,P,B,C,Rr,I,la,lo:integer);
procedure Add(x,y:integer);
procedure Del(x,y:integer);
procedure Appliquer(MiniMap:TMinimap;nb_cases:integer);
function GetProd():integer;
function GetNb():integer;
function GetC():integer;
end;
Nous avons donc
1. TMaison : les habitations :
(a) Maison
(b) Manoir
(c) Villa
2. TBatProd : les batiments producteurs
(a) Mine d’or (or)
(b) Tailleur de pierre (pierre)
(c) Bucheron (bois)
(d) Eglise (mana)
(e) Cathedrale (mana)
3. TBatUp : les batiments améliorant les productions
(a) Fonderie (or)
(b) Maconnerie (pierre)
Page 22
SimKingdom
Rapport de projet
(c) Menuiserie (bois)
4. TChateau : les batiments administratifs (réducteur de criminalité)
(a) Chateau I
(b) Chateau II
(c) Tour
(d) Epita
Pour être utilisé, le coeur principal crée à chaque partie une occurence
d’un objet du core batiments pour chaque batiments. Cela donne donc
dans moteur_graphique_map :
Maison := TMaison.create(0,10,75,10,1,1);
Maison2 := TMaison.create(40,160,175,10,2,2);
Maison3 := TMaison.create(250,200,300,5,2,2);
Chateau1 := TChateau.Create(0,300,300,20,5,1,6,6); // 1
Chateau2 := TChateau.Create(1000,600,600,40,8,1,6,6); // 1
Epita := TChateau.Create(15000,15000,20000,0,10,1,2,4); // 1
Tour := TChateau.Create(0,150,150,0,3,1,1,1);
Bucheron := TBatProd.Create(0,25,200,1,6,2);
MineOr := TBatProd.Create(50,50,200,1,6,2);
MinePierre := TBatProd.Create(0,50,200,1,6,2);
MinePierre.SetTaille(2,2);
Eglise := TBatProd.Create(300,100,500,1,6,3);
Eglise.SetTaille(2,2);
Cathedrale := TBatProd.Create(2000,2000,1000,1,20,6); // 1
Cathedrale.SetTaille(6,3);
Menuiserie := TBatUp.Create(50,50,300,2);
Menuiserie.SetTaille(2,3);
Maconnerie := TBatUp.Create(50,100,300,2);
Maconnerie.SetTaille(2,2);
Fonderie := TBatUp.Create(200,200,300,2);
Fonderie.SetTaille(2,2);
Le core batiment a été réalisé par 80048.
Page 23
SimKingdom
3.4.2
Rapport de projet
CoreBudget
Le sous-coeur Budget est le coeur qui gère les ressources et qui permet
de récolter les impôts. Toute la gestion du budget est réaliser à partir de la
classe TTresors. Voici (pour changer) sa déclaration :
TTresors = class
private
Impot : integer;
Gold,Pierre,Bois,Priere : integer;
TabRessource : array[1..6] of TabGraph;
TabRessource2 : array[1..6] of TabGraph;
public
constructor Create(G,B,P:integer);
function Get(t:integer):integer;
procedure Add(t,v:integer);
function Del(g,p,b,m:integer):boolean;
function GetGraph(t:integer;t2:integer):TabGraph;
procedure AddGraph(t:integer;v,v2:integer);
procedure SetImpot(t:integer);
function GetImpot():integer;
procedure RecolterImpot(pop:integer);
end;
Le coeur budget permet par exemple de determiner si la construction
d’un batiments et possible de le payer (Del), d’ajouter des ressources au
trésors (Add), de récuperer les statistiques concernant le trésors, . . . Voici
plusieurs exemples de son utilisation dans le coeur principal :
– Pour la barre des ressources
Ressource.Afficher((w div 2) - 250,h,Tresors.Get(1),Tresors.Get(3),
Tresors.Get(2),Population.GetPop,Maison.GetCapacity+Maison2.GetCapacity
+Maison3.GetCapacity+Chateau1.GetC+Chateau2.GetC,Tresors.Get(4));
– Pour la construction d’un batiment
if Liste[indice_icone].val = 'Maison1' then
begin
CONSTRUCT_OK :=
(Maison.Construct (TabPick[ObjSelected].x,TabPick[ObjSelected].y,
nb_cases))and(Tresors.Del(Maison.GetPrice.G,Maison.GetPrice.P,
Maison.GetPrice.B,0));
if CONSTRUCT_OK then
begin
Maison.Add();
Page 24
SimKingdom
Rapport de projet
Maison.ConstrucRemp
(TabPick[ObjSelected].x,TabPick[ObjSelected].y,nb_cases,'Maison1
end;
end;
Le core budget a été réalisé par 80048.
3.4.3
CoreCreature
Le core Creature est le système qui gère tous les pouvoirs, bonus et
influence de la créature. Ce core est activé lorsqu’une créature est affichée
sur la carte.
Sa déclaration est la suivante :
TCoCreature = class
private
bonus : integer;
public
CreatureCore : TChateau;
name : string;
constructor Create(n: string; x,y,b, r: Integer);
function GetBonus(batprod:TBatProd; Tresors: TTresors) : integer;
function Pouvoir(cost, pv : integer; Tresors:TTresors) : boolean;
end;
Bonus
La fonction GetBonus permet de calculer le bonus de production à ajouter aux batiments producteurs (Mine d’or, camp de mineurs ou bucheron)
pour ensuite l’ajouter au trésor (or, pierre, bois) chaque mois :
function TCoCreature.GetBonus(batprod:TBatProd; Tresors: TTresors) : integer;
begin
result := ceil(batprod.GetProd * (bonus/100));
end;
Pouvoirs
La fonction Pouvoir effectue l’un des pouvoirs de la créature : ajouter
50 de bois, ajouter 50 de pierre, ajouter 50 de bois. On obtient ces pouvoirs
en cliquant sur la créature puis en cliquant sur l’un des 3 boutons (voir cidessous). On diminue bien sûr la mana en fonction du coup du pouvoir.
Page 25
SimKingdom
Rapport de projet
function TCoCreature.Pouvoir(cost, pv : integer; Tresors: TTresors):boolean;
begin
if Tresors.Del(0,0,0,cost) then
begin
Tresors.Add(pv,50);
result := true;
end
else result := false;
end;
F IG . 20 – Les pouvoirs de la créature
Les icones sont affichés via un autre module : "composant_selactive.pas"
qui gère la petite fenêtre de droite. Si on clique sur la créature, on affiche
son nom puis les 3 images des 3 pouvoirs (non ? !), si l’on passe sur un
icone avec le curseur, une bulle d’aide apparaît et indique la ressource qui
va être ajouter au trésor.
Influence
Le principe d’influence de la créature est exactement celui du chateau. En effet, CreatureCore : TChateau permet de traiter la gestion de l’influence en reprenant un composant déjà codé en POO pour plus de facilité. . . (après tout un programmeur c’est feignant. . . ). Donc la créature peut
être assimiler un chateau de taille 1, 1 avec une influence (rayon d’action)
fixé à partir de la créature choisit.
Il suffit d’appeler à chaque mois les fonctions suivantes pour gérer l’influence de la créature :
if CreatureActiv then GestionC.CreatureCore.Appliquer(MiniMap,nb_cases);
if CreatureActiv then Population.SetDCriminel(Chateau1.GetProd +
Chateau2.GetProd + Epita.GetProd + Tour.GetProd +
Page 26
SimKingdom
Rapport de projet
GestionC.CreatureCore.GetProd)
else Population.SetDCriminel(Chateau1.GetProd + Chateau2.GetProd
+ Epita.GetProd + Tour.GetProd);
Le core créature à été réalisé par 80122 et 80048.
3.4.4
CoreCS
Le core CS est le système qui s’occupe du chargement et des sauvegardes. Plus précisement, cette unité contient la classe CS, qui permet la
sauvegarde, le chargement et l’affichage du contenu de la fenêtre sauvegarde. Sa déclaration est la suivante :
CS = class
public
Map,Pseudo : string;
S:string;
nb_cases : integer;
Chaine : Array_of_string;
Gold,Pierre,Bois,Priere,Impot,
Hab,Mois,Annee : integer;
Objectif : TObjectif;
Scenario : boolean;
function sauvegarder(filename,map,pseudo:string;
nb_cases:integer;Tresors:TTresors;
Population:TPopulation;Timer:T_Timer;
mode_scenario:boolean;Objectif:TObjectif):boolean;
procedure Charger(filename:string);
function checkfile(x,y:integer;var Edit : t_edit;ha,xs,ys:integer;pleft:boo
nb_cases:integer;Tresors:TTresors;Population:
TPopulation;Timer:T_Timer;mode_scenario:boolean;
Objectif:TObjectif;p_back:boolean):boolean;
end;
Le système de sauvegarde se base sur l’écriture dans un fichier *.sav
dont la structure est la suivante :
nom de la carte
pseudo du joueur
{------}
x y type_du_batiment
[...]
Page 27
SimKingdom
Rapport de projet
{------}
Or Pierre Bois Mana Tx_imposition
Habitant
{------}
Mois Annee
{SCENARIO} // seulemment en cas de scénario
Objectif_Or Objectif_Pierre Objectif_Bois Objectif_Priere Objectif_Habitant
Objectif_Bucheron ...
Le système de chargement parse ce fichier et remplit ses variables publics en conséquences. Pour rappel, en mode chargement le jeu est crée
avec une variable de type CS en paramètre. Cette variable seras ensuite
utilisé dans le jeu pour le chargement de la carte, des différents bâtiments,
du trésors,. . .
Le coeur CS a été réalisé par 80048 avec l’aide de 80122.
3.4.5
CoreMinistere
Le core ministère est le système permettant de générer des conseils
adapté à la situation. Il se base sur les données recueillis des années précédentes (via les graphiques). Sa structure est la suivante :
TCoreMinistere = class
private
public
function Kristel(Population : TPopulation; maison, villas, manoir, bonheur
function Benalli(Antresor, tresor, Anpierre, pierre, Anbois, bois : integer
function Rodot(Antresor, tresor, taux : integer) : TProb;
function Nath(maison, manoir, villa, bucheron, mineor, minepierre : integer
function Petit(mana : integer) : TProb;
function Boullay(m1, m2, m3, m4, m5 : boolean) : string;
procedure PrintConseil(chaine,typ:string;x,y:integer);
end;
Voici un exemple de test réalisé en son sein (M. Rodot, conseiller des
finances) :
if (tresor <= 0) then
begin
str := str + 'Augmentez les impots ou construisez plus de mines d''or. Je vou
bool := true;
Page 28
SimKingdom
Rapport de projet
end
else if (tresor < Antresor) then
begin
str := str + 'Votre tresorerie m''inquiete... construisez plus de bâtiments d
bool := true;
end
else if (tresor > Antresor) and (taux >= 50) then
begin
str := str + 'Le taux d''imposition est tres eleve.. vous devriez songer a le
bool := true;
end
else if (taux <= 50) then
begin
str := str + 'Le taux d''imposition est tres bas... Je suis pas specialement
bool := true;
end;
Chaque fonction est appelé respectivement quand on appelle la fenêtre
du conseiller, elle renvoie un enregistrement :
TProb = Record
texte : string;
prob : boolean;
end;
Le texte est affiché dans le cadre du conseiller et prob permet d’afficher
un message adapté avec la conseiller principal.
Il a été réalisé par 80018, 80120 et 80122.
3.4.6
CorePopulation
Le core population est, ô surprise, le système gérant la population.
Voici la déclaration du composant TPopulation qui le peuple (facile) :
TPopulation = class
private
FBonheur : integer;
TBonheur,TDeces : integer;
TabPop : TabGraph;
TabBon : TabGraph;
Chomeurs:integer;
Page 29
SimKingdom
Rapport de projet
PCriminel,RCriminel:integer;
public
ICap : integer;
NbH : integer;
constructor Create(nb,bonheur,deces:integer);
function Get:integer;
procedure Cycle(capacite:integer);
function GetPop:integer;
function GetBon:integer;
function GetGraphBonheur:TabGraph;
function GetGraphPopulation:TabGraph;
procedure SetBonheur(v:integer);
procedure AddGraphe(v,v2:integer);
function GetChomeurs():integer;
procedure SetChomeurs(t:integer);
procedure SetDCriminel(t:integer);
function GetRCriminel:integer;
end;
On y trouve des fonctions et procédures essentielles du jeu tel que la
procedure Cycle, qui permet chaque mois (elle est appelé chaque mois)
d’augmenter ou diminuer la population en fonction du bonheur. La classe
TPopulation contient aussi le nombre de criminel potentiel et réelle, le
nombre de chomeurs,. . .
Le core population a été réalisé par 80048.
3.4.7
CoreScenario
Le core scénario. . . Enfin bref, il contient l’enregistrement TObjectif et
la classe TMission. L’enregistrement TObjectif stock les objectifs de la mission (ce qui est somme toute logique), voici sa déclaration :
TObjectif = record
Gold,Pierre,Bois,Priere,Habitants : integer;
NbBucheron,NbMineOr,NbTailleur : integer;
NbEglise,NbCathedrale,NbEpita : integer;
NbChateau1,NbChateau2 : integer;
Temps : integer;
Map : string;
end;
La classe TMission permet :
Page 30
SimKingdom
Rapport de projet
1. l’affichage des objectifs du scénario
2. vérifier si le joueur à gagné
3. vérifier si le joueur à perdu
Voici son code :
TMission = class
private
Accompli : Array[1..13] of Boolean;
public
Objectif : TObjectif;
procedure Init();
function TempsRestant(Tps_ecoule:integer):integer;
function Check(t,v:integer):boolean;
function CheckAll(Tresors:TTresors;Population:TPopulation;Bucheron,MineOr,
MinePierre,Eglise,Cathedrale:TBatProd;Chateau1,Chateau2,Epita:TChateau)
:boolean;
procedure Afficher(dfen_obj:T2i;tps_ecoule:integer);
end;
Le sous-coeur scénario à été réalisé par 80048 avec l’aide de 80120.
3.4.8
CoreTech
Le Core Tech. . . ah le core tech, tout une histoire. . . mais là n’est pas le
propos. C’est dans ce fichier qu’est implémenté l’arbre des technologies,
que voici :
C’est donc le core tech qui gère l’affichage du composant tab_icones,
en fonction de la situation (conformément à l’image).
Voici un fragment de son code illustrant son fonctionnement :
if (Chateau2.GetNb = 1) then
begin
inc(I);
liste[I].texte := 'Villa '+IntToStr(Maison3.GetPrice.G)+' O,
'+IntToStr(Maison3.GetPrice.P)+' P, '+IntToStr(Maison3.GetPrice.B)+'B';
liste[I].val := 'Maison3';
liste[I].id := 17;
liste[I].bd := 22;
end;
inc(I);
Page 31
SimKingdom
Rapport de projet
liste[I].texte := 'Tour '+IntToStr(Tour.GetPrice.G)+' O, '
+IntToStr(Tour.GetPrice.P)+' P, '+IntToStr(Tour.GetPrice.B)+'B';
liste[I].id := 2;
liste[I].val := 'Tour';
liste[I].bd := 21;
if (Chateau1.GetNb = 0)and(chateau2.GetNb = 0) then
begin
inc(I);
liste[I].texte := 'Chateau I '+IntToStr(Chateau1.GetPrice.G)+' O,
'+IntToStr(Chateau1.GetPrice.P)+' P, '+IntToStr(Chateau1.GetPrice.B)+'B';
liste[I].id := 3;
liste[I].val := 'Chateau1';
liste[I].bd := 20;
end;
La fonction contenu dans ce sous-coeur (GetLS_Icone) renvoie donc un
enregistrement TListe_Icone.
Ce coeur a été réalisé par 80048 et 80122.
3.5
Le Coeur principal
Le coeur principal du jeu se situe dans l’unité moteur_graphique_map
dans la procedure Jeu de la classe TJeu. En réalité, il n’y a pas vraiment de
Page 32
SimKingdom
Rapport de projet
coeur principal. Il s’agit plutôt de ligne de code dans la boucle principal de
GLFW qui joigne les différents sous-coeurs ensembles, et qui font tourner
le jeu. . . Donc bon, y en a de partout, et ca fonctionne, donc c’est super. . .
Le "Coeur principal", enfin, moteur_graphique_map catégorie TJeu.Jeu
à été codé par 80048, 80120 et 80122.
4
Bâtiments
Le développement des bâtiments a principalement commencé entre la
première et la deuxième soutenance, après qu’ils aient été bien définis.
Nous utilisons des fichiers .obj, un format qui nous avons créé et qui se
trouve être la liste des différens polygônes (carrés et triangles) qui composent les différents objets : bâtiments, arbres, pierre, etc...
Chaque ligne est du format suivant : Nbr x y z R G B A Text, où :
– Nbr est le nombre de sommets du polygône
– x, y, et z sont les coordonnées relatives du sommet (où 0,0,0 est l’origine du repère dans lequel est placé le bâtiment, ce ne sont bien sur
pas les coordonnés sur la map qui varieront continuellement)
– R, G, B sont les 3 paramètres de la couleur à utiliser pour tracer la
map dans le cas où il n’y a pas de texture
– A est la transparence du polygône
– Text est le numéro de la texture, 0 correspondant à l’état "pas de texture". Les textures sont effets chargées dans un tableau, puis désignées en fonction de leur position à l’interieur de celui-ci. Le tableau
est défini dans un .pas à part, lui permettant d’être chargé une fois
pous toute à l’ouverture du jeu et d’être utilisé sans modération au
cours des parties.
On arrive ainsi à des bâtiments très divers, de la simple maison (58
surfaces), au temple (280 surfaces).
La réalisation des bâtiments a au début été assez laborieuse... il fallait
en effet écrire à la main les sommets 1 à 1 dans le .obj, puis lancer le jeu
pour voir l’aperçu. Le placement des bâtiments n’étant pas implémenté à
cette époque, on devait également modifier le code source à chaque nouveau bâtiment pour l’afficher dans le jeu... Un peu avant la 3e soutenance
est né l’éditeur de bâtiments, qui nous a permis un placement des points
et une construction des textures bien plus aisés, avec un aperçu très simple
également. La construction des bâtiments s’est donc vue nettement simplfiée, ce qui nous a permi de réaliser des bâtiments bien plus complexes et
jolis.
Page 33
SimKingdom
Rapport de projet
F IG . 21 – Un bâtiment simple : une maison
F IG . 22 – Un bâtiment plus complexe : le temple
Page 34
SimKingdom
Rapport de projet
La totalité des batiments ont été réalisé par 80018 (quelques corrections
effectués par 80048 et 80120).
5
Site Web
Nous avons voulu réaliser un site convivial, rapide, facile d’accès, dynamique et qui respecte les recommandations du W3C - www.w3c.org
(World Wilde Web Consortium). Notre site a été développé grâce à Macromedia Dreamweaver et est codé seulement en XHTML et CSS. Nous
n’avons pas utilisé de PHP ni de base de donnée par choix car cela necessitait l’installation d’un serveur local (par exemple apache) en cas de problème internet (ce qui nous est arrivé fréquemment lors des soutenances
...) et pour le rendu sur le CD-Rom final. De plus vu le peu de choses à
gérer sur notre site, les pages PHP auraient eu peu d’utilité ...
Pour rendre notre site plus vivant nous avons utilisé la technologie
Flash de Macromedia. Le header du site comporte quelques effets de bande
lumineuse. De plus, pour plus de facilité, le menu a été mappé grâce au
Flash. Nous avons également essayé de rendre notre charte graphique le
plus agréable possible en créant un design fait avec soin et approprié au
contenu de notre projet dans un genre médiéval. Suite à notre note sur le
site Web à la 3e qui nous a deçu nous avons décidé de le rendre plus vivant
en ajoutant des images en rapport avec les jeux médiévaux sur chaque
page du site : troll, chevalier, ogre ...
Pour ce qui est du contenu nous avons séparé notre site comme suit :
– Index : regroupe toutes les news concernant le projet Simkingdom et
l’équipe Atlanteam, ainsi qu’en bas une description rapide du projet.
– Projet : description plus complète du projet.
– Liens : la page qui regroupe tous les liens qui ont été utilisé pour réaliser le projet, classés dans différentes catégories : Delphi, OpenGL,
animations d’un modèle 3D, les quaternions (génial ...), EPITA.
– Team : descriptif des membres du projet avec les photos, les rôles
dans le projet ... Suivi de photos bonus : nos Tshirt Simkingdom personnalisés, et d’autres photos du groupe.
– Screenshots : pleins de captures d’écran du jeu à différents stades du
développement : soutenance 1 et 2, soutenance 3, version 81, version
135 (liés aux numéro de version de SVN) et la version actuelle du
jeu.
Page 35
SimKingdom
Rapport de projet
– Download : pour télécharger tout ce qui concerne le projet : goodies
(fond d’écran, modules, cahier des charges), sources et pdf des rapports de soutenance, executables des versions présentées aux soutenances, des executables de versions stables et après la soutenance
finale : les sources du jeu.
F IG . 23 – Notre site web
Le site web a été réalisé par 80122 avec l’aide de 80018. L’ensemble du
groupe a participé a sa vie.
6 Son
Le son a été intégralement développé avant la première soutenance,
mais une amélioration y a été rajoutée il y a peu de temps. Nous avons
utilisé les librairies FMOD qui proposent de très nombreuses fonctions
simples à utiliser, mais aussi très utiles pour la plupart dès que l’on veut
faire des choses un peu plus complexes que jouer une musique de fond.
Nous avons à la base créé plusieurs fonctions, séparant les musiques,
les effets sonores et les voix. Une lecture de notre fichier .ini de configuration nous permet de fixer le volume au démarrage du jeu (modifiable
par la suite). Pourquoi des fonctions différentes ? Car on ne joue pas une
musique de la même façon d’un effet sonore. En effet, une musique doit
se repeter, et il peut-être utile de la mettre en pause, alors qu’une voix ou
un effet sonore simple n’a pas besoin de se répeter ou d’être mis en pause
Page 36
SimKingdom
Rapport de projet
aussi souvent, et au même moment. De plus, l’utilisation de 3 canaux différents nous permet de jouer une musique, un son et une voix en même
temps.
Voici les prototypes de nos différentes fonctions :
procedure
procedure
procedure
procedure
procedure
procedure
procedure
procedure
procedure
init_son; // Initialiser FMOD et les canaux
init_son_var(m,s,v:integer); // Initialise les différents volumes
jouer_musique(music:string);
pause_musique;
stop_musique;
jouer_son(son:string);
jouer_voix(voix:string);
pause_son;
pause_voix;
Nous avons récemment mis en place un système permettant de jouer
des playlist, variant ainsi les musiques au cours du jeu... Cette petite fonctionnalité rendra les parties, nous l’esperons, un peu plus agréables.
7
Moteur graphique
F IG . 24 – Le jeu
7.1
Introduction
Au début, le moteur graphique devait être simplement la partie graphique (sans blague) de notre jeu, une sorte de boucle de jeu. Elle était
nommé "moteur_graphique_map" et contenait tous les appels des fonctions de traçage OpenGL. Mais petit à petit, nous nous sommes apperçu
Page 37
SimKingdom
Rapport de projet
que cette boucle de jeu nous serait également utile pour faire tous nos calcults, action sur les objets, la créature. . . En clair, elle deviendrait la boucle
principale du jeu qui appelle une multitude de fonctions (et procédures)
mais pas simplements des fonctions qui tracent quelque chose à l’écran.
On peut néanmoins décomposer le véritable moteur graphique en plusieurs sous parties qui sont induites dans le code de notre jeu par une
décomposition en fonctions et procédures.
Initialisation
C’est dans le moteur graphique qu’à lieu l’initialisation d’OpenGL et
de GLFW, ainsi que le réglage de la matrice 3D. L’initialisation du moteur
graphique ainsi que les réglages ont été codé par 80122 et 80048.
Rotation, déplacement
Ce sont les fonctions bord, touche, zoom et angle de la classe TJeu qui
permettent au joueur de se déplacer sur la carte. Il est aussi possible au
joueur de revenir au centre de la carte en appuyant sur ctrl-o. L’ensemble
de ces fonctionnalités ont été implémentés par 80122 et 80048.
Skybox
Une skybox a été réalisé afin de rendre le jeu moins froid et plus. . . normal ?
La skybox est tout simplement une boite géante (de la taille maximale selon les paramètres de notre espace) avec des textures ciel pour le ciel et
eau pour l’eau (trop fort).
Traçage général
Tout d’abord, la fonction de traçage générale : Tracer(ModPick : boolean)
qui est une sorte de procédure chapeau qui appelle d’autres fonctions de
traçage et qui indique si on est mode empilement d’objets dans la pile de
noms ou traçage dans la fenêtre de sortie :
– TracObj(ModPick) qui trace TOUS les objets présents sur la carte et
qui appelle la fonction draw_object (qui sera vu plus loin . . . )
– Terrain(i,ModPick) qui affiche le terrain case par case
Page 38
SimKingdom
Rapport de projet
F IG . 25 – La skybox
– Et enfin, CreatureClass.Principal qui appelle la procédure principale
de gestion de la créature qui effectue les animations, puis trace la
créature. (voir la partie sur la Créature dans le rapport)
Ces deux fonctions ont été réalisé par 80122.
Les montagnes
C’est dans le moteur graphique que les montagnes, et leur formes sont
calculés. Etant donné que les montagnes ne change pas dans notre jeu,
elles sont calculé une seule fois lors du début de la partie. La forme des
montagnes dépend du nombre de case montagne adjacente : plus il y en
as, plus le sommet est élevé. Tout les calculs nécessaire se déroule dans la
fonction charger_map de la classe TJeu. Cette partie a été réalisé par 80122.
Les composants
Il faut également tracer tout ce qui est composants OpenGL :
–
–
–
–
–
–
–
Bouton
Flèche
Case à cocher
Compteur
Texte d’édition
ListBox
Barre de défilement
Page 39
SimKingdom
Rapport de projet
L’interface
Puis tracer tout l’interface qui regroupe des composants, des images
(icones ou fond de l’interface) :
1
2
3
4
5
Barre des ressources.
Affichage du mois et de l’année.
Mini-map : indique la position des objets.
Zone de selection du bâtiment que vous désirez construire.
Zone pour faire défiler la liste des bâtiments si elle contient plus de
huit bâtiments.
6 Zone d’information sur les bâtiments une fois construits.
7 Boutons pour accéder aux conseillers : Dame Kristel (F1), Baron Rodot (F2), Sir Benalli (F3), Lady Nath (F4), Pere Petit (F5), Lord Krisboul (F6).
8 Bouton pour accéder aux objectifs (F7).
9 Vitesse du jeu.
Et tracer un fond de l’interface pour faire plus joli (ou en tout cas essayer). . .
Les fenêtres
Et enfin, il faut tracer tout ce qui est fenêtre.
Page 40
SimKingdom
8
Rapport de projet
Moteur physique
Au début, nous pensions que nous allions gérer les collisions dans le
moteur physique, ce que nous n’avons pas fait puisque nous avons trouvé
une autre solution plus adapté à notre type de jeu : un astar qui gère le
contournement des obstacles, ce qui c’est révélé très astucieux.
Puis, nous nous sommes intéressé à "sur quoi pointe la souris ?" avant de
trouver de la documentation sur le picking par nom, ce qui est devenu
notre méthode pour gérer la sélection.
En effet, au début, nous pensions repérer les coordonnées de la souris puis grâce à des calculs mathématiques avec l’angle de rotation, les
déplacements sur les axes x, y et connaitre l’objet pointé par notre souris. . . Hum, finalement, cette méthode ne nous réjouissant pas vraiment
(les mathématiques à haute dose ça donndes boutons.) nous avons poussé
nos recherches et découvert le picking !
Le picking par nom
Pour sélectionner les objets sur la carte, nous avons donc utilisé la méthode du picking par nom. Le principe de cette méthode est le suivant :
lorsque l’on trace notre scène, nous attribuons (enfin, OpenGL) des noms
aux différents objets que nous désirons sélectionner et nous empilons nos
noms dans une pile de nom gérée toute seule par OpenGL (c’est pas beau
ça ?).
Plus précisément, le picking par nom ce déroule en quatre étapes :
1 Passer en mode "sélection" grâce à la fonction glRenderMode(GL_SELECT),
lui fournir un tableau à remplir (un buffer) et créer la pile de noms
glPushName ;
2 Dessiner chaque élément voulu en lui attribuant un nom (GLint)
pour chaque objet juste avant de le dessiner concrètement dans la
fenêtre de rendu grâce à la fonction ou glLoadName ;
3 Sortir du mode "sélection" et récupérer les informations sur le picking (nombre d’éléments cliqué : hits et no de l’élément qui correspond à sa position sur la carte) ;
4 Gérer les informations fournies pour effectuer la sélection ou les actions sur l’objet.
Page 41
SimKingdom
Rapport de projet
Le traçage des objets
Le traçage s’effectue dans deux modes : le mode normal et le mode sélection.
Le premier consiste à tracer nos objets avec leurs textures, couleurs. . . En
appelant la procédure tracer avec le ModPick := False (variable booléenne
qui indique si on affiche ou pas et si on empile le nom de l’objet).
Après, il nous faut tracer les objets en mode "sélection" et stocker les
noms dans la pile de noms d’OpenGL. Pour cela, on appelle la procédure
Picking qui lance le mode "sélection", initialise le buffer de sélection puis
trace les objets de la carte en mode picking, c’est-à-dire en appelant la procédure Tacer avec ModPick := True. Cela a pour effet de tracer les objets en
empilant leurs noms dans la pile des noms.
Les informations données par le picking
Une fois que l’on a tracé les objets en mode picking, on récupère les
informations stockées par OpenGL. Cette opération s’effectue en plusieurs
étapes :
1 On récupère le nombre de hits ;
2 Si le nombre de hits est supérieur à 0 :
– On donne à la variable Selection la valeur True pour effectuer les
actions spécifiques dans la fonction Tracer pour l’objet sélectionné ;
– On récupère ensuite le nom de l’objet sélectionné par la souris ;
– On récupère le type de l’objet sélectionné dans tableau TabPick qui
contient tous les objets de notre carte ;
– On effectue l’action (plutôt plus tard ou immédiatement) correspondante à l’objet ;
3 On revient en mode de traçage normal
Exemple
Cette partie a été réalisé par 80122 avec l’aide de 80120.
Page 42
SimKingdom
Rapport de projet
F IG . 26 – Curseur sur une case
F IG . 27 – Curseur sur un objet (ici une maison)
F IG . 28 – Quand on a cliqué sur un objet !
Page 43
SimKingdom
9
Rapport de projet
Créatures
9.1
Introduction
La créature a une fonction importante dans notre jeu : elle est l’incarnation du joueur dans le royaume. Grâce à elle, le royaume pourra jouir
de nombreux privilèges : augmentation de la production, influence sur la
criminalité, pouvoirs sépciaux ...
Elle a aussi était implanté par une classe. Cette classe contient exclusivment la créature (modèle parsé et près à être affiché) et toute les actions
que touchent à modifier le modèle 3D. Tout ce qui est gestion de la créature ou astar est codé par un autre partie (pour l’astar voir plus bas, pour
la gestion voir CoreCreature)
TCCreature = class
private
My_Creature : TCreature;
TabVertex : Tab2TVertex_mdl;
CurrAnim : TAnimCur;
angle, scale : real;
frame : integer;
procedure reinit_tabvertex; // réinitialise le tableau de vertex à tracer
procedure Animation_mdl; // Procédure d'animation
procedure Traceur_mdl(Picking : boolean); // traceur
procedure Deplacement(var DeplacB : boolean; ArrivC : TDeplac;
var i :integer);
function QuatRotat(Quat : TTransform) : TKey;
public
posx, posy : real;
CSelectionnee : boolean;
Move : TabTDeplac;
constructor Create(x, y : real);
procedure Parseur_mdl(NomMdl : string); // parseur
procedure setAnim(index : integer; boucle : boolean);
procedure Principal(Picking : boolean; var DeplacC : boolean;
mil, x, y, fps : real; ArrivC : TDeplac; var i :integer);
end;
Page 44
SimKingdom
9.2
Rapport de projet
Parseur mdl
Notre créature est un modèle 3D qui fonctionne sur un mode indépendant au .obj cité plus haut. Elle est beaucoup plus complexe et surtout
complète et fait appel aux animations. C’est le seul "objet" de notre jeu qui
pourra se déplacer sur la carte grâce au clic du joueur ! Le déplacement est
géré par l’a-astar (voir plus bas).
Le format de notre créature n’est pas le .3ds ou le .ase comme de nomc
breux projets mais le .mdl. Ce format a été "inventé" par Blizzardpour
ses jeux Warcraft III et World Of Warcraft. Nous utiliserons nous des modèles exportés de Warcraft III. Le .mdl comporte de nombreux avantages par
rapport au .3ds :
– Format simplifiable très facilement selon nos besoin.
– Ouverture et modification direct dans le Bloc Note ou tout autre éditeur de texte. Il ne nécessite pas l’ouverture de 3dsMax ou autre logiciel de 3D comme le .3ds.
– Syntaxe assez simple à comprendre si l’on a déjà fait de la 3D.
– De très nombreux modèles sont à notre disposition, de quoi afficher
n’importe quelle créature fantaisiste sans se casser la tête à chercher
partout sur Internet.
– Nombreux tutoriaux sur le format .mdl dans la communauté francophone de Warcraft III.
C’est ainsi que notre choix a été très vite fait au profit du format .mdl face
au .3ds, de plus nous pouvons coder nous même notre loader mdl sans se
compliquer ...
9.2.1
Structure simplifiée du mdl
Le format mdl s’organise en 3 grandes parties :
– Définition des animations et de la (des) texture(s) utilisée(s).
– Définition du (des) Geoset(s).
– Définition des bones et les PivotPoints.
Un Geoset est une partie du modèle qui utilise une texture. En tout logique, 2 Geosets dans un modèle utiliserons 2 textures différentes, c’est
pour celà qu’ils sont séparés. Un bone ou "os" est une articulation du modèle. Ils sont reliés entre eux et forment le squelette de notre modèle, ce
qui permettra ensuite de l’animer ! Les PivotPoints ou "points de pivot"
représente la position des bones.
Page 45
SimKingdom
Rapport de projet
Pour le moment nous n’utilisons que la (les) texture(s) et une partie du
(des) Geoset(s), les animations viendront plus tard.
9.2.2
Le loader de créature (.mdl)
Notre loader de créature c’est à dire notre loader de .mdl parse le .mdl
pour ensuite envoyer toutes les données à une procédure de traçage. C’est
en gros le même principe que notre loader de .obj.
La partie la plus importante à parser est le Geoset ! C’est lui qui contient
toutes les informations nécessaires au traçage de la créature :
– Les Vertices (ou sommets).
– Les TVertices (ou sommets de texture).
– Les Faces (triangle composé de 3 sommets sur lequel est appliqué
une partie de la texture).
C’est 3 parties sont une suite de nombres (en général des flottants). En
général il y a autant de Vertices que de TVertices, car chaque sommet possède une coordonnée de texture. Les Faces sont toujours un multiples de 3 !
En effet, on récupère 3 numéros dans la définition Faces qui correspondent
au n˚ des Vertices (et donc des TVertices) pour dessiner un triangle texturée. Ainsi, notre parseur stocke dans différents tableaux : les Vertices, les
TVertices et les Faces. Notre créature est un enregistrement de ces 3 tableau
plus d’un chaîne de caractères qui représente la texture.
Nous utilisons des créatures à ou plusieurs Geoset avec animations !
Voici les types que nous avons utilisé pour notre créature :
// Type vertex du mdl
TVertex_mdl = Record
x, y, z : real;
end;
// Type face du mdl
TFace_mdl = Record
V1, V2, V3 : integer;
end;
// Type texture du mdl
TTVertex_mdl = Record
x, y : real;
Page 46
SimKingdom
Rapport de projet
end;
// Tableau de vertex mdl
TabTVertex_mdl = array of TVertex_mdl;
// Tableau de tableau de vertex mdl
Tab2TVertex_mdl = array of array of TVertex_mdl;
// Tableau de texture mdl
TabTTVertex_mdl = array of TTVertex_mdl;
// Tableau de faces mdl
TabTFaces_mdl = array of TFace_mdl;
// Tableau de VertexGroup
TabVertexGroup = array of integer;
// Matrices
TMatrices = array of integer;
// Tableau de Matrices
TabGroups = array of TMatrices;
// Geoset
TGeoset = Record
Vertex : TabTVertex_mdl; // Vertex
Textures : TabTTVertex_mdl; // TVertex
Faces : TabTFaces_mdl; // Faces
VertexGroup : TabVertexGroup; // VertexGroup
Groups : TabGroups; // Matrices
DirTex : string; // Textures
end;
// Tableau de Geosets
TabTGeoset = array of TGeoset;
On envoie ensuite dans le jeu toutes ces informations à la procédure de
traçage qui récupère la texture et la charge (si on est pas en mode picking
pour ajouter la créature dans la pile de nom), et lit toutes les Faces pour tracer un triangle. L’enchainement de triangles permet d’afficher notre créaPage 47
SimKingdom
Rapport de projet
ture. Elle effectue cette opération sur tous les geosets
procedure TCCreature.Traceur_mdl(Picking : boolean);
var
i, j, nFace : integer;
// Tableau de Faces
Faces : TabTFaces_mdl;
// Tableau de Textures
TexVertex : TabTTVertex_mdl;
begin
// Sans pickng //
if not(Picking) then
begin
{Autorise les textures}
glEnable(GL_TEXTURE_2D);
{-----------------------------}
// Récupérations des Geoset //
{-----------------------------}
for i := 0 to length(My_Creature.Geoset)-1 do
begin
// Définition des variables
TexVertex := My_Creature.Geoset[i].Textures;
Faces := My_Creature.Geoset[i].Faces;
// Utilisation de la texture du Geoset
glBindTexture(GL_TEXTURE_2D, TexCreature[i]);
// Récupération des faces //
for j := 0 to length(Faces)-1 do
begin
glColor3f(1,1,1);
glBegin( GL_TRIANGLES );
// Affichage de la face //
// Vertex 1
Page 48
SimKingdom
Rapport de projet
nFace := Faces[j].V1;
glTexCoord2f(TexVertex[nFace].x,1 - TexVertex[nFace].y);
glVertex3f( TabVertex[i,nFace].x, TabVertex[i,nFace].y,
TabVertex[i,nFace].z );
// Vertex 2
nFace := Faces[j].V2;
glTexCoord2f(TexVertex[nFace].x,1 - TexVertex[nFace].y);
glVertex3f( TabVertex[i,nFace].x, TabVertex[i,nFace].y,
TabVertex[i,nFace].z );
// Vertex 3
nFace := Faces[j].V3;
glTexCoord2f(TexVertex[nFace].x,1 - TexVertex[nFace].y);
glVertex3f( TabVertex[i,nFace].x, TabVertex[i,nFace].y,
TabVertex[i,nFace].z );
glEnd;
end;
end;
{On désactive les textures}
glDisable(GL_TEXTURE_2D);
end
// Avec picking //
else
begin
{-----------------------------}
// Récupérations des Geoset //
{-----------------------------}
for i := 0 to length(My_Creature.Geoset)-1 do
begin
// Définition des variables
TexVertex := My_Creature.Geoset[i].Textures;
Faces := My_Creature.Geoset[i].Faces;
// Récupération des faces //
for j := 0 to length(Faces)-1 do
Page 49
SimKingdom
Rapport de projet
begin
glColor3f(1,1,1);
glBegin( GL_TRIANGLES );
// Affichage de la face //
// Vertex 1
nFace := Faces[j].V1;
glVertex3f( TabVertex[i,nFace].x, TabVertex[i,nFace].y,
TabVertex[i,nFace].z );
// Vertex 2
nFace := Faces[j].V2;
glVertex3f( TabVertex[i,nFace].x, TabVertex[i,nFace].y,
TabVertex[i,nFace].z );
// Vertex 3
nFace := Faces[j].V3;
glVertex3f( TabVertex[i,nFace].x, TabVertex[i,nFace].y,
TabVertex[i,nFace].z );
glEnd;
end;
end;
end;
end;
9.3
Format des bones
Pour réaliser les animation de la créature, nous avons dû utiliser la 2e
grande partie des mdl : les bones, ils forment le squelette de la créature et
permettent de l’articuler. Les sommets (ou vertex) sont attachés aux bones
par un méchanisme qui sera étudié plus bas.
Les bones sont composés ainsi :
– Le geoset auquel il est attaché
– L’index de son bone parent (bone auquel est "attaché" ce bone)
Page 50
SimKingdom
Rapport de projet
– Les transformations : translation, rotation et homothétie
Un bone peut contenir soit 1 type de transformation, soit 2 soit les 3.
Chaque type de transformation possède une construction particulière et
permet des modifications différentes sur les bones.
– Les translation permettent de déplacer les bones sur les axes x, y ou
z
– Les rotations permettent de faire tourner les bones dans l’espace autour d’un axe
– Les homothétie permettent d’agrandir les bones
Au cours de l’animation, des transformations différentes sont appliquées à chaque frame sur les bones. Ainsi, les transformations des bones
sont des tableaux qui contiennent plusieurs données de transformations.
Les translations et les homothéties possède donc plusieurs données de
transformation qui sont des enregistrements de 4 valeurs :
– Un temps donné qui permet d’effectuer cette transformation à un
moment précis dans la boucle d’animation
– Une coordonnée x
– Une coordonnée y
– Et une coordonnée z
Pour les rotations, ce sont des enregistrements d’un quaternion (extension des nombres complexes qui permet d’effectuer différents calculs sur
les matrices et souvent utilisé dans les rendus et animations 3D, que du
bonheur !) composés des coordonées (x, y, z, w) et d’un temps
Voici un exemple d’un bone complet possédant les 3 transformations :
Bone "Mesh15" {
0
11
Translation 12 {
6667 0 0 -1.23516
6900 0 0 7.11766
7167 0 0 -1.54375
7433 0 0 6.30507
7667 0 0 -1.23516
Page 51
SimKingdom
Rapport de projet
8333 0 0 0
}
Rotation 12 {
6667 0 0.0654033 0 -0.997859
6900 0.0388058 0.00169976 -0.0389302 0.998487
7167 0 -0.0610487 0 0.998135
7433 -0.0381404 0.0196451 0.0380599 0.998354
7667 0 0.0654033 0 -0.997859
8333 0 0 0 1
}
Scaling 8 {
667 1 1 1
1167 0.875823 0.875823 0.875823
1667 1 1 1
8333 1 1 1
}
}
Et les types utilisés pour nos bones et pivotspoints
// Transformations (unitaire)
TTransform = Record
Time : integer;
x, y, z, w : real;
end;
// Tableau de TTransform (transformations multiples)
TabTTransform = array of TTransform;
// Utilisation geoset
TGeosetUtil = array of integer;
// Bones
TBones = Record
Parent : integer;
MeshID : TGeosetUtil;
Rotation, Translation, Scaling : TabTTransform;
end;
// Tableau de Bones
TabTBones = array of TBones;
Page 52
SimKingdom
Rapport de projet
// Clé
TKey = Record
x, y, z : real;
end;
// Tableau de clés
TabTKey = array of TKey;
(*-----------------*)
(* Points de pivot *)
(*-----------------*)
// Point de pivot
TPivotPoints = Record
x, y, z : real;
end;
// Tableau de point de pivot
TabTPivotPoints = array of TPivotPoints;
9.4
Attachement des bones aux vertex
Chaque bone possède un index et il est stocké dans tableau de bone. Il
sera donc ensuite identifiable par son index.
Chaque geoset de la créature possède, en plus de tout ce qu’on a cité plus
haut en rappel, 2 autres structures :
– Les VertexGroup
– Et les Groups
On utilise ces 2 structures pour lier les vertex du geoset (qui sont stockés dans un tableau de vertex et identifiables par leur index) à un bone.
Le schéma ci-dessous explique ce mode de liaison :
9.5
Principe d’animation
Pendant le jeu, notre créature effectuera 2 animations : "Stand" (Repos)
qui est l’animation par défaut et "Walk" (Marcher) lorsque qu’elle se déplace. Il faut donc tout d’abord, définir l’animation à jouer. Pour cela, nous
Page 53
SimKingdom
Rapport de projet
F IG . 29 – la liaison bones-vertex
Page 54
SimKingdom
Rapport de projet
avons créer 1 procédure : procedure setAnim(index : integer ; boucle : boolean).
Le type Tab2Vertex_mdl est un tableau de vertex qui sera utilisé pour appliquer les transformations et tracer la créature.
Voici les type des séquences d’animations :
// Animations
TAnims = Record
Nom : string;
Debut, Fin, Longueur : integer;
end;
// Tableau d'animations
TabTAnims = array of TAnims;
// Animation en cours
TAnimCur = Record
index : integer;
boucle : boolean;
time_start : real;
end;
setAnim permet de définir l’animation à jouer, si elle se joue en boucle,
et récupère le temps de départ de l’animation et de réinitialiser le tableau
de vertex à tracer. Toutes les animations sont stockées dans un tableaux et
sont identifiables par leur index.
procedure TCCreature.setAnim(index : integer; boucle : boolean);
begin
reinit_tabvertex;
CurrAnim.index := index;
CurrAnim.boucle := boucle;
CurrAnim.time_start := glfwGetTime;
end;
Ensuite à chaque boucle de jeu on entre dans la procédure d’animation : Animation_mdl
Page 55
SimKingdom
Rapport de projet
Tout d’abord, on commence par tracer les bones. Puis on vérifie si on
est pas sortit de l’animation, c’est à dire si le temps n’a pas dépassé la
durée de l’animation.
// Si on est sortit de l'anim
if time > (My_Creature.Animations[CurrAnim.index].Fin)/1000 then
begin
// Si anim jouée en boucle
if CurrAnim.boucle then
begin
CurrAnim.time_start := glfwGetTime;
time := 0.0;
//reinit_tabvertex;
end
else
// Sinon on lance l'animation de base de la créature (Stand)
begin
setAnim(0,true);
Exit;
end;
end;
Puis on parcours le tableau de bone est on effectue les transformations
associées à chaque bone sur les vertex qui y sont attachés. On calcule la
donnée de transformation qui correspond au temps en cours de l’animation puis on effectue les transformations par une interpolation entre la
donnée trouvé et la donnée précédente pour éviter d’avoir une animation
saccadé.
Voici un exemple pour les translation :
// Trouve la position de clé adapté au temps en cours
index := 0;
while (index < length(Transformation)-1)
and (Transformation[index].time/1000 < (time))do inc(index);
if( index > 0 ) then
begin
// Interpolation entre les 2 clés
// Temps qui s'écoule entre les 2 clés
Page 56
SimKingdom
Rapport de projet
deltaTime := (Transformation[index].Time
- Transformation[index-1].Time)/150;
// Position relative de l'interpolation de la position
fraction := (time - Transformation[index-1].Time/150) / deltaTime;
// Valeurs de la clé translation (x, y, z)
Translation.x := Transformation[index-1].x + fraction *
(Transformation[index].x - Transformation[index-1].x);
Translation.y := Transformation[index-1].y + fraction *
(Transformation[index].y - Transformation[index-1].y);
Translation.z := Transformation[index-1].z + fraction *
(Transformation[index].z - Transformation[index-1].z);
end
else
begin
// Valeurs de
Translation.x
Translation.y
Translation.z
end;
la
:=
:=
:=
clé translation (x, y, z)
Transformation[index].x;
Transformation[index].y;
Transformation[index].z;
Il faut ensuite affecter ces valeurs de transformations aux vertex associés aux bones.
Ensuite, on effectue le même travail mais cette fois-ci avec les données
de Rotation du bone.
La seule chose qui chose c’est qu’on applique pas direction les données de
transformation du qutaernion, on les transforme :
// Récupère le quaternion d'avant et le transforme
RotatCoord := QuatRotat(Transformation[index-1]);
Pour cela, il faut appliquer une formule mathématique trouvée à partir
de la matrice de transformation d’un quaternion, ce qui donne (un code
horrible mais bon ...) :
function TCCreature.QuatRotat(Quat : TTransform) : TKey;
var
Mat : TKey;
Page 57
SimKingdom
Rapport de projet
begin
Mat.x := 1 - 2*sqr(Quat.y)- 2*sqr(Quat.z) + 2*Quat.x*Quat.y +
2*Quat.w*Quat.z + 2*Quat.x*Quat.z - 2*Quat.w*Quat.z;
Mat.y := 2*Quat.x*Quat.y - 2*Quat.w*Quat.z + 1 - 2*sqr(Quat.x) 2*sqr(Quat.z) + 2*Quat.y*Quat.z + 2*Quat.y*Quat.z + 2*Quat.w*Quat.x;
Mat.z := 2*Quat.x*Quat.z + 2*Quat.w*Quat.y + 2*Quat.y*Quat.z 2*Quat.w*Quat.x + 1 - 2*sqr(Quat.x) - 2*sqr(Quat.y);
result := Mat;
end;
Vive les maths et les quternions !
Une fois cette transformation effectuée, on applique les translation et
les rotations sur nos vertex :
// Rotation
TabVertex[Geoset,Vertex[j]].x :=
My_Creature.Geoset[Geoset].Vertex[Vertex[j]].x * Rotation.x;
TabVertex[Geoset,Vertex[j]].y :=
My_Creature.Geoset[Geoset].Vertex[Vertex[j]].y * Rotation.y;
TabVertex[Geoset,Vertex[j]].z :=
My_Creature.Geoset[Geoset].Vertex[Vertex[j]].z * Rotation.z;
// Translation
TabVertex[Geoset,Vertex[j]].x :=
My_Creature.Geoset[Geoset].Vertex[Vertex[j]].x + Translation.x;
TabVertex[Geoset,Vertex[j]].y :=
My_Creature.Geoset[Geoset].Vertex[Vertex[j]].y + Translation.y;
TabVertex[Geoset,Vertex[j]].z :=
My_Creature.Geoset[Geoset].Vertex[Vertex[j]].z + Translation.z;
9.6
Procédure principal de la créature
Tout ce que nous avons vu plus haut et lancer à partir d’un procédure,
la procédure principale de la créature :
procedure TCCreature.Principal(Picking : boolean; var DeplacC : boolean;
mil, x, y, fps : real; ArrivC : TDeplac; var i :integer);
var
time : real;
ok : boolean;
Page 58
SimKingdom
Rapport de projet
begin
// Déplace toutes les 1s
time := frame/fps;
if time >= 0.05 then
begin
ok := true;
frame := 0;
end
else
begin
ok := false;
inc(frame);
end;
// Gère les déplacements de la créature
if DeplacC and ok then
Deplacement(DeplacC,ArrivC,i);
glPushMatrix;
// Transformations 3D
glTranslatef(TAILLE_QUADRILLAGE * (posx+0.5) - mil + x,
TAILLE_QUADRILLAGE * (posy+0.5) - mil + y, 0);
glScale(scale,scale,scale);
glRotatef(angle,0,0,1);
// Gestion des animations
Animation_mdl;
// Cercle de sélection
if CSelectionnee then
Tracer_Cercle(0,0,0.5,30,1,0,0);
glColor3f( 1, 1, 1 );
// Traçage des faces avec texture
Traceur_mdl(Picking);
glPopMatrix;
Page 59
SimKingdom
Rapport de projet
end;
Si on est en mode déplacement, on lance la procédure Deplacement qui
incrémente soit la position x, soit la position y, soit les 2 de la créature de
0,5 jusqu’à arriver à la case d’arrivée. On effectue cette action jusqu’à ce
qu’on soit arrivé à la fin du tableau fournit par l’astar (voir plus bas)
Ensuite, on la déplace physiquement avec OpenGL, on la tourne. . . On
gère les animations comme vu plus haut, on trace un cercle autour si elle
a été sélectionné puis on la trace !
Au final, on est passé de ça :
F IG . 30 – la . . . créature hum !
A ça :
Ou même : le mouton avec son cercle de sélection, le mouton et Krisboul !
La création, le parçage, enfin bref, toussa, a été réalisé par 80122.
9.7
L’a-star
Dans une interface. . .
Afin de permettre à notre créature de se déplacer sans encombre jusqu’à son point d’arrivée, il a été nécessaire de faire un a-star, c’est-à-dire
Page 60
SimKingdom
Rapport de projet
F IG . 31 – ca poutre un max
Page 61
SimKingdom
Rapport de projet
F IG . 32 – avec le cercle de sélection
F IG . 33 – le cochon
Page 62
SimKingdom
Rapport de projet
F IG . 34 – notre prof préféré :D
Page 63
SimKingdom
Rapport de projet
un algorithme de calcul du plus court chemin. Nous avons d’abord implémenter cette a-star via une interface delphi, dans le but de pouvoir facilement visualisé son efficacité. Etant donné la manière dont est stocké
le terrain, nous avons choisi d’utiliser la méthode dite du "case pas case",
au détriment de la méthode dite "des surfaces". Avec cette méthode, nous
avons choisi d’utiliser un tableau contenant par case un enregistrement
contenant ceci :
– un état ;
– des coordonnées (abscisse, ordonnée) ;
– des coordonnées "prédécesseur" ;
– des coûts.
L’état indique si la case est libre ou non, et si elle se trouve dans la liste
ouverte ou fermée (ces deux listes seront expliquées par la suite), ou si elle
forme une partie du chemin.
Les coordonnées "prédécesseur" correspondent aux coordonnées de la
case d’où l’on vient.
Les coûts correspondent à une distance restante et une distance déjà effectuée, ils seront explicités par la suite.
L’utilisation de deux listes permet de stocker le chemin définitif (liste
ouverte) et de stocker les cases possibles pour le chemin définitif (liste
fermée).
Afin de calculer le plus court chemin, nous utilisons un astar qui calcul
deux coûts :
– le premier donne une estimation de la distance qu’il reste à parcourir,
il est calculé en allant de la case en cours jusqu’à la case d’arrivée
en ignorant les obstacles et en ne se déplaçant que verticalement ou
horizontalement ;
– le second donne la distance déjà effectuée, c’est-à-dire celle comprise
entre la case départ et la case en cours.
Maintenant que nous avons exposé ce que nous avons dû utiliser, expliquons comment fonctionne l’a-star sur une interface. Nous utiliserons
pour cela un exemple simple comme suit :
– Rouge : case de départ
– Bleu : case d’arrivée
– Noir : obstacles
Pour calculer le meilleur chemin, nous procéderons en plusieurs étapes.
La première consiste à mettre les cases adjacentes à la case en cours, et qui
ne sont pas des obstacles, dans la liste ouverte de la manière suivante :
Page 64
SimKingdom
Rapport de projet
F IG . 35 – fonctionnement de l’astar : au début
procedure aelo(Point: p_elt);
var
i: Integer;
PTemp: p_elt;
place: boolean;
begin
i := 0;
place := false;
if listeouverte.Longueur > 0 then
begin
while ( i < listeouverte.Longueur ) and not place do
begin
PTemp := listeouverte.Enieme(i).Contenu;
if Point.coutf < PTemp.coutf then
begin
listeouverte.InsererMaillon(Point, i);
place := true;
end;
i := i + 1;
end;
if not place then
listeouverte.AjouterMaillon(Point);
end
else
listeouverte.AjouterMaillon(Point);
end;
Page 65
SimKingdom
Rapport de projet
Maintenant que nous avons les cases adjacentes, il nous faut trouver la
case qui servira au chemin définitif. C’est ici qu’interviennent les coûts. Le
premier (décris précédement) est implémenté comme suit :
function ctcpc(Ptemp:p_elt) :integer;
var
test : boolean;
i, j : integer;
begin
i := ptemp.abscisse;
j := ptemp.ordonne;
test := (j-1 >= 0) and (i-1 >= 0) and (j+1 <= dim) and (i+1 <= dim);
if test and
((((matrice[i, (j+1)]^.etat) = 1) and ((matrice[(i+1), j]^.etat) = 1))
or (((matrice[i, (j-1)]^.etat) = 1) and ((matrice[(i-1), j]^.etat) = 1))
or (((matrice[i, (j+1)]^.etat) = 1) and ((matrice[(i-1), j]^.etat) = 1))
or (((matrice[i, (j-1)]^.etat) = 1) and ((matrice[(i+1), j]^.etat) = 1)))
then
result := 150
else
begin
if ((abs(ptemp.pere - ptemp.abscisse) + abs(ptemp.mere - ptemp.ordonne))) = 1
result := 10
else
result := 14;
end;
end;
La première partie sert à empecher de prendre une diagonale entre deux
obstacles. Le second (décris précédement) est coder comme suit :
couth := (10*(abs(abscisse - x_arr) + abs(ordonnee - y_arr)));
Pour obtenir la case qui servira au chemin, nous comparons les différents coûts pour chaque case adjacente à celle en cours. Le plus petit coût
est celui retenu, la case ayant ce dernier est placée dans la liste ouverte.
– Gris : case se situant dans la liste fermée
– Jaune : case présente dans la liste ouverte
Afin d’obtenir le chemin final, nous réiterons le procédé jusqu’à arrivé
à la case d’arrivé, une fois cette dernière atteinte, la liste ouverte contiendra toute les cases du chemin. Pour tracer le chemin sur l’interface, nous
utilisons les coordonnées "prédécesseur", puisqu’elles connaissent toutes
Page 66
SimKingdom
Rapport de projet
F IG . 36 – Le fonctionnement de l’astar en cours de route
leurs prédécesseurs respectifs, il ne nous reste plus qu’à donner une couleur au chemin, et nous aurons tracer le chemin le plus court.
F IG . 37 – Le chemin calculé par notre Astar
Dans le jeu. . .
Une fois l’a-star implémenté dans une interface, il a fallu l’implémenter
dans le jeu. Pour cela, nous utilisons une classe TAstar dont le contenu est
fortement identique à celui dans l’interface :
TAstar = class
private
matrice: array of array of p_elt;
x_arr, y_arr : integer; //arrivee
pc_x,pc_y : integer; //parents en cours
Page 67
SimKingdom
Rapport de projet
listeouverte, listefermee : TChaine;
dim : integer;
procedure init_matrice ;
procedure close_matrice;
function principale(a, b : p_elt):boolean;
procedure init_liste;
procedure close_liste;
function edlo (P : p_elt):integer;
function edlf(P:p_elt):integer;
procedure aelo(Point: p_elt);
function ctcpc(Ptemp:p_elt) :integer;
procedure acavlo( i, j,dim :Integer );
procedure cpc(var Point: p_elt);
procedure aff_chemin(x, y: Integer);
function Recherche(x, y : integer; Move : TabTDeplac) : boolean;
procedure reset_terrain;
public
procedure Generer(nb_cases : integer; TabMap : TTabOccup); // génère la mat
function Calcul(dep_x, dep_y, arr_x, arr_y : integer; var Move : TabTDeplac
end;
Nous appelons la fonction calcul pour lancer l’a-star. Dans cette dernière, nous testons si il y a un chemin existant et si c’est le cas, nous parcours le tableau à la recherche du chemin de la manière suivante :
if not(bool) then
begin
while (x <> arr_x) or (y <> arr_y) do
begin
a := -1;
bool := true;
while (a <= 1) and bool do
begin
b := -1;
while (b <= 1) and bool do
begin
if (x + a >= 0) and (x + a < dim) and (y + b >= 0)
and (y + b < dim) then
begin
if (matrice[x+a,y+b]^.etat = 2)
and not(Recherche(x+a,y+b,Move)) then
begin
Page 68
SimKingdom
Rapport de projet
x := x + a;
y := y + b;
setlength(Move,i+1);
Move[i].x := x;
Move[i].y := y;
inc(i);
bool := false
end;
end;
inc(b);
end;
inc(a);
end;
end;
result := true;
end
else result := false;
Finalement, on fait un parcours des cases adjacentes à la case en cours
pour retrouver le bon chemin.
Cette partie a été réalisé par 80120 avec l’aide de 80122 (implémentation et correction des bugs).
10
Editeur de cartes
Principe
Nous avons décidé de réaliser un éditeur de cartes dès le début (difficile quand on ne connait pas encore Delphi ...) pour générer facilement nos
cartes qui seront ensuite affichées dans notre jeu par parsage d’un fichier
*.map.
L’éditeur permet de générer une carte sur laquelle sont placés les objets
de base qui seront chargés par le moteur graphique au début du jeu, les
différents objets sont :
– Arbres
– Montagnes
– Eau
– Ressources (or et pierre)
Page 69
SimKingdom
Rapport de projet
F IG . 38 – L’éditeur de carte
Fonctions de l’éditeur
Notre éditeur est doté de plusieurs fonctions pratiques pour permettre
de créer facilement et rapidement une carte jouable.
– Génération aléatoire d’une carte avec de l’eau et/ou de la montagne
et/ou des arbres
– Choisir une texture et une taille
– Placer des objets un par un dont les ressources (pierre et or)
– Effacer un objet
– Afficher une grille pour repérer les cases
Génération de la carte
Avant de pouvoir placer les objets sur la carte, il faut la générer. Pour
cela, il faut choisir certains paramètres initiaux.
Tout d’abord, il faut choisir la texture qui sera utilisée :
– Gazon
– Herbe
– Herbe sèche
– Roche
Ensuite la taille de la carte (toutes les cartes sont carrées) :
– Petite (302 cases)
– Moyenne (502 cases)
Page 70
SimKingdom
Rapport de projet
– Grande (1002 cases)
Il est possible de placer aléatoirement des objets (arbres, eau, montagnes) grâce à la génération de la carte. Ainsi, la carte sera déjà remplie
(utile si l’on veut beaucoup d’objets). Pour celà il suffit de faire varier les
différentes TrackBars. Les positions initiales sont 0.
Enfin, pour générer la carte il suffit d’appuyer sur le bouton "Générer". Une série d’information sur la carte s’afficheront sur la droite du programme : longueur et largeur en pixels (une case fait 20 pixels), texture
utilisée, nombre de cases (largeur×longueur), occupation totale de la carte
par les objets générés, occupation en fonction du type de l’objet (exprimées
en %) : arbres, eau, montagnes, ressources.
F IG . 39 – une carte généré par notre éditeur
Placement des objets
Pour placer des objets il suffit de cliquer sur son icône (un message
dans la barre de statut vous indiquera l’objet choisi) puis de cliquer sur la
carte à l’emplacement où vous souhaitez placer l’objet.
Page 71
SimKingdom
Rapport de projet
Pour faciliter l’utilisation de l’éditeur, deux petites fonctionnalités pourront nous être utile :
– La gomme : elle permet d’effacer un objet, elle fonctionne sur le
même principe que le placement des objets.
– La grille : affichage d’une grille jaune qui décompose la carte en
cases. Pratique pour placer un objet précisément.
Sauvegarder et charger un *.map
Une des fonctionnalités les plus importantes de cet éditeur sont la possibiliter de charger une carte déjà faite auparavant grâce à l’éditeur. Le
menu "Charger" de l’éditeur est prévu à cet effet. Il affichera la carte avec
sa texture, sa taille, ses objets et affichera les informations relatives à la
carte.
Et enfin, il est bien sûr possible de sauvegarder notre carte gâce au
menu "Sauvegarder" ou au bouton présent sur la fiche. L’éditeur enregistrera notre carte au format *.map ci-dessous :
Texture
[Texture de la carte]
Cases
[Nombre de cases en largeur (ou longueur)]
[type de l'objet 1]
[coordonnée x] [coordonnée y]
[type de l'objet 2]
[coordonnée x] [coordonnée y]
..
.
[type du dernier objet]
[coordonnée x] [coordonnée y]
Exemple :
Texture
Herbe
Cases
30
eau
0 0
Page 72
SimKingdom
Rapport de projet
or
0 1
pierre
0 2
eau
0 8
arbre
0 12
montagne
0 23
Notre carte est ainsi prête à être affichée par le moteur graphique.
Aide
Un menu d’aide est disponible dans l’éditeur (F1) et vous permet d’obtenir des informations sur :
– Comment générer une carte
– Comment placer un objet
– Comment sauvegarder/charger
11
11.0.1
Editeur de bâtiments
Introduction
Comme nous l’avons vu lors de nos précédentes soutenances, nos batiments et objets sont générés a partir de notre fonction draw_object qui se
base sur notre format .obj que nous ne rapellerons plus.
Bien que facilement lisible et éditable, il est assez compliqué de réaliser
des formes géométriques complexes simplement à partir d’une feuille de
papier milimetrée et d’un plan (~x, ~y, ~z). . . C’est donc dans cette optique
que l’éditeur de batiments a été réalisé lors de la troisième soutenance.
Celui-ci a pour particularité majeure d’être programmé en OpenGL (via
notamment les composants du menu) et d’être entièrement programmé
en objet.
11.0.2
De l’intérêt de la POO
Comme on peut le voir sur l’image, l’interface de l’éditeur comprend
de nombreuses occurences de mêmes objets : la notion de POO a donc été
Page 73
SimKingdom
Rapport de projet
F IG . 40 – l’aide
F IG . 41 – l’interface de l’éditeur de batiments
Page 74
SimKingdom
Rapport de projet
pleinement exploité pour l’application. Ainsi, chacun des 4 écrans qui représentent la vue de face, de côté, de haut et la vue 3d sont tous issues
de la même classe T_Ecran. Voici la déclaration de la classe T_Ecran, qui
comprend un grand nombre de fonction, puisque l’essentiel des fonctionnalités de l’éditeur se joue sur ces écrans.
T_Ecran = class
protected
start : boolean;
r,g,b:real;
num_polygone:integer;
position_x,position_y,echelle,nbc,tc:integer;
function Calcul_Milieu(Objet : T_Obj ; NbPoly : integer):T_Coord3;
function New_Coord(x1,y1,x2,y2:integer):T_Coord;
public
pl:string;
mode:string;
dpx,dpy:real;
procedure Init_Color(num_polygone,r,g,b:integer);
function Afficher_Coordonnees(plan:string;h,xs,ys:integer):string;
procedure Afficher_Ecran(pos_x,pos_y,tcase,nbcases,ech:integer);
function Focus(h,xs,ys:integer):boolean;
procedure Tracer_Point(px,py:integer;r,g,b:real);
procedure Afficher_Obj(var obj:T_Obj;h,xs,ys,Nb,C:integer;
Color:array of T_Color;cgauche:boolean);
function GetSelection(var obj:T_Obj;h,xs,ys:integer):t_coord3;
function Convertir_Coord(x,y,z:real):T_Coord;
function Focus_Point(h,xs,ys,px,py:integer):boolean;
procedure Surbrillance_Point(px,py:integer);
function GetCoordonnees(h,xs,ys:integer):T_Coord2;
procedure DeSel(var Obj:T_Obj);
procedure Ajout_Afficher(NewObj:T_Obj;Nb_Poly,Nb_Pts:integer);
function Ajout_NewPoint(var NewObj : T_Obj;h,xs,ys:integer;num_poly,
num_point,type_gl:integer;Couleur:T_Color;Tex:integer):T_NP;
procedure Ajout_LnTemp(NewObj:T_Obj;h,xs,ys,nb_poly,nb_pts:integer);
procedure Modifier_Point(var Objet:T_Obj;num_poly,num_pts,h,xs,ys:integer);
procedure Supprimer_Polygone(var Objet:T_Obj;num_poly,h,xs,ys:integer);
end;
L’aperçu 3D est un peu différent des autres écrans : c’est une classe enfant qui hérite des particularités de la classe T_Ecran et en ajoute d’autre.
Voici sa déclaration :
Page 75
SimKingdom
Rapport de projet
T_Ecran3d = class(T_Ecran)
public
procedure Ecran_Apercu(pos_x,pos_y,tcase,nbcases:integer);
procedure Tracer_Objet_3D(Mode:string;Objet:T_Obj;
Nb_Vertex:integer;xb,yb,zb:real;zoom:integer;C:integer;Color:array of T_Color);
procedure Apercu_3D(mode:string;dx,dy:integer;axe_x,axe_y,
zoom_vue:integer;w,h:integer;objet:T_obj;
Nb_Vertex:integer;C:integer;Color:array of T_Color);
end;
11.0.3
La fonctionnalité avant tout
Afin de rendre la création des bâtiments facile, de nombreux raccourcis clavier ont été ajoutés (ctrl+s,entrer,tab,. . . ), ainsi qu’une barre de message :
F IG . 42 – la barre de message
De même, l’affichage 3D permet de voir le bâtiment sous toutes les coutures, de zoomer,. . .
Il est aussi possible via la checkbox apercu texture/couleur de voir le bâtiment texturé et coloré tel qu’il apparaitra dans le jeu ou de la même couleur que les polygones des écrans.
Enfin, un aperçu de la texture ou de la couleur spécifié par l’utilisateur est
également possible : Nous avons réalisé depuis un nouveau mode d’affichage, en 3D fil de fer, dont voici un exemple :
12
Editeur de scénarios
Une fois le mode scénario implémenté, nous avons décidé de réaliser
un outil afin de nous faciliter la création des campagnes.
Cet outil à été réaliser de manière à être très simple à utiliser, son interface est donc très simple tout comme l’aide qui l’accompagne. Cela permet
ainsi au joueur qui le désire de créer un nouveau scénario ou même une
campagne entière s’il le désire, en utilisant les cartes du jeu déjà existante
ou des cartes qu’il aura préalablement crée via l’éditeur de carte.
L’éditeur de campagne récupère les valeurs données par l’utilisateur et
génére deux fichiers : un fichier *.snr et un fichier *.txt.
Page 76
SimKingdom
Rapport de projet
F IG . 43 – aperçu en mode 3D fil de fer
F IG . 44 – L’éditeur de scénario
Page 77
SimKingdom
Rapport de projet
Le fichier *.snr contient les objectifs à atteindre ainsi que le nom de la
carte à utiliser. C’est ce fichier qui est parser par le jeu pour être exploité
par le système de scénario.
Le fichier *.txt l’accompagnant comprend tout simplement l’histoire de
notre scénario. Il est affiché lors du choix du scénario.
F IG . 45 – Les fichiers générés
L’éditeur de scénario a été réalisé par 80048 avec l’aide de 80120.
13
Conclusion
Cette année de Sup est passé très rapidement (surtout vers la fin), et
le projet y est pour quelque chose. Au premier abord sur-réaliste, la réalisation d’un jeu vidéo complet est vite devenue le point central de nos vie
de gentils geeks, occupant nos rares moments libres, nos nuits, nos journées, nos cours d’élecs. . . bref. En effet quoi de plus passionnant pour nous
mordus d’informatique ?
Aujourd’hui, nous sommes extremement fiers du résultat que nous
avons obtenus. Nous avons réunie en un seul plusieurs jeux sur lesquels
nous avions passé maintes heures, c’est-à-dire SimCity (inspiration principal), Caesar III, Black and White,. . . De plus, le jeu est entièrement jouable,
il est intéressant, on peut le faire évoluer (via nos éditeurs), sa durée de
vie est illimité, et les graphismes sont époustouflants (tout est relatif hein).
Qui plus est il est dénué de bugs (la classe). Enfin, nous avons réussi a faire
le jeu dont nous rêvions : le jeu est fidèle à la vision que nous en avions au
début de l’année, lors de la rédaction du cahier des charges, voire même
mieux.
Page 78
SimKingdom
Rapport de projet
Ce projet nous a aussi beaucoup appris et ce à tous les niveaux : les
joies et les difficultés du travail en groupe, la POO (grande révélation), la
3D, la réalisation d’un projet complet et de tout ce qui va autour (rapports,
soutenances). . . C’est donc heureux et exténués par ces longues nuits de
codes que nous terminons ce rapport et cette année.
14
Tableau récapitulatif : qui a fait quoi
Légende :
– A : a fourni une aide
– E : a effectué le travail
Qui à coder quoi dans SimKingdom
Page 79
SimKingdom
Fichier
AntUtils
Astar
Class_Creature
Construct
getip
highscore
mode_scenario
moteur_graphique_draw_object
moteur_graphique_map
moteur_graphique_parseur
op_chaine
s_objets_u
s_textures
skybox
son_fonctions
type_graph
type_mdl
interface_composant_button
interface_composant_button_arrow
interface_composant_checkbox
interface_composant_combobox
interface_composant_compteur
interface_composant_edit
interface_composant_listbox
interface_composant_trackbar
charger_icones
composant_fenetre
composant_graphique
composant_minimap
composant_ressources
composant_selactive
composant_tab_icone
composant_tableau
composant_temps
composant_vitesse
conseillers
Rapport de projet
Nb Lignes 80018
132
477
902
445
55
E
86
E
65
304
2759
45
134
55
174
100
103
E
78
140
75
116
70
117
101
116
77
84
60
138
302
204
170
223
225
215
100
118
390
A
80048
E
80120
80122
E
E
A
E
A
E
A
E
A
A
A
E
A
E
E
E
E
E
E
E
E
E
E
E
E
E
E
E
E
E
E
E
A
A
E
E
E
E
E
E
E
E
A
E
A
Page 80
A
SimKingdom
Fichier
Nb Lignes
open_fenetres
179
corebatiments
558
corebudgets
127
corecreature
50
corecs
142
coreministere
227
corepopulation
137
corescenario
168
coretech
189
SimKingdom.dpr
689
Rapport de projet
80018
80048
E
E
E
A
E
80120
A
E
E
E
E
E
80122
A
E
A
E
A
A
E
E
Page 81

Documents pareils