51 Zone 51 - Deadly Area LAWSON Wilfried LEFORTIER Damien MOURET Romain SAVIN Alexis
←
→
Transcription du contenu de la page
Si votre navigateur ne rend pas la page correctement, lisez s'il vous plaît le contenu de la page ci-dessous
LAWSON Wilfried LEFORTIER Damien MOURET Romain SAVIN Alexis Zone 51 - Deadly Area 3e Soutenance - Avril 2006 51 ZONE http ://zone51da.free.fr/
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
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
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