Comme promis, nous reprenons les tutos sur les composants de XNA, aujourd’hui nous allons aborder le sujet du réseau. Pour ceux qui en ont déjà fait dans d’autre Framework, ce n’est pas toujours des plus facile, mais grâce a XNA nous allons non seulement pourvoir créer un réseau qui marchera sur toute les plates-formes XNA (même si je n’ai pas pu tester sur le Zune sniff), mais aussi inter plateforme, c’est-à-dire que vous pourrez jouer en réseau en même temps sur votre Xbox et sur votre pc ^^.

capture

Nous allons commencer par créer une classe Session, qui nous servira juste à conserver notre session de jeu. Il n’est pas forcement important de créer une classe, mais cela se révèlera pratique pour des projets réseau plus importants.

   1: class Session

   2: {

   3:     NetworkSession session;

   4:     public Session()

   5:     {

   6:     }

   7:

   8:     public NetworkSession getsession

   9:     {

  10:         get { return session; }

  11:         set { session = value; }

  12:     }

  13:  }

Nous allons maintenant créer notre classe réseau en elle-même, qui sera un drawablegamecomponent, histoire qu’elle soit indépendante et réutilisable dans d’autres projets. Commençons par nos variables :

   1: Main mainGame; //lien vers notre classe principale

   2: SpriteBatch spriteBatch;

   3: SpriteFont font;

   4: KeyboardState currentKeyboardState;

   5: GamePadState currentGamePadState;

   6: NetworkSession networkSession;

   7: GraphicsDeviceManager graphicManager;

   8: PacketWriter packetWriter = new PacketWriter(); //notre packetwriter pour ecrire sur le reseau

   9: PacketReader packetReader = new PacketReader(); //notre packet reader pour lire sur le reseau

  10: public NetworkSession netSession { get; set; }

  11: bool profile_created; //un bool pour saboir si le profil est pret pour une connexion reseau

  12: bool affiche;

  13: bool getIndex; //un bool pour savoir si nous avons recu botre index dans la session

  14: const int maxGamers = 4; //le nombre de jouers max dans la session

  15: const int maxLocalGamers = 1; //le nombre de joueur max par machine   

  16: string errorMessage;

  17: public bool IsNetwork { get; set; }  //un bool pour savoir si nous sommes connectés  

  18: public bool IsHost { get; set; } //un bool pour savoir si nous somme l'hote de la partie

  19: public int gamerIndex { get; set; } //le gamerindex du joueur

  20: public NetworkSession Getsession

  21: {

  22:     get { return networkSession; }

  23: }

Vous avez l’explication en commentaire pour les éléments que nous n’avons pas encore vus.

Il n’y a rien de spécial a faire pour l’instenciateur de classe, pour l’initialize et pour le loadcontent, c’est comme d’habitude.(vous aurez quand même le source complet à la fin ne vous inquiétez pas ^^). Il faut juste penser a jouter un GamerServicesComponent pour gérer le guide du LIVE:

   1: mainGame.Components.Add(new GamerServicesComponent(mainGame));

Dans l’update nous allons juste vérifier si notre networkSession est nulle si c’est le cas nous allons faire plusieurs choses, tout d’abord nous allons lancer le guide du LIVE, qui permettra de gérer les comptes de profile et mettre en place les appuis boutons pour les créations et les connexions aux sessions.

   1: /// <summary>

   2: /// Menu screen provides options to create or join network sessions.

   3: /// </summary>

   4: void UpdateMenuScreen()

   5: {

   6:     if ((!Guide.IsVisible) && (!profile_created))

   7:     {

   8:         // Show the Guide so the user can sign in.

   9:         Guide.ShowSignIn(1, false);

  10:         profile_created = true;

  11:     }

  12:     else if (IsPressed(Keys.Delete, Buttons.A))

  13:     {

  14:         // Create a new session?

  15:         CreateSession();

  16:     }

  17:     else if (IsPressed(Keys.Enter, Buttons.B))

  18:     {

  19:         // Join an existing session?

  20:         JoinSession();

  21:     }

  22: }

Attaquons nous à la méthode Create Session, pour créer un session en XNA il suffit de faire ceci :

   1: networkSession = NetworkSession.Create(NetworkSessionType.SystemLink, maxLocalGamers, maxGamers);

On ne peut pas faire plus simple ^^. Ici j’utilise l’option NetworkSessionType.SystemLink qui permet de faire des sessions en réseau local pour faire des sessions en ligne il faut utiliser PlayerMatch ou Ranked. Il est bien entendu possible de rajouter des options spécifiques comme AllowJoinInProgress qui permet la connexion de joueurs, même quand la partie est lancée, ou des options permettant de filtrer les parties avec des propriété de session présentée ci-dessous.

   1: enum SessionProperty{ GameMode, SkillLevel, ScoreToWin }

   2: enum GameMode{ Practice, Timed, CaptureTheFlag }

   3: enum SkillLevel{ Beginner, Intermediate, Advanced }

une fois la session créée il ne faut pas oublié de mettre la variable isHost à true puisque nous serons le serveur dans ce cas-la et de prévenir la session qu’un joueur s’est connecté:

   1: using (AvailableNetworkSessionCollection availableSessions = NetworkSession.Find(NetworkSessionType.SystemLink,maxLocalGamers, null))

Il faut savoir que XNA se sert du GUID du projet pour trouver les sessions de jeu, donc la connexion peut se faire entre deux versions différentes du projet, si ca peut ne pas être grave il faut quand même faire attention.

Si availableSession.count est à zéro on affichera problème de connexion, sinon on passe le isHost à false et on oublie pas d’incrémenter le nombre de joueurs dans la session comme lors de la création.

Nous allons surcharger la méthode GamerJoinedEventHandler afin de pouvoir ajouter un peu de notre logique.

   1: void GamerJoinedEventHandler(object sender, GamerJoinedEventArgs e)

   2: {

   3:     if (!getIndex)

   4:     {

   5:         int gamerIndexTemp = networkSession.AllGamers.Count - 1; ;

   6:         IsNetwork = false;

   7:         netSession = networkSession;

   8:         gamerIndex = gamerIndexTemp;

   9:         getIndex = true;

  10:         affiche = false;

  11:     }

  12: }

Deuxième chose a faire dans la boucle update est de mettre à jour le réseau, une fois la connexion effectuée.

Le plus important est d’appeler la méthode netSession.Update(), et ce même si vous ne voulez que tester la connexion, puisque c’est cette méthode qui gère tout ce qui se passe sur le réseau.

Pour envoyer les infos aux joueurs sur le réseau il va falloir utiliser la méthode suivante :

   1: foreach (LocalNetworkGamer gamer in netSession.LocalGamers)

   2: {

   3:     SendNetwork(gamer);

   4: }

   5:

   6: void SendNetwork(LocalNetworkGamer gamer)

   7: {

   8:     foreach (NetworkGamer remoteGamer in netSession.RemoteGamers)

   9:     {

  10:         packetWriter.Write(gamerIndex);

  11:         packetWriter.Write(mainGame.caracter.Position.X);

  12:         packetWriter.Write(mainGame.caracter.Position.Y);

  13:         gamer.SendData(packetWriter, SendDataOptions.InOrder, remoteGamer);

  14:     }

  15: }

packetWriter.Write permet d’envoyer les datas sur le réseau, mais faites attention on ne peut pas envoyer n’importe quel type de données, vous trouverez des infos la dessus sur le site du MSDN ^^.

gamer.SendData(packetWriter, SendDataOptions.InOrder, remoteGamer) permet de préciser les options d’envoi, comme s’assurer que les données sont bien reçues dans l’ordre ou elles sont envoyées et si elle sont complètes.

De la même manière il va falloir gérer la réception des paquets.

   1: foreach (LocalNetworkGamer gamer in netSession.LocalGamers)

   2: {

   3:     ReadNetwork(gamer);

   4: }

   5:

   6: void ReadNetwork(LocalNetworkGamer gamer)

   7: {

   8:     while (gamer.IsDataAvailable)

   9:     {

  10:         NetworkGamer sender;

  11:

  12:         // Read a single packet from the network.

  13:         gamer.ReceiveData(packetReader, out sender);

  14:

  15:         if (sender.IsLocal)

  16:             continue;

  17:

  18:         int tempIndex;

  19:         tempIndex = packetReader.ReadInt32();

  20:         mainGame.caracter.Position.X = packetReader.ReadInt32();

  21:         mainGame.caracter.Position.Y = packetReader.ReadInt32();

  22:     }

  23: }

Pour lire les paquets il faut préciser leur type faites donc très attention au moment d’envoyer des données, sinon vous risquez de planter votre application ^^.

Voila vous avez tout ce qu’il vous faut pour implémenter un réseau au sein de votre jeux en XNA, j’essaierais de revenir plus tard sur des options plus avancées.

Vous retrouver comme d’habitude un projet complet utilisant le réseau, afin de pouvoir voir son intégration. Ici le principe est simple un bonhomme se balade aléatoirement sur la surface de jeu. Le serveur fait les calculs de déplacements et envoi les données sur le réseau, et les client se synchronise sur les mouvements calculés sur le serveur.

Bien entendu si vous avez des questions ou des remarques n’hésitez pas, je suis la pour ca.

networkdemo