Le but de ce projet est de réaliser une application client/serveur dans un contexte MMO. Notre jeu est un jeu de survie à la première personne. Dans un monde postapocalyptique, le joueur doit survivre dans un environnement hostile peuplé de zombie.
Ce projet se divise en deux parties, un serveur et un client. Chaque client peut se connecter au serveur. Le client est implémenté en C# avec Unity tandis que le serveur est implémenté en C++. La connexion entre le client et le serveur se fait uniquement en TCP.
Ce projet a été réalisé par :
Vous pouvez accéder au repository de la partie serveur en suivant ce lien :
Vous pouvez accéder au repository de la partie client en suivant ce lient :
La semaine dédiée à cette UE nous a permis de travailler et de prendre place au sein du groupe. Avant de commencer à coder. Nous avons pris soin de faire en sorte de tirer meilleur parti des compétences de chacun. Ainsi nous nous sommes chacun attribué un "rôle" dans l'équipe et le projet.
Afin d'être efficaces et autonomes nous avons, avant de commencer, procédé à une phase de conception communes. C'est à ce moment que les choix importants ont été fait.
La partie serveur a été commencée depuis le début de la semaine intensive, car un membre était motivé pour créer cette partie du projet. Or le serveur de base, fourni avec le projet, ne présentait pas de fonctionnalité multi threadée, et donc aucune gestion de plusieurs clients (ce qui est dommage pour un jeu multi joueurs). La première partie de l'implémentation du serveur de communication consistait donc à définir et créer cette implémentation afin de permettre la connexion simultanée de plusieurs joueurs. Au milieu de la semaine intensive, une version multi threadée proposant la gestion de plusieurs clients fut ajoutée au projet principal. Nous avons donc abandonné celui que nous concevions, pour utiliser celui finalement fourni.
Le serveur de communication est implémenté directement par-dessus le serveur de socket fourni avec le projet. Il présente une interface de passage de messages et permet la connexion simultanée de plusieurs clients. Même si destinée à notre jeu, celui-ci est tout à fait générique.
Chaque donnée devant être envoyée/reçue par le serveur devra implémenter une classe virtuelle pure de message générique (IMessage). L'interface IMessage demande l'implémentation des fonctions permettant l'encodage de la donnée en flux d'octets, ainsi que de spécifier le tag du message. Ceci servira à l'identification du type de message, et est nécessaire pour l'identification des flux d'octets.
Ensuite, le serveur de communication présente deux interfaces, la première permet l'envoi de messages. En identifiant un client grâce à un id, le serveur est capable d'envoyer le message. La seconde interface permet la réception de messages. Chaque module présent sur le serveur désireux de recevoir un type de message devra alors implémenter une interface ("MessageHandler"). Il suffira ensuite de s'abonner au serveur en notifiant le type des messages souhaité. Il est à noter qu'il est de la responsabilité du MessageHandler de décoder le message, car le serveur transmettra uniquement un flux d'octets ainsi que le type de message transmis (ce qui permet de s'abonner à plusieurs types de messages).
Une fois le travail du serveur fini, il suffit de définir les messages que nous utiliserons (même à la volée si nécessaire) et de fournir les fonctions pour les transformations binaires/structures.
Diagramme de classe illustrant la machinerie interne du server.
Dans ce paragraphe, nous parlerons des échanges réseau. Nous utiliserons le mot "trame" à la place de "message". Les messages sont un procédé "haut niveau" de notre application. Afin de pouvoir dialoguer grâce au socket, nous avions besoin d'un format générique de trames. En effet, le nombre d'informations que nous devons faire transiter entre le serveur et le client est indéfini (assets, mouvement/action joueur etc). Nous avons donc gardé l'implémentation faite avec les byteBuffers (envoie de la taille, puis lecture de la trame), et nous avons ajouté un caractère au début de la trame afin de différencier les différentes trames réseau.
| taille : int | id trame : char | Message : bytes |
|---|
Le principal rôle de la partie client est de faire le lien entre ce que nous envoie le serveur et ce dont Unity a besoin pour fonctionner. Pour cela, nous avons créé plusieurs fonctions qui récupèrent une chaine d'octects, et selon l'ID qui a été envoyé en tête de la chaîne, récupère le message voulu. Ainsi, en imposant un formalisme précis entre le client et le serveur, on peut faire transiter des messages de type Mesh, String, Event (type que nous avons créé pour signaler un mouvement) et connexion.
De plus, il est de la responsabilité du client d'informer en temps réel la position du joueur au serveur. Le serveur, lui, va envoyer continuellement la position de chacun des zombies pour que le client puisse mettre à jour son affichage. Tous les mouvements des zombies sont calculés par le serveur.
Nous avons deux protagonistes :
Le but de notre projet était de créer un Système Multi-Agents (SMA) représentant un écosystème post-apocalyptique. Nous avons donc voulu que des zombies parcourent l'environnement, se déplacent et réagissent de manière "vraisemblable" et indépendante du joueur, c'est-à-dire qu'ils ne soient pas simplement des bots ayant une zone de déplacement et réapparaissant après un certain temps.
Nous voulions que nos zombies se déplacent en "horde" à travers l'environnement, qu'ils réagissent aux sons, à la lumière et à la vue d'un ou plusieurs joueurs.

Afin d'implémenter ce SMA nous avons utilisé une implémentation permettant de lancer les agents à l'aide de threads en suivant le schéma suivant :
Pour donner aux zombies le comportement que nous souhaitions, c'est-à-dire :
Ainsi nous obtenons le comportement souhaité : des hordes de zombies parcourant l'environnement et pouvant tomber à tout moment sur le joueur.
Voici les fonctionnalités implémentées :
Attention, les arbres ne sont pas très beaux, car nous avons dû désactiver les lumières dynamiques afin d'améliorer la réactivité du jeu.
Accueil
Choix du pseudo et de l'adresse IP du serveur
Interface utilisateur
Son plus beau profil
Vue côté serveur de la map