51 Zone 51 - Deadly Area LAWSON Wilfried LEFORTIER Damien MOURET Romain SAVIN Alexis

La page est créée Nathan Thibault
 
CONTINUER À LIRE
51 Zone 51 - Deadly Area LAWSON Wilfried LEFORTIER Damien MOURET Romain SAVIN Alexis
LAWSON Wilfried
LEFORTIER Damien
MOURET Romain
SAVIN Alexis

           Zone 51 - Deadly Area

                           3e Soutenance - Avril 2006

                            51
                          ZONE

             http ://zone51da.free.fr/
51 Zone 51 - Deadly Area LAWSON Wilfried LEFORTIER Damien MOURET Romain SAVIN Alexis
Sommaire
1 Introduction                  3

2 Menus                         4

3 Lumières et Shaders          7

4 Cg                            9

5 OpenGL Shading Language       12

6 Le terrain                    17

7 Réseau                       19

8 Screenshots                   22

9 Conclusion                    23

                            2
51 Zone 51 - Deadly Area LAWSON Wilfried LEFORTIER Damien MOURET Romain SAVIN Alexis
1     Introduction
     Nous voici donc arrivé à l’echéance de la seconde soutenance, notre projet
avance en accord avec le planning, les moteurs physique et graphique approchant
de l’aboutissement et le son étant déjà terminé. Nous avons particulièrement
travaillé sur l’aspect graphique avec l’intégration de menus et des shaders pour
l’éclairage notamment. Le réseau n’a pas été laissé de côté vu que notre jeu se
veut principalement multijoueur, il est en cous de déboguage actuellement. . .

    Nous n’avons pas utiliser d’objets pour les vaisseaux de notre jeu alors que
ceux-ci avaient été indispensables pour d’autres parties (e.g., le son), nous avons
préféré utiliser ici des structures simples. Nous avons donc mis en place un fichier
struct.pas qui regroupent différents types

   Vous trouverez dans ce rapport nos explications détaillées concernant l’avan-
cement et le contenu des différentes parties.

                                          3
51 Zone 51 - Deadly Area LAWSON Wilfried LEFORTIER Damien MOURET Romain SAVIN Alexis
2     Menus
    Lors de la précédente soutenance nous avions présenté une très brève ébauche
de menu. Le seul objectif de cette présentation était de donner un aperçu sur
le fonctionnement de notre menu, quel mode d’afichage nous choisirerions. La
librairie Glut s’avérant peu compatible avec Glfw, nous avons donc opté pour
un menu texturé.

2.1    Fonctionnement
     Un tampon carré est crée au sein de notre fenêtre Opengl. Ce dernier com-
porte une texture : notre menu. A l’aide de la fonction glfwGetMousePosition,
nous récupérons la position de la souris. Si les coordonnées de la souris cor-
respondent aux coordonnées d’emplacement d’un bouton dans le menu, une
nouvelle texture s’implémente sur notre précédent tampon carré. Le cas échéant,
l’affichage ne connait aucun changement.

   Ensuite, la fonction glfwGetMouseButton permet de savoir si un clic (bouton
gauche) a été effectué. Selon le bouton sur lequel le clic a eu lieu, le menu laisse
place soit au jeu ou ferme l’application.

    L’affichage complet du menu s’opère grâce à une fonction nommée afficher
menu. afficher menu est une fonction qui prend un paramètre un booléen. Si
ce booléen est de valeur « vraie », le menu s’affiche, si ce n’est pas le cas, le
menu ne s’affiche pas ou disparaı̂t. Bien entendu, chaque jeu débutant sur un
menu, la variable est donc initialisée à la valeur « vraie ». Un clic change cette
valeur pour effectuer les actions précédemment vu : entrer dans le jeu, ou fermer
l’application.

2.2    Interface graphique
    Le logiciel Photoshop CS fut d’une grande aide dans l’élaboration du menu.
Pour bien rejoindre le contexte du jeu que je rappelle brièvement : Des courses
de vaisseaux dans un monde post apocalyptique dans le but de capturer des
flags, l’image d’un canyon, abrupte et desertique a été pris comme fond. S’y
trouve légérement superposé un fond composé de plaques métalliques, similaire
à celui du site du jeu. Toujours par souci de coller au contexte, les teintes,
sombres, varient entre l’orange et le marron foncé rappellant l’idée d’un monde
assez désert, sombre et ravagé par une guerre sans précédente.

    La police utilisée pour les différents textes apparaı̂ssant dans le menu n’est
pas en reste. Son style est assez futuriste, science fiction et annonce l’époque du
jeu c’est à dire bien après notre époque. Si on fait un peu attention ou si l’on

                                          4
est un fervent fan de la saga, on peut remarquer qu’il s’agit de la police utilisée
pour les films « ALIEN » qui compose le titre du jeu (en haut à gauche). Une
autre texture a été utilisé pour les boutons. Celle ci reste toujours issue d’une
série de science fiction à succès : Stargate. La figure 1 montre l’aspect de notre
menu.

                                Fig. 1 – Le menu

2.3    Projet pour la suite
     Laisser le menu tel qu’il est serait problématique pour la suite du dévelop-
pement du jeu. En effet, si le nombre de boutons devait changer ou si les pages
à relier s’avèraient nombreuses, il faudrait tout reprendre depuis le début. Un
travail fastidieux.

    Dans cette optique, nous nous penchons sur une nouvelle forme de gestion
du menu. Elle prendrait en compte un nouveau type nommé TBouton. Ce type
correspondrait à un tableau regroupant des textures, des numéros de pages et
des coordonées. Les textures variraient selon l’action effectué : si l’on se trouve
sur un bouton, si l’on clique dessus. Les numéros de pages permettraient de
situer sur quelle page du menu se trouve le bouton sur lequel nous travaillons.

                                         5
Enfin les coordonnées correspondraient aux coordonnées du bouton. Des para-
mètres nécessaire à la fonction glfwGetMouseButton comme nous l’avons vu
précedemment. A l’aide différentes procédure comme addbouton, createbouton
ou encore affichebouton, nous pourrions manier ces différents boutons. Seul le
fond du menu resterait réellement statique et ne connaitraı̂t pas de changements.

                                        6
3     Lumières et Shaders
3.1     Lumières
    On a tout d’abord pensé simuler un soleil au dessus de notre scène via
OpenGL, avec celui-ci on peut créer une scène contenant jusqu’à huit sources
de lumière. Ces sources peuvent être de type ’omnidirectionnel’ (la source émet
de la lumière uniformément dans toutes les directions, comme le soleil), ou ’spot’
(la lumière n’est émise que dans un cône).

   La lumière émise par une source est formée de trois composantes auxquelles
on peut affecter une couleur :

    – La composante diffuse qui est réfléchie par un objet dans toutes les direc-
      tions
    – La composante spéculaire qui correspond à la lumière qui est réfléchie dans
      une direction privilégiée (et qui est donc à l’origine de l’effet de brillance)
    – La composante ambiante : une lumière non directionnelle, que l’on peut
      considérer comme issue des multiples réflexions de rayons lumineux

    Il faut ensuite positionner la source de lumière dont la 4e composante définie
le type de lumière : spot ou omnidirectionnelle ; à laquelle on peut ajouter des
paramètres d’attenuation, ils sont au nombre de 3 : le facteur d’atténuation
constante, le facteur d’atténuation linéaire et le facteur d’atténuation quadra-
tique. Si on note respectivement Ac, Al et Aq ces trois coefficients, l’intensité
reçue par un point P situé à une distance d de la source lumineuse est divisée
par Ac + Al × d + Aq × d × d. Par défaut, Ac = 1 et Al = Aq = 0, ce qui
correspond à une atténuation nulle (division par 1).
Enfin il peut être bon de modifier le coefficient de brillance afin d’obtenir un
effet plus réaliste.

    Pour résumer tout cela au niveau de l’implémentation on obtient en Delphi :
    // Définition des couleurs et de la position de la lumière //

     ...

     L0pos[3] := 0; // Lampe omnidirectionnelle

    // Paramétrage de la lumière //

     glEnable(GL_LIGHTING);

     // L0dif et L0spe : vecteurs de GlFloat de 3 cases
     glLightfv(GL_LIGHT0,GL_DIFFUSE,@L0dif);
     glLightfv(GL_LIGHT0,GL_SPECULAR,@L0spe);

                                           7
// L0pos : vecteur de GlFloat de 4 cases
   glLightfv(GL_LIGHT0,GL_POSITION,@L0pos);

   glLightf(GL_LIGHT0,GL_LINEAR_ATTENUATION, 2.0);

  // Paramétrage du matériau //

   glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,50);

   Mais les lumières ainsi définies sont limitées et ne permettent pas toujours
d’obtenir un rendu de qualité, on s’est donc ensuite orienté vers l’utilisation de
shaders dont il est question dans la partie suivante.

3.2    Shaders
     Les shaders sont des programmes, écrits dans un langage pseudo-assembleur
ou plus récemment pseudo-C, directement executable par la carte graphique. Il
existe deux types de shaders : les vertex shaders (ou encore vertex programs)
et les pixel shaders (ou encore fragment programs, ou fragment shaders). Tous
deux fonctionnent de la même manière, excepté qu’ils remplissent chacun un
rôle différent.

     Le vertex shader vient remplacer les parties « transformation et éclairage »
du pipeline de rendu, le pixel shader vient lui remplacer les parties « texturage,
filtrage et mélange » du pipeline. La grande force des shaders c’est qu’il n’y
a qu’à faire marcher son esprit créatif pour obtenir des effets toujours plus
impressionnants, il n’y a quasi aucune limite aux effets possibles.

    La programmation des shaders se fait par le biais de 3 langages haut niveau
au choix. Le Cg (C for graphics), développé par nVidia, le plus utilisé, il est
compatible avec DirectX et OpenGL. Le HLSL, développé par Microsoft, est
spécifique à DirectX, enfin le GLSL, le plus récent des trois langages spécifique
à OpenGL.

  On a donc testé les langages Cg et GLSL, les deux seuls possibles avec
OpenGL, pour ainsi tester les différentes possibilités.

                                         8
4     Cg
   Le langage Cg (C for Graphics) est le langage crée par nVidia pour la pro-
grammation des pixel et des vertex shaders. C’est un langage pseudo-C et utilise
donc la même syntaxe, même si des fonctions et des types de donnée nouveaux
ont été ajouté pour permettre au Cg d’être plus pratique pour la programmation
graphique.

4.1    Incorporation d’un shader program dans une appli-
       cation Delphi
    Il faut utiliser les librairies Cg et CgGL fournies par NVIDIA pour les
développeurs et qui permettent de charger des shaders et de les utiliser, cela
selon la démarche suivante :

    - Création du contexte avec cgCreateContext().
    - Lécture du fichier (.cg) contenant le shader avec cgCreateProgramFrom-
      File.
    - Chargement du shader avec cgGLLoadProgram.
    - Définir les paramètres dont le shader a besoin en entrée grâce au type :
      CGparameter.
    - Lier l’ensemble avec cgGLBindProgram(gCGprogram).
    - Utiliser le shader avec cgGLEnableProfile(gCGprofile).
    - Enfin, il faut penser à libérer la mémoire lors de la fermeture de l’applica-
      tion avec cgDestroyProgram(gCGprogram) et cgDestroyContext(gCGcontext)

   Tout cela étant ajouté dans les différentes procédures que nous avions déjà
mises en place : glInitWnd, glKillWnd, glMain, . . .

4.2    Le fichier Cg
    Nous allons voir comment implémenter un vertex shader en Cg à travers
un exemple simple permettant l’éclairage d’un objet en calculant les lumières
spéculaire et diffuse pour chaque vertex.

    Les structures
struct appin
{
float4 Position : POSITION;
float4 Normal : NORMAL;
};

                                         9
Cette structure contient deux variables : Position et Normal, ces données étant
différentes pour chaque vertex. Les mots clefs - correspondant à des attribues
prédéfinies - POSITION et NORMAL permettent de signifier au compilateur
que les variables sont associées à ces attribus.

struct vertout
{
    float4 HPosition : POSITION;
    float4 Color0    : COLOR0;
};

Cette seconde structure permet de lier le vextex au fragment, elle contient deux
variables. HPosition correspond à la position du vertex dans les coordonnées
homogènesI et Color0 à sa couleur.

       Les paramètres
fragment main (appin IN,
               uniform float4x4 ModelViewProjection,
               uniform float4x4 ModelViewInverse,
             uniform float4 EyePosition,
               uniform float4 LightVector )
{
Nous sommes en train de définir un vertex shader, main() doit donc prendre en
entrée un structure « application-to-vertex » et retourner une structure « fragment-
to-vertex ». Les 4 paramètres - deux matrices et deux vecteurs - présents sont
données par l’application comme nous l’avons déjà vu dans le paragraphe concer-
nant l’incorporation dans une application Delphi.
Précisons juste que la matrice ModelViewProjection permet d’obtenir les coor-
données de clipping du vertex.

    Les transformations basiques On précise qu’un vertex shader doit calcu-
ler la position des vertex dans l’espace de clipping donnant ainsi les coordonées
du vertex dans l’espace du model. De plus vu que notre shader doit permettre
un éclairage de notre objet dans le « eye space » il faut transformer le vecteur
IN.Normal en coordonnées de cet espace. Tout cela est fait de la manière suivant :

        fragment OUT;

        // Transforme la position du vertex en coordonnées de clipping.
   I
     Ces coordonnées largement utilisées en infographie rendent les calculs possibles dans
l’espace projectif comme les coordonnées cartésiennes le font dans l’espace euclidien

                                            10
OUT.Hposition = mul(ModelViewProjection, IN.Position );

     // Transforme la normale du ’model space’ au ’view-space’.
     float4 normalVec = normalize(mul(modelViewInverse,
                                   IN.Normal).xyz);

    L’éclairage

     // On normalise le vecteur de la source
     float4 lightVec = normalize(LightVector.xyz);

     // Calcul du vecteur demi-angle
     float4 eyeVec = EyePosition;
     float4 halfVec = normalize(lightVec + eyeVec);

On doit d’abord s’assure que tous nos vecteurs sont normalisés. Ensuite on
définie le vecteur demi-angle qui correspond au vecteur lightV ec + eyeV ec)/2,
la normalisation rendant inutile la division par deux.

     // Calcul de la composante diffuse
     float diffuse = dot(normalVec, lightVec);

     // Calcul de la composante spéculaire
     float specular = dot(normalVec, halfVec);
     specular = pow(specular, 32);

// La lumière ambiante
float4 ambientColor = float4( 0.2, 0.2, 0.2, 0.2 );

// Une source blanche
  float4 specularMaterial = float4( 1.0, 1.0, 1.0, 1.0 );

     // Lumière de sortie
     OUT.color0 = diffuse * IN.color0 + specular * specularMaterial
                                      + ambientColor;

     return OUT;
}

La suite étant assez simple à comprendre, elle se passe de commentaire. Nous
avons donc maintenant un éclairage de qualité !

                                      11
5     OpenGL Shading Language
   Le GLSL (OpenGL Shading Language) est le langage standardisé par l’OpenGL
Architecture Review Board pour concevoir des shaders. C’est un langage haut
niveau, syntaxiquement basé sur le langage C, qui offre un grand nombre de
fonctions et variables prédéfinies, ce que nous verrons dans la seconde partie.
Parallèlement aux fonctions d’éclairage, de texture et de transformation, le
GLSL s’insère dans la pipeline OpenGL sous forme de vertex objects : les vertex
shaders et les fragment shaders.

5.1    Incorporation d’un shader program dans une appli-
       cation Delphi
    Contrairement à certains langages de shader comme le Cg de nVidia, le
GLSL se compile à l’exécution de l’application Delphi, et ce grâce à des fonctions
intégrées dans les bibliothèques OpenGL. Avant de profiter de la puissance des
shaders, il va donc falloir écrire une unité Delphi retranscrivant la démarche
suivante :
    - Loader les extensions OpenGL propres aux shaders avec glext LoadExtension.
    - Créer un shader object vide avec glCreateShaderObjectARB.
    - Récupérer le contenu du fichier contenant le shader object.
    - Associer le code source récupéré au shader object avec glShaderSour-
      ceARB
    - Compiler le shader object avec glCompileShaderARB
    - Créer un shader program vide avec glCreateProgramObjectARB.
    - Attacher les shader objects (en théorie un fragment shader et un vertex
      shader) au shader program avec glAttachObjectARB
    - Lier l’ensemble avec glLinkProgramARB
    Pour plus de commodité, nous avons ajouté à notre unité shaders.pas une
procédure qui affiche le log des opérations et un enregistrement chargé de stocker
les shader programs. Ainsi à l’initialisation nous appelons la procédure loadsha-
ders et pour appliquer un shader à une primitive nous utilisons
beginshader(shaders.nom_du_shader) et endshader(). Par ailleurs, nous avons
également ajouté des fonctions pour transmettre des variables uniform dont
nous verrons l’utilité plus tard.

5.2    Syntaxe du GLSL
    Comme nous l’avons déjà fait remarqué, le GLSL a une syntaxe analogue à
celle du C. Pour résumer, un shader object est composé d’une fonction principale
main, les instructions sont séparées par des points-virgules, les blocs (fonctions,
conditions et boucles) sont délimités par des accolades et les variables sont
déclarées en précisant préalablement leur type.

                                         12
Pour exploiter au maximum les capacités du GPU, le GLSL met à disposition
de nombreuses fonctions préfinies intéressantes telles que le produit scalaire, le
produit vectoriel, la normalisation ou la multiplication de matrices qui mani-
pulent donc des types préstructurés tels que les vecteurs, les textures ou les
matrices.
    Il est souvent utile d’afficher les shaders selon une variable externe, un timer
par exemple ou la direction d’une lumière. Pour transmettre une variable delphi
aux shaders on utilise le mot clef « uniform » dans la déclaration de la variable.
Du coté de l’application Delphi, il faut utiliser glGetUniformLocationARB pour
localiser la variable et glUniformARB pour l’envoyer au shader program.
    Pour transférer une variable du vertex shader au fragment shader, le mot clef
est « varying ». GLSL effectue sur la variable une interpolation pour déterminer
sa valeur en chaque fragment situé entre les vertex.

Vertex shader On peut comparer un vertex shader à une fonction qui prend
en paramètre les variables uniform et qui retourne la position du vertex cou-
rant. En pratique, certaines variables sont automatiquement uniform telles que
gl Vertex ou gl Normal et la fonction retourne la position du vertex courant en
modifiant le vecteur gl Position. Pour y voir plus clair, retenons que ce vertex
shader n’effectue aucune transformation supplémentaire :
void main()
{
    gl_Position = vec4(gl_ModelViewProjectionMatrix * gl_Vertex);
}

Fragment shader L’objectif du fragment shader est de définir la couleur du
fragment courant. Par exemple, ce fragment shader colorie la primitive en rouge :
void main()
{
    gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
Le vecteur gl FragColor est composé d’une composante rouge, verte, bleue et
alpha activée à l’initialisation par glEnable(GL_BLEND) et
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)

5.3     Exemples de shaders
    Afin de fournir un élément de comparaison avec le Cg, nous avons développé
un éclairage en GLSL basé sur les mêmes formules que l’exemple en Cg donné
précédemment. L’intensité de la lumière est donc là aussi calculée à partir d’une
composante ambiante, diffuse et spéculaire mais avec en plus la prise en compte
des couleurs de la texture.

                                          13
//phong.vert (le vertex shader):
varying vec3 normal, eye;

void main()
{
    gl_TexCoord[0] = gl_MultiTexCoord0;
    normal = gl_NormalMatrix * gl_Normal;
    eye = - vec3(gl_ModelViewMatrix * gl_Vertex);
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
Ici le vertex shader ne présente pas beaucoup d’intérêt puisque la position des
vertex n’est pas modifiée. Toutefois il est nécessaire pour transférer au fragment
shader, grâce au mot clef « varying »,le vecteur normal et le vecteur caméra
utiles au calcul de l’eclairage.
//phong.frag (le fragment shader):
uniform sampler2D myTexture;
varying vec3 normal, eye;

const float n = 5.5; const float amb = 0.1; const float ks = 6.0;

void main (void)
{
  //couleur de la texture
  vec4 color = texture2D(myTexture, vec2(gl_TexCoord[0]));

    //normalisation des vecteurs
    normal = normalize(normal);
    eye = normalize(eye);
    vec3 lum = normalize(vec3(0.3,0.6,0.2));

    //lumiere ambiante
    float intensite = amb;

    //lumiere diffuse
    intensite += max(0.0,dot(normal,lum));

    //lumiere speculaire
    vec3 R = reflect(-lum,normal);
    intensite += ks*pow(max(0.0,dot(eye,R)),n);

    gl_FragColor    = intensite*color;
}
   L’application de ce shader est visible sur la figure 2. La figure 3 illustre un
shader similaire qui fait intervenir une fonction sinusoı̈dale pour simuler des

                                         14
reflets variés. La figure 4 utilise toujours le même type de shader mais fixe un
seuil d’intensité lumineuse en dessous duquel le pixel est noir et au dessus duquel
le pixel est blanc.

                            Fig. 2 – Phong classique

                             Fig. 3 – Phong modifié

                                        15
Fig. 4 – Phong à deux états

.

                 16
6     Le terrain
Turning over a new leaf A la précédente soutenance, nous avions présenté
un algorithme de génération de relief. Comme nous l’avions vu, cet algorithme
a quelques inconvénients. Premièrement, le tableau, contenant les informations
relatives au terrain, devait avoir des dimensions bien spécifiques pour qu’il reste
divisible à chaque récursion de la fonction en charge de la génération du terrain.
Le second inconvénient est la présence visible de segment délimitant les divisions
et subdivisions engendrées par l’algorithme. Après application de nombreux
flous, ces segments disparaissent mais cela demande un certain temps de calcul
regrettable. Néanmoins, cet algorithme n’a pas été abandonné pour autant car
il pourra par la suite être combiné avec le nouvel algorithme de génération de
relief expliqué ci-dessous.

Génération d’une courbe aléatoire Notre objectif premier est de générer
une courbe pouvant représenter un relief aléatoire vu de profil. Une telle courbe
a la particularité de passer progressivement d’un état à un autre sans former
d’angles tranchés, c’est ce qui rend le relief crédible. Autrement dit, la dérivée
de la courbe est continue. Ainsi, l’algorithme manipule la vitesse de la courbe et
non la courbe elle-même. En pratique, l’algorithme incrémente ou décrémente
aléatoirement le taux d’accroissement de la courbe de façon épisodique, c’est-
à-dire que la courbe accélère ou décélère tous les n points (figure 5). Pour que
la courbe ne dépasse pas le cadre fixé, sa vitesse est limitée positivement et
négativement.

Adapation 3D Pour adapter cet algorithme à une troisième dimension, nous
utilisons un petit tableau annexe contenant les vitesses de chaque surface in-
cluant une composante x et y. Puis l’altitude de chaque sommet du terrain est
déterminée en fonction des deux vitesses et des altitudes des précédents sommets
(figure 6).

                     Fig. 5 – Courbe générée aléatoirement

                                         17
Fig. 6 – Relief généré aléatoirement

.

                      18
7     Réseau

    Le réseau étant l’une des parties les plus importantes de notre jeu, nous y
avons consacré beaucoup de temps. Nous avons beaucoup réfléchi aux différents
moyens de communiquer nos informations, aux procédures à mettre en uvre,
aux différents protocoles disponibles.
Aussi, dans un premier temps nous avons développé un chat de base car c’était
un moyen simple de mettre en place notre réseau et de le tester de façon efficace.
C’est à partir de ces différents minis projets de chat que nous avons pensé notre
programme. En effet dans pour commencer, nous avons utilisé des composants
anciennement intégrés à Delphi, les Tclientsocket, et Tserversocket. Cette pre-
mière ébauche fonctionnait sur le principe d’envoie d’une chaı̂ne de caractère
contenant toutes les informations à transmettre. Mais nous avons assez vite
abandonné ce mode de fonctionnement, car parser cette chaı̂ne été long et
fastidieux pour un nombre de données important. Aussi avons-nous travaillé
sur l’envoie de Record avec ces mêmes composants, et sur la gestion d’une liste
de clients pour la soutenance précédente. Fort de la réussite de ces programmes,
nous avons décidé de changer de composants, et de nous baser sur ICS qui,
d’après nos camarades de spé, est plus performant. Notre objectif pour cette
soutenance était donc de réaliser et d’intégrer un réseau, basé sur le composants
ICS, dans notre jeu qui s’étoffe au fur et à mesure. Je vais dans cette partie
développer le fonctionnement de ce réseau.

                                         19
7.1     L’architecture du réseau
    Notre réseau est basé sur une architecture client serveur standard, hormis
que le serveur doit aussi être considéré comme un client du fait que le joueur
hébergeant la partie joue également. Il faut donc considérer ces deux entités que
sont le client et le serveur, car chacun a un rôle différent.

7.2     Le client
     Son rôle est réduit, il reçoit et analyse les commandes du joueur pour les
transmettre au serveur, ce dernier les traite et les renvoie au client qui a la
réception les analyse à nouveau, et procède à l’affichage.

7.3     Le serveur
     Dans cette architecture centralisée, sont rôle est prépondérant, en effet, c’est
le serveur qui gère toute la physique du jeu, le terrain, et ce afin de ne pas avoir
d’incohérences. Pour cela, les données du serveur et des clients son stockées dans
un tableau qui permet un accès rapide aux données, et la carte est stockée sur le
serveur qui l’envoie à la connexion du client. Le tableau de gestion, qui au final
n’est rien d’autre qu’une liste implémenté statiquement, est organisé de la même
façon du côté client comme du côté serveur, en fait, c’est exactement le même.

                                           20
C’est la gestion de ce dernier, qui est la plus compliquée car il faut pouvoir
organiser ce tableau de façon cohérente chez chaque client. Une autre difficulté
réside également dans la transmission de la carte, et des données d’initialisation
car un seul socket ne peut remplir toutes ces tâches sans problème. Aussi, pour
venir à bout de ce souci, nous avons mis en place un serveur qui fonctionne de
deux façons différentes.

   – Un socket est dédié à la connexion et à l’initialisation de la partie chez le
     serveur dans un premier temps, puis chez chaque client qui se connecte.

   – Un autre socket est exclusivement dédié à la phase de jeu. Le nombre de
     socket dédié à cette phase sera potentiellement augmenté si un seul ne
     permet pas d’assurer un jeu fluide.

7.4    L’initialisation
    C’est une phase importante car c’est elle qui assure la cohérence du jeu en
permettant la transmission aux différents clients des données telles que la carte,
et des identifiants assurant la cohérence de la liste de joueur. A la connexion
d’un client, on ajoute un joueur à notre liste, lui réservant ainsi une place dans
la partie. Puis on lui transmet son identifiant, et on lui envoie la carte de jeu. A
la réception de ce paquet de données, le client renvoie ses propres données qui
sont mise à jour dans la liste. Et enfin, le client est connecté au socket assurant
la phase de jeu.

7.5    La phase de jeu
    Elle début par l’envoie de la liste des données des joueurs à tous les clients
pour leur permettre d’afficher le monde. Par la suite, on se contente de mettre
à jour régulièrement la liste du serveur et de chaque client, sachant que le
client n’envoie que des ordres, et , ne reçoit que des états ( coordonnées, vitesse
angulaire etc ).

7.6    Futures améliorations
    Nous travaillons actuellement sur la mise en place et l’utilisation de deux
protocoles différents selon les actions du joueur, sur la mise en place de certains
calculs côté client qui permettraient de soulager le serveur, et sur l’extrapolation
pour permettre une plus grande fluidité. Mais cela est pour le moment réservé
à notre soutenance finale.

                                         21
8    Screenshots
   Voici une image 7 qui permet de montrer l’état actuel du jeu au niveau des
graphismes grâce au développement des shaders.

                               Fig. 7 – Le jeu

                                     22
9    Conclusion
    Le rythme que nous tenons depuis le début du développement du projet à été
maintenu, et malgré les soucis techniques rencontrés - comme l’absence de prise
en charge des shaders de certaines de nos ordinateurs - qui nous ont empêcher
d’atteindre tous nos objecifs pour cette soutenance nous restons satisfaits du
travail accomplie et des progèrs réalisés par l’ensemble de notre équipe.

    Nous gardons d’ailleurs une bonne cohésion qui rend le travail sur le projet
agréable et motivant, et ainsi nous abordons sereinement la fin du développe-
ment.

                                        23
Vous pouvez aussi lire