Réaliser une expérience multijoueur seamless sous Unity

Réaliser une expérience multijoueur seamless sous UnityIntroductionPremiers tests avec UNet et la HLAPI d'UnityRecherche d'une solutionDéveloppement avec SmartFoxServerCréation d'une base de jeu en localMise en place d'une connexion avec le serveurEchange de messages entre les joueursSuites possiblesConclusionRéférencesBiographie

Introduction

Aujourd'hui, la majorité des jeux qui sortent possèdent une composante multijoueur, quand ce n'est pas simplement leur coeur de gameplay. Néanmoins l'accès à cette composante est souvent lourde pour l'utilisateur : vérification du réseau et de l'état des connexions, recherche de joueurs en matchmaking, connexion à un serveur de jeu ... Ce qui a pour effet de complètement couper le joueur du monde dans lequel il pouvait être immergé précédemment. Pour contrer cette sensation certains développeurs de jeux tentent de réaliser des modes multijoueurs dits seamless, qui permettent à des joueurs de jouer ensemble sans que l'expérience de jeu en pâtisse, en cherchant à abolir la frontière entre le jeu solo et le jeu multijoueur. On pourra citer par exemple Journey (That Game Company, 2012) qui permet à deux joueurs de vivre une aventure sans interfaces gênantes et sans moyen de communication directe. Ou encore The Crew (Ivory Tower, 2014) qui offre aux joueurs une carte réduite des USA, dans laquelle ils peuvent rouler tout en voyant leurs voisins les plus proches, les transitions se faisant de manière fluide.

Bien que la valeur ajoutée à l'expérience du jeu soit loin d'être moindre, ce genre de jeux reste rare pour différentes raisons. D'abord parce que tous les jeux n'y sont pas adaptés. Ensuite parce que le design de l'expérience sera différent de celui d'un mode multijoueur plus classique. Et enfin, ce qui nous intéresse ici, parce que le challenge technique sera beaucoup plus élevé lors de la réalisation du jeu que dans le cadre d'un mode multijoueur bien délimité, bien que celui-ci présente déjà de nombreuses contraintes. Le sujet de ce travail de recherche et d'expérimentation est donc le suivant : comment créer une expérience multijoueur seamless dans le moteur de jeu Unity ? Nous allons donc réaliser différentes tests et réflexions afin de réaliser une base solide pouvant servir à la création d'un jeu de type MMO avec un multijoueur seamless : les joueurs devront pouvoir jouer en solo, puis rejoindre le mode multijoueur et apercevoir d'autres joueurs, puis retourner en solo suite à une déconnexion sans subir le moindre chargement, avec le moins d'interfaces possibles, le tout de la manière la plus fluide possible en toutes circonstances.

Premiers tests avec UNet et la HLAPI d'Unity

La première solution que nous avons envisagée et expérimentée dans le cadre de la réalisation d'un jeu seamless est celle fournie directement dans Unity. En effet, depuis sa version 5.1 Unity dispose d'une solide interface réseau (une API) nommée Unet. Celle-ci comporte deux composantes principales : une API haut niveau appelée High Level API (HLAPI) dédiée au jeu multijoueur sous Unity, et une seconde API appelée Network Transport API dédiée elle aux infrastructures réseaux et au jeux possédant des contraintes spécifiques.

UNET

Nous avons donc commencé par expérimenter et réaliser des premiers tests d'architectures avec la HLAPI, car celle-ci est très simple à mettre en place et possède son propre Network Manager, qui se révèle efficace dans de nombreuses situations lors de la création d'un jeu. Celui-ci permet en particulier de gérer les choses suivantes :

Ce qui représente les fonctionnalités vitales à la réalisation d'un jeu multijoueur en réseau. Nous avons donc commencé par réaliser un premier prototype de MMO en suivant la documentation officielle d'Unity. Celle-ci est très claire, et nous a permis de rapidement mettre en place une scène (en mode pair-à-pair dans un premier temps) dans laquelle des joueurs représentés par de simples cubes pouvaient se déplacer en réseau, et ainsi s'apercevoir les uns les autres. En effet, le Network Manager et les différents components d'Unity s'occupent de synchroniser la position des joueurs (et les variables personnalisées de notre choix) sans que l'on ait à envoyer et à traiter nous même les messages sur le réseau. Ils permettent donc de réaliser tout ceci avec un minimum de code (uniquement nécessaire pour instancier les connexions, et régler quelques détails) :

Server

Prefab du joueur

Ainsi ces deux prefabs (dont les scripts héritent de la classe NetworkBehaviour et non de la classe MonoBehaviour classique d'Unity) suffisent à réaliser un jeu en réseau avec Unity. Cependant, dans l'optique de réaliser un MMO seamless, nous avons besoin d'un serveur dédié qui puisse adresser des requêtes à tous les clients. La case "Server" du ServerScript permet donc de créer le serveur en mode dédié, et non hôte + joueur, serveur que les autres joueurs (eux en mode client) vont pouvoir rejoindre. Le jeu fonctionne alors de la même façon que précédemment, mais possède un serveur principal par lequel vont transiter tous les paquets.

Aperçu du MMO sous Unity

Ainsi, il était possible de simuler un jeu en ligne massivement multijoueur à l'aide de l'API haut niveau d'Unity. Une fois ce prototype réalisé, nous avons essayé de l'adapter afin de le faire fonctionner de manière seamless : les connexions et déconnexions doivent être transparentes pour les joueurs. Malheureusement, le Network Manager est le seul objet capable d'instancier des gameobjects héritant de la classe NetworkBehaviour. Il est donc impossible de créer un objet pour le joueur, puis de lui faire rejoindre et quitter le serveur à notre guise : celui-ci peut uniquement être créée lors de la connexion, et sera détruit à la déconnexion. L'HLAPI d'Unity n'est donc nativement pas compatible avec notre volonté de réaliser un jeu seamless.

Recherche d'une solution

A ce moment là, plusieurs solutions s'offraient à nous pour continuer à utiliser les fonctions native d'Unity. La première était de détourner le fonctionnement du NetworkManager et de la classe NetworkBehaviour afin que ceux-ci fonctionnent d'une manière qui réponde à nos besoins. Cette solution a tout de suite été écartée pour la raison suivante : il n'est jamais bon d'utiliser des composantes d'une manière dont elles ne sont pas prévues pour, plus particulièrement lorsque que l'on ne possède pas les sources (et que l'on ne peut donc prévoir le comportement dans 100% des cas).

La seconde solution envisagée pour continuer avec UNET était d'utiliser la couche transport fournie par Unity (la fameuse Transport Layer API). Celle-ci permet un contrôle total sur tout le réseau, et offre donc la possibilité de réaliser tous les échanges et actions nécessaires à la création d'un jeu seamless. La principale contrainte avec cette API provient de sa nature même : celle-ci demande de réaliser tous les échanges "à la main". De la connexion, à l'envoi des messages en passant par leur traitement, tout devra être fait en code en utilisant des sockets, de la même manière qu'on le ferait en programmation réseau bas niveau. Dans le cadre d'un projet de grande ampleur, cette API constituerait une solution viable afin de maîtriser la totalité du réseau ; mais dans le cas de notre expérimentation, celle-ci demande trop de travail avant de pouvoir être utilisable.

Nous avons donc étudié les différentes solutions qui s'offraient à nous afin de réaliser un jeu en réseau sous Unity. En effet, de nombreux plugins et solutions existent : Photon, Bolt, Darknet. Néanmoins, c'est vers une solution plus générale que nous avons choisi de nous tourner pour réaliser ce projet : SmartFoxServer

SmartFoxServer

SmartFoxServer est un middleware dédié à la création de jeux en réseau. Il existe depuis 2004 et a été utilisé par de nombreux éditeurs tels qu'EA ou Sony Online Entertainment afin de réaliser des jeux en ligne massivement multijoueurs. Celui-ci fournit de nombreuses API dédiées (Unity, Android, iOS, Flash ...) et permet donc de réaliser des jeux sur plusieurs plateformes, avec un seul et unique serveur dédié. API qui ont la particularité d'être relativement simple à utiliser mais également performantes. Il faut savoir que le serveur est codé en Java (donc multiplateforme), et son interface de gestion est en Flash, ce qui la rend accessible dans n'importe quel navigateur. On a donc une solution qui nous permet de réaliser un serveur dédié contrôlant l'état global d'un jeu en réseau, mais également une API qui permet de s'affranchir des besoin bas niveau de la programmation réseau, et donc se concentrer sur ce qui nous intéresse dans ce travail d'expérimentation.

Développement avec SmartFoxServer

Une fois le serveur installé et configuré, puis l'API (constituée d'un simple fichier .dll) ajoutée à Unity, nous avons commencé le développement basé sur SmartFoxServer. Bien que ce dernier propose de nombreuses fonctionnalités, nous avons essayé d'en faire une utilisation la plus basique possible afin de se concentrer sur ce qui nous intéresse dans son utilisation. Il faut tout d'abord connaître le fonctionnement du serveur : celui-héberge plusieurs zones (qui peuvent représenter plusieurs jeux hébergés sur le même serveur), dans lesquelles se trouvent des rooms que les joueurs peuvent rejoindre afin de jouer ensemble. Une room peut être un lobby, une carte de jeu ou encore un match privé, et leur nombre peut être fixe (une par carte) ou variable (une nouvelle room est créée pour chaque nouveau match). Dans notre cas nous en utiliserons une seule, représentant notre espace de jeu.

ArchitectureSFS

Création d'une base de jeu en local

Avant de commencer le développement de la partie réseau à proprement parler, nous avons réalisé une base de jeu, en reprenant une partie de ce qui avait été fait pour les premiers tests avec UNET. Cette base de jeu permet dans une première scène d'entrer un nom et de rejoindre le jeu, de cette façon le joueur pourra être identifé par son nom mais également par une couleur qui lui sera attribuée de manière aléatoire lors de sa première apparition.

Une fois le nom validé, le jeu charge une seconde scène dans laquelle un prefab va être confié au joueur, représentant son avatar virtuel (qui est ici un simple cube). Celui-ci a la possibilité de se déplacer sur la carte de jeu en utilisant les touches du clavier. Mais ce qui nous intéresse ici est de savoir comment rendre seamless cette partie du jeu. Pour se faire, nous avons donc créé une classe LocalPlayerManagerScript qui s'occupe de gérer l'état du joueur en permanence. Celle-ci va permettre de sauvegarder la position, la rotation, et la couleur du joueur à intervalle régulier via la fonction save() :

 
AخA
private void save()
{
    if(DebugSaves)
        Debug.Log("Saving prefs ...");
    PlayerPrefs.SetInt("saved" + playerName, 1);
    PlayerPrefs.SetFloat("x" + playerName, transform.position.x);
    PlayerPrefs.SetFloat("z" + playerName, transform.position.z);
    PlayerPrefs.SetFloat("rot" + playerName, transform.rotation.eulerAngles.y);
    Color c = GetComponent<MeshRenderer>().material.color;
    PlayerPrefs.SetFloat("r" + playerName, c.r);
    PlayerPrefs.SetFloat("g" + playerName, c.g);
    PlayerPrefs.SetFloat("b" + playerName, c.b);
    PlayerPrefs.DeleteKey("name");
    PlayerPrefs.Save();
    if(DebugSaves)
        Debug.Log("Saved");
}

Comme on peut le voir dans cet extrait de code, le nom du joueur sert également d'identifiant afin de permettre à différentes personnes de jouer sur le même ordinateur, à la manière d'un slot de sauvegarde dans un jeu classique. Mais cette classe va également servir lors de l'instanciation du joueur à lui restituer sa dernière position connue, sa couleur originale et sa rotation. Les PlayerPrefs d'Unity permettent de lire et d'écrire ses informations directement sur le disque dur, et donc de les sauvegarder même après la fin du processus. Afin de ne pas surcharger les entrées/sorties du disque dur, les sauvegardes sont faites toutes les secondes. Le joueur peut ainsi reprendre le jeu exactement là où il en était, sans menus lui proposant des choix ni temps de chargement, uniquement à l'aide de son nom.

TestLocal

Mise en place d'une connexion avec le serveur

Une fois la base du jeu créée, il a fallu rendre celui-ci multijoueur. Pour cela, nous avons commencé par créer une classe ServerConnectorScript réalisant toutes les formalités nécessaires afin qu'Unity puisse communiquer avec le serveur. Celle-ci utilise une instance unique de la classe SmartFox afin de se connecter au serveur ; cette instance sera plus tard accessible dans les autres classes via un singleton. La connexion se fait en une seule ligne via la fonction Connect une fois la configuration du serveur entrée. Afin de continuer dans les échanges avec le serveur et de parer à tout problème, SmartFoxServer nous propose de nombreux listeners à implémenter afin de pouvoir réagir en fonction du comportement de l'objet.

 
xxxxxxxxxx
//LISTENERS
sfs.AddEventListener(SFSEvent.CONNECTION, OnConnection);
sfs.AddEventListener(SFSEvent.CONNECTION_LOST, OnConnectionLost);
sfs.AddEventListener(SFSEvent.CONFIG_LOAD_SUCCESS, OnConfigLoadSuccess);
sfs.AddEventListener(SFSEvent.CONFIG_LOAD_FAILURE, OnConfigLoadFailure);
sfs.AddEventListener(SFSEvent.LOGIN, OnLogin);
sfs.AddEventListener(SFSEvent.LOGIN_ERROR, OnLoginError);
sfs.AddEventListener(SFSEvent.ROOM_JOIN, OnJoin);
sfs.AddEventListener(SFSEvent.ROOM_JOIN_ERROR, OnJoinError);

Ainsi si la connexion est lancée, la suite des opérations se déroule dans la fonction OnConnection. Dans cette fonction, nous allons vérifier grâce aux paramètres si la connexion s'est bien effectuée, auquel cas nous pouvons mettre l'objet SmartFox dans le singleton et envoyer une requête au serveur afin de se logger dans une zone (définie lors de la configuration initiale, ici nous utilisons tous les paramètres de base).

 
xxxxxxxxxx
private void OnConnection(BaseEvent evt)
{
    if((bool)evt.Params["success"])
    {
        Debug.Log("Connected");
        SmartFoxConnection.Connection = sfs;
        sfs.Send(new LoginRequest(""));
    }
    else
    {
        Debug.Log("Connection Failed");
    }
}

Une fois la requête effectuée et la réponse renvoyée par le serveur, nous pouvons continuer dans les fonctions correspondantes (OnLogin et OnLoginError) avec la connexion à une room, et donc enfin rejoindre les autres joueurs présents sur le serveur :

 
xxxxxxxxxx
private void OnLogin(BaseEvent evt)
{
    User user = evt.Params["user"] as User;
    Debug.Log("Logged as " + user.Name);
    sfs.Send(new JoinRoomRequest(roomName));
}
 
xxxxxxxxxx
private void OnJoin(BaseEvent evt)
{
    Room room = evt.Params["room"] as Room;
    Debug.Log("Joined room "+ room.Name);
}

A partir de ce moment là, le joueur est présent dans une des rooms du serveur et il est capable de communiquer avec les autres joueurs. Dans le cadre de la réalisation d'un multijoueur seamless, nous avons mis en place une reconnexion automatique qui va tenter de relancer la connexion toutes les 10 secondes lorsque celle-ci est perdue. De cette façon toute les actions en rapport avec le réseau sont transparentes pour l'utilisateur puisque celui-ci peut continuer de jouer pendant ce temps.

 
xxxxxxxxxx
if(!sfs.IsConnected)
{
  timer += Time.deltaTime;
  if(timer >= TimeBeforeReconnection)
  {
    timer = 0;
    sfs.Connect(cfg);
  }
}

Echange de messages entre les joueurs

Maintenant que les joueurs sont dans une room, nous pouvons les faire communiquer de différentes manières fournies par SmartFoxServer. Il en existe deux principales : utiliser les Server Variables qui vont être partagées entre le serveur et les clients ou créer notre propre Extension afin de traiter nous-même les messages et les différentes données transmises sur le réseau. Nos besoins étant relativement simples dans le cadre de ce travail de recherche (transmettre la position des joueurs et quelques informations supplémentaires), nous allons utiliser la première solution. Néanmoins (et comme précisé dans la documentation de SmartFoxServer) dans le cadre d'un développement de plus grande ampleur, il faudrait créer des extensions du serveur afin de traiter les données de manière plus efficace.

SmartFoxServer nous propose trois types de Server Variable :

Dans notre cas, nous avons utilisé les User Variables afin de transmettre régulièrement la position d'un joueur aux autres joueurs présents dans la room. Pour se faire nous avons créé une classe PlayerNetworkScript attachée au joueur local qui s'occupe d'envoyer les informations lors de la première connexion, puis lorsque le joueur se déplace (afin que les autres clients puissent mettre à jour sa position). Certaines informations ne sont envoyées qu'une seule fois, afin d'économiser de la bande passante.

 
xxxxxxxxxx
public void sendInfos(bool firstTime = false)
{
    List<UserVariable> userVariables = new List<UserVariable>();
    userVariables.Add(new SFSUserVariable("playerName", localPlayer.playerName));
    userVariables.Add(new SFSUserVariable("x", (double)transform.position.x));
    userVariables.Add(new SFSUserVariable("z", (double)transform.position.z));
    userVariables.Add(new SFSUserVariable("rot", (double)transform.rotation.eulerAngles.y));
    if(firstTime)
    {
        Color c = localPlayer.GetComponent<MeshRenderer>().material.color;
        userVariables.Add(new SFSUserVariable("r", (double)c.r));
        userVariables.Add(new SFSUserVariable("g", (double)c.g));
        userVariables.Add(new SFSUserVariable("b", (double)c.b));
    }
    sfs.Send(new SetUserVariablesRequest(userVariables));
}

Ici c'est la dernière ligne qui nous intéresse : elle transmet au serveur une requête de modification des User Variables du client. De son côté lorsque le serveur reçoit cette requête, il stocke les variables sur l'utilisateur correspondant, puis les retransmet à tous les autres clients présents dans la room.

Afin de traiter ces données lorsqu'elles sont reçues par les différents clients, nous avons créé une classe GameManagerScript qui s'occupe de lire les messages et de réaliser les actions nécessaires. Pour se faire, celle-ci utilise plusieurs listeners:

 
xxxxxxxxxx
sfs.AddEventListener(SFSEvent.USER_ENTER_ROOM, OnUserEnterRoom);
sfs.AddEventListener(SFSEvent.USER_EXIT_ROOM, OnUserExitRoom);
sfs.AddEventListener(SFSEvent.USER_VARIABLES_UPDATE, OnUserVariableUpdate);

qui sont appelés respectivement quand un client entre dans la room, quand un client quitte la room et quand un client met à jour ses User Variables sur le serveur. Cette classe utilise également un dictionnaire afin de stocker de manière locale les informations sur les autres joueurs. Voyons maintenant comment est gérée l'arrivée d'un nouveau joueur dans la room :

 
xxxxxxxxxx
private void OnUserEnterRoom(BaseEvent evt)
{
    localPlayer.GetComponent<PlayerNetworkScript>().sendInfos(true);
}

Dans la pratique, nous demandons seulement au joueur local d'envoyer ses informations, afin que le nouveau joueur puisse afficher les clients qui l'entourent. De son côté, le client local verra forcément le nouveau joueur car celui-ci envoie ses informations une première fois dès sa connexion.

Lorsque qu'un client quitte la room, on appelle simplement la fonction removeRemotePlayer qui supprime le GameObject correspondant et retire l'entrée du dictionnaire :

 
x
private void removeRemotePlayer(SFSUser user)
{
    if (user == sfs.MySelf)
        return;
    if(remotePlayers.ContainsKey(user))
    {
        Destroy(remotePlayers[user]);
        remotePlayers.Remove(user);
    }
}

Intressons nous maintenant à la fonction la plus importante du GameManager, OnUserVariableUpdate qui est appelée lorsque le serveur a transmis au client un changement parmi les User Variables des joueurs présents dans la room. Celle-ci va réaliser deux actions principales. Dans un premier temps si le client qui envoie ses User Variables n'est pas présent dans le dictionnaire des autres utilisateurs, nous traitons les données reçues, ajoutons l'utilisateur au dictionnaire et faisons spawner le GameObject correspondant :

 
xxxxxxxxxx
if(!remotePlayers.ContainsKey(user))
{
  Vector3 pos = new Vector3(0, 0, 0);
  if(user.ContainsVariable("x") && user.ContainsVariable("z"))
  {
  pos.x = (float)user.GetVariable("x").GetDoubleValue();
  pos.z = (float)user.GetVariable("z").GetDoubleValue();
  }
  float rot = 0;
  if (user.ContainsVariable("rot"))
  rot = (float)user.GetVariable("rot").GetDoubleValue();
  string playerName = "Bob";
  if (user.ContainsVariable("playerName"))
  playerName = user.GetVariable("playerName").GetStringValue();
  Color c = Color.white;
  if (user.ContainsVariable("r") && user.ContainsVariable("g") && user.ContainsVariable("b"))
  c = new Color((float)user.GetVariable("r").GetDoubleValue(), (float)user.GetVariable("g").GetDoubleValue(), (float)user.GetVariable("b").GetDoubleValue());
  spawnRemotePlayer(user, playerName, pos, Quaternion.Euler(0, rot, 0), c);
}
 
xxxxxxxxxx
private void spawnRemotePlayer(SFSUser user, string playerName, Vector3 position, Quaternion rot, Color color)
{
    if (remotePlayers.ContainsKey(user) && remotePlayers[user] != null)
    {
        Destroy(remotePlayers[user]);
        remotePlayers.Remove(user);
    }
    GameObject remotePlayer = Instantiate(playerPrefab);
    remotePlayer.GetComponent<SimpleRemoteInterpolation>().SetTransform(position, rot, false);
    remotePlayer.GetComponentInChildren<TextMesh>().text = playerName;
    remotePlayer.GetComponent<MeshRenderer>().material.color = color;
    remotePlayers.Add(user, remotePlayer);
}

Enfin dans un second temps la fonction vérifie si les variables x, z et rot sont bien reçues : si oui on les transmet directement à une simple classe d'interpolation de mouvement qui s'occupera de déplacer le GameObject correspondant au joueur ayant envoyé ses données :

 
xxxxxxxxxx
if(changedVars.Contains("x") && changedVars.Contains("z") && changedVars.Contains("rot"))
    {
        remotePlayers[user].GetComponent<SimpleRemoteInterpolation>().SetTransform(
            new Vector3((float)user.GetVariable("x").GetDoubleValue(), 0, (float)user.GetVariable("z").GetDoubleValue()),
            Quaternion.Euler(0, (float)user.GetVariable("rot").GetDoubleValue(), 0),
            true);
    }

Grâce à ces différentes classes et à la possibilité offerte par SmartFoxServer d'utiliser ses Server Variables, nous avons pu créer un prototype de MMO seamless (puisqu'il se reconnecte de manière invisible) et fonctionnel sans pour autant mettre une place une lourde architecture :

Diagramme

MMO

Suites possibles

Ce travail d'expérimentation nous a permis de tester une base solide créée à l'aide de SmartFoxServer et d'expérimenter un premier prototype de jeu seamless. Néanmoins, celle-ci ne serait pas suffisante dans le cadre d'un projet de plus grande ampleur : nous allons maintenant étudier comment nous pourrions rendre tout ceci viable.

Dans un premier temps, il faudrait configurer le serveur d'une manière plus optimale. En créant différentes rooms, qu'elles soit dédiées directement au jeu (les différentes cartes) ou au login des joueurs. Login qui devra être relié à une base de données, afin d'avoir des informations plus consistantes sur les utilisateurs qu'actuellement où celles-ci sont uniquement sur le disque dur de l'utilisateur.

Ensuite, l'utilisation des UserVariables pour transmettre des informations à un intervalle régulier n'est pas assez polyvalente et performant dans le cadre d'un vrai jeu en ligne. Il faudrait, pour remplacer ce système écrire différentes extensions de serveur dédiées aux différentes parties du jeu : une pour les déplacements des joueurs, une pour les combats ...

De plus, il faudrait optimiser les envois de messages. Pour cela, SmartFoxServer nous fournit une puissante API dédiée à la réalisation de MMO. Celle-ci permet par exemple de ne transmettre les messages qu'aux joueurs les plus proches, permettant ainsi d'économiser temps de processeurs et bande passante.

Enfin, dans le cadre d'un jeu massivement multijoueur, un gros travail est souvent demandé afin de répartir la charge des joueurs sur les serveurs et ainsi offrir une expérience agréable. SmartFoxServer permet de palier à ces problématiques, mais il est nécessaire de les avoir en tête dès le début du développement afin de créer une architecture et des classes adaptées.

Conclusion

Nous venons de voir comment créer une expériences multijoueur seamless, par opposition aux expérience classiques beaucoup moins fluides. Si l'API de base d'Unity est très puissante, celle-ci n'a pas suffi à combler nos besoins, là où l'utilisation du serveur dédié SmartFoxServer nous a permi de mettre en place une architecture classique de client serveur très rapidement. En adaptant cette architecture et en faisant attention aux endroits critiques que sont les déconnexions et les reconnexions, nous avons pu facilement réaliser un prototype dans lequel les joueurs peuvent se connecter et se déconnecter à la volée.

Aujourd'hui, réaliser un jeu seamless est un challenge important pour la majorité des développeurs de jeu, plus important que réaliser un mode multijoueur plus classique. Néanmoins, nous venons de voir qu'avec un peu de travail, il est tout à fait possible de réaliser une architecture permettant aux joueurs d'avoir une expérience fluide. Nous pouvons donc espérer une prise de conscience de l'apport du seamless et ainsi plus de concurrents à The Crew et Dark Souls dans un futur proche !

Références

Biographie

Avatar

Victor Grosclaude - Etudiant au CNAM ENJMIN

Programmeur depuis de nombreuses années, je m'intéresse à tous les aspects de la création des jeux vidéo et en particulier au game design.