Le Multijoueur sous GameMaker expliqué
GM
Buhl Damien
allias daminetreg
http://lecbna.com/
- Topic Forum Correspondant
GameMaker 6 et +
Enregistré
Bien,
Je vais dans ce petit tutorial (:p) énumerer toutes les façons de faire un jeu multijoueur sous GameMaker.
Aussi à sa fin vous trouverez comment créer un jeu multijoueur rapidement et facilement, le tout bien expliqué par mes soins.
Aller laissez vous tenter, c'est lu en une demi-heure, et le tuto en fin de page dure 15 minutes, allez s'il vous plaît dites oui?
45 minutes de votre temps pour devenir un Online GMProger.
De plus si ça vous paraît trop long vous pouvez juste lire la fin du tutorial: Un petit projet, cela ne durera que 15 minutes, toutefois il est conseillé de le lire en entier si l'on veut vraiment comprendre, et pas juste recopier. Merci d'avance.

Voici le Sommaire:
GML: Mode Multi Joueurs
1    Configurer une connexion
2    Créer et Rejoindre des Sessions
3    Joueurs
4    Partage de Données ou Shared Data
5    Messages
Autres Façons De Créer Un Jeu Multi Joueurs
Un petit Projet



GML: Mode Multi Joueurs


Jouer contre l'ordinateur est amusant.  Mais jouer contre d'autres êtres humains peut être encore plus amusant. Il est relativement facile de fabriquer de tels jeux car vous n'aurez pas à mettre en place des algorithmes compliqués d'Intelligence Artificielle (IA). Vous pouvez bien sur mettre deux joueurs devant le même clavier et leurs demander d'utiliser des touches différentes mais il est plus intéressant de mettre chaque joueur devant son ordinateur.  Ou mieux encore, un joueur de chaque côté de l'océan. Game Maker offre un support multi joueurs. Veuillez réaliser que synchroniser tout ce petit monde sans délai d'attente est une tâche difficile, et qu'ici je ne ferais qu'expliquer les bases.

1    Configurer une connexion

Pour que 2 ordinateurs communiquent, il faut un protocole de connexion. Comme beaucoup de jeux, Game Maker offre 4 différents types de connexion : IPX, TCP/IP, Modem, et Série :
 
IPX    Ce protocole fonctionne de façon complètement transparente. Il peut être utilisé par différents joueurs situés sur le même réseau local. Il doit être installé sur votre ordinateur pour être utilisable (voir la documentation d'installation de Windows ou allez dans les propriétés du Voisinage Réseau et ajoutez le protocole IPX)
TCP/IP     est le protocole internet. Il peut être utilisé pour jouer avec des personnes situées n'importe où sur le Web, à condition que vous connaissiez leurs adresses IP.
Modem    Il faut dans ce cas appeler un autre joueur ayant lui aussi un modem par son numéro de téléphone et une chaîne de caractères d'initialisation.
Série    Grâce à un simple câble entre 2 ordinateurs, vous pouvez jouer ensemble à condition de préciser le port série (Com1, Com2 etc.) utilisé.

Voici les fonctions utilisables :

mplay_init_ipx()        
Initialise une connexion IPX.
mplay_init_tcpip(adr)    
Initialise une connexion TCP/IP . Adr est une chaîne IP ('www.gameplay.com' ou '123.123.123.222') suivie éventuellement d'un port (':12' à '123.123.123.222:12). Sur un réseau local, les adresses ne sont pas nécessaires.
mplay_init_modem(init,notel)
Initialise une connexion modem. Init est la chaîne d'initialisation (peut être vide) et NoTél est le numéro de téléphone à appeler ('001122334455'). C'est seulement pour joindre une session qu'il vous faut un n° de téléphone.
mplay_init_serial(noport,vitesse,bitarret,parité,flux)
Initialise une connexion série.
- NoPort     est le numéro de port (1-4). 0 affiche une boîte de dialogue.
- Vitesse     (baudrate) 100 Bauds à 256 KBauds.
- BitArrêt     0 = 1 bit, 1 = 1.5 bit, 2 = 2 bits.
- Parité     0=none, 1=odd, 2=even, 3=mark.  
- Flux     (flow ctrl)  0=none, 1=xon/xoff, 2=rts, 3=dtr, 4=rts et dtr.
Indique si la connexion est réussie. Un paramétrage classique est : 1,57600,0,0,4.

Votre jeu doit utiliser ces fonctions qu'une seule fois. Toutes ces fonctions indiquent si l'initialisation s'est correctement déroulée. Il y a erreur si le protocole n'est pas installé ou supporté par l'ordinateur. Pour vérifier si la connexion en elle-même est correcte, utilisez la fonction :

mplay_connect_status()
Retourne le type de statut de la connexion en cours
0 : erreur    1 : IPX    2 : TCP/IP    3 : Modem    4 : Série

mplay_end()    Coupe la connexion.

Quand vous utilisez une connexion TCP/IP, vous devez connaître l'adresse IP de la personne jointe. Et parfois la vôtre ! La fonction suivante y pourvoit :

mplay_ipaddress()
Retourne l'adresse IP de votre ordinateur (exemple : '123.123.123.12'). Vous pouvez afficher cette adresse à l'écran. Attention, cette routine prend du temps (enfin pas tant que ça).
 
2    Créer et Rejoindre des Sessions

Quand vous vous connectez à un réseau, il peut y avoir divers jeux en cours de route. Nous appelons çà des sessions. Ces différentes sessions correspondent à différents jeux ou à un seul. Un jeu doit être identifié de façon unique sur un réseau. Heureusement, Game Maker s'en occupe. La seule chose  à savoir est que vous devez changer l'identifiant dans les options du jeu à travers les différentes versions. Sans cette précaution, il est possible de jouer avec des personnes ayant une ancienne version ou une récente.

Si vous démarrer une session multi joueur, il faut la créer:

mplay_session_create(nomsession,maxi,nomjoueur)
Crée une nouvelle session dans la connexion en cours.
- NomSession est le nom de la session à créer.
- Maxi est le nombre maximum de joueurs dans cette session.
- NomJoueur est le nom du joueur, le vôtre.
Indique si la session a pu être créée.

Une instance du jeu doit créer la session. Les autres instances du jeu rejoignent la session qui vient d'être créée. C'est un peu plus compliqué : Vous devez d'abord voir quelles sessions sont disponibles puis choisir celle à rejoindre. 3 fonctions s'en occupent :

mplay_session_find()
Recherche toutes les sessions qui acceptent des joueurs et retourne le nombre de sessions trouvées.
mplay_session_name(num)
Retourne le nom de la session n° Num (0 est la 1ère session). Cette routine ne fonctionne que si la précédente a été appelée.
mplay_session_join(num,nomjoueur)
Vous introduit dans la session n° Num (0 est la 1ère session). NomJoueur est le nom que vous décidez de prendre en tant que joueur dans la session.La fonction indique si tout s'est bien passé.

Il y a une autre routine qui vous permet de changer de mode de session. Doit être appelée après la création de la session :

mplay_session_mode(dépl)     Faut-il oui ou non transférer l'hôte de la session sur un autre ordinateur quand l'hôte quittera la partie ? Dépl est soit sur True ou sur False (valeur par défaut).

Pour connaître le statut de la session en cours :

mplay_session_status()    Retourne le statut : 0 = pas de session, 1 = session créée, 2 = session rejointe.

Un joueur peut quitter la session par la fonction suivante :

mplay_session_end()    Termine la session pour le joueur.

3    Joueurs

Chaque instance du jeu qui rejoint une session est en réalité considérée comme un joueur. Chaque joueur a un nom. Trois routines s'occupent des joueurs :

mplay_player_find()    Recherche tous les joueurs d'une session et retourne le nombre de joueurs trouvés.
mplay_player_name(num)    Retourne le nom du joueur n° Num (0 étant le 1er joueur). Cette routine ne fonctionne que si la précédente a été appelée.
mplay_player_id(num)    Retourne l'identifiant unique (id) du joueur n° Num (0 étant le 1er joueur). Cette routine ne doit être utilisée qu'après avoir lancé mplay_player_find(). Cet ID est utilisé pour envoyer et recevoir des messages des autres joueurs.

4    Partage de Données ou Shared Data

La communication par partage de données est probablement la façon la plus simple( pour les matheux, car il vous faudra faire deux trois calculs pour définir les slots selon le nombre de joueurs) et la meilleur de synchroniser le jeu. Toutes vos communications sont protégées. Il y a un ensemble de 1000000 valeurs (ou emplacements, je préfère nommer ça Slot) qui sont communes à tout le jeu. Chaque instance du jeu peut lire et écrire des valeurs dans ces emplacements. Game Maker garantit que chaque instance du jeu (chaque joueur) voit les mêmes valeurs. Une valeur peut être un réel ou texte. Il y a seulement 2 routines :

mplay_data_write(e,v)    Ecrit la valeur V (texte ou réel) à l'emplacement E (E compris entre 0 et 1000000).
mplay_data_read(e)    Retourne la valeur de l'emplacement E (entre 0 et 1000000). Au début, toutes les valeurs sont à 0.

Pour synchroniser ces valeurs sur différents ordinateurs, vous pouvez utiliser un mode "garanti" qui vous assure que chaque changement de valeur sera bien envoyé à tout le monde (mode lent) ou un mode "non garanti" plus rapide. Pour choisir le mode, utilisez la fonction :

mplay_data_mode(guar)    
Guar = true       mode "garanti" (valeur par défaut).
Guar = false      mode "non garanti".

Note: Le mode garanti, n'est pas si lent que les gens le pense, mieux vaut l'utiliser, jusqu'à un certain nombre de joueurs, puis au dessus de ce nombre changer le mode.
Pour les mmo, qui comporte beaucoup de joueurs, le mode non garanti est intéressant pour les déplacements mais pour ce qui est des messages privés etc... mieux vaut l'utiliser,
après vous faites ce que vous désirez.

5    Messages

Le second mécanisme de communication que Game Maker supporte est l'envoi et la réception de message. Un joueur peut envoyer des messages vers un joueur en particulier ou à tous les joueurs. Les joueurs peuvent ainsi accorder leurs actions en fonction des messages reçus. Ces messages peuvent être envoyés en mode "garanti" pour être sur qu'ils arrivent (mais ce mode est lent) ou en mode "non garanti" (qui est plus rapide et tout aussi fiable devrais je dire...).

Les routines suivantes existent :

mplay_message_send(joueur,id,val)
Envoie un message au joueur indiqué (soit un identifiant ou un nom, utilisez 0 pour adresser un message à tous les joueurs). Id est un nombre entier qui identifie le message et Val est la valeur (texte ou réel). Le message est envoyé en mode "non garanti".
mplay_message_send_guaranteed(joueur,id,val)
Idem que la précédente sauf que le message est envoyé en mode "garanti".
mplay_message_receive(player)
Reçoit le prochain message stocké dans la mémoire d'entrée, de réception des messages, tampon (buffer/queue) qui provient du joueur indiqué (nom ou identifiant). Utilisez 0 pour recevoir un message de tous les joueurs. La routine indique s'il existe effectivement un message à lire. Pour consulter le message, utilisez les fonctions suivantes :
mplay_message_id()     Retourne l'identifiant du dernier message reçu.
mplay_message_value()     Retourne la valeur du dernier message reçu.
mplay_message_player()     Indique le joueur qui a envoyé le dernier message reçu.
mplay_message_name()     retourne le nom du joueur qui a envoyé le dernier message reçu
mplay_message_count(joueur)     Retourne le nombre de messages restés dans le buffer d'entrée provenant du joueur indiqué (0 pour compter les messages de tous les joueurs).
mplay_message_clear(joueur)     Supprime tous les messages restés dans le tampon d'entrée du joueur indiqué (0 pour effacer tous les messages de tous les joueurs).

Pour envoyer un message, il faut connaître l'identifiant ou le nom du joueur voulu. Utilisez la fonction mplay_player_id() pour le connaître. Si plusieurs joueurs ont le même nom, seul le 1er est concerné. Idem pour lire un message particulier, il faut connaître qui l'envoie.
Pourquoi chaque message possède un identifiant ? La raison est que çà facilite beaucoup la programmation. Cet identifiant est une sorte de type de message et permet de faire le tri en réception. Comme l'envoie de messages n'est pas garanti, vous pouvez utiliser cet identifiant comme une sorte de compteur afin de vérifier si tout a bien été reçu dans l'ordre.

Bien sûr il existe d'autres façons de créer un jeu  multijoueur sous  GameMaker, mais puisqu'elle  ne  sont  pas  officielles  nous  ne  les aborderons pas.
Je vais juste vous donnez quelques noms afin que vous puissiez les retrouver sur la toile:
-GMSock
-SOC
-GMProxy
-CBNA_IPC
Et sûrement d'autres dont je ne connais pas l'existence.


Un petit Projet



Bien, il est tant d'appliquer ce que vous venez d'apprendre n'est-ce pas?
Si vous ne voulez pas tant pis, mais je l'ai déjà écris et vous me fairez le plaisir de lire...

Légende:
Sprites
Sounds
Background
Paths
Scripts
Fonts
Timelines
Objects
Rooms

Groupe

Event
Action

§Point étape
!Information importante

1) Le jeu

Tout d'abord, qu'allons nous faire?
Un jeu vidéo simple multijoueur sur internet, pour éviter tous calculs mathématiques périlleux, nous allons donc limiter notre jeu à 2 joueurs.
Que diriez vous d'un jeu où deux joueur se déplacent dans une room?
Ce n'est pas vraiment un jeu, mais c'est un moyen de vous apprendre à vous servir du multijoueur et de créer quelques chose d'intéressant et simple à programmer.

2) Le système dont nous allons user

Maintenant, quel protocole allons nous utiliser?
Les message seraient intéressant pour un tchat, mais les shared data sont beaucoup plus intéressants pour une mise à jour en temps réel des informations sur le joueur comme les variables x,y.
Donc ici nous userons des Shared data.

3) Mise en application
Vous êtes prêt?
Ok, on y va!
Bien nous allons tout d'abord définir les paramètres globaux du jeu, ainsi que le script de connexion serveur et client.

Nous allons créer l'unique script de connexion:

script_connect
ip = get_string("Ip:","127.0.0.1");

if (mplay_init_tcpip(ip) != 1)
{
show_message("Connexion Imossible.");
break;
}
else
{
global.name = get_string("Nom du joueur","daminetreg");
}

if (mplay_session_find() == 0)
{
game_name = get_string("Nom de la partie:","Serv");
global.gamename = game_name;
mplay_session_create(game_name,2,global.name);
global.ident = 1;//Pour définir qui est le joueur 1
//Jeu en préchargement
}
else
{
global.gamename = mplay_session_name(0);
mplay_session_join(mplay_session_name(0),global.name);
global.ident = 2;//Pour définir qui est le joueur 2
}

global.number = mplay_player_find();//Nous n'en aurons pas usage
On règle sur 2 le nombre max de joueur.


! Soyez conscient qu'il faut toujours qu'il y est un joueur qui fasse le serveur et l'autre le client, sinon le jeu ne peut pas fonctionner.
Maintenant créons un objet: Y_control



Y_control
Vous y entrerez les paramètres suivant:
Selectionnez l'event create puis entrez y l'action Execute a piece of code:
mplay_data_mode(false);//Les données seront en mode non garanti
script_connect();

§Vous en êtes là, Step 1:

Voir l'image en grand
Récapitulatif:
-Vous avez créé le script_connect
-Vous avez créé un objet Y_control

Bien maintenant il nous faut créer les scripts de maintenance des joueurs, c'est à dire les scripts qui vont mettre à jour et qui vont lire les mises à jour des déplacement des joueurs.
Nous inclueront aussi dans ce script, un système pour savoir si un des deux joueurs quitte la partie.
Donc, créons dans Scripts un groupe que nous nommerons: Maintenance
Nous y placerons les deux scripts qui suivent:
script_update_p1
//Script de maintenance du joueur 1
//lecture des déplacements
x = mplay_data_read(5);
y = mplay_data_read(6);
//Déplacements
if global.ident = 1//si le joueur est l'hôte
{
if (keyboard_check(vk_up))
{
y -= 6
mplay_data_write(6,y);
}

if (keyboard_check(vk_down))
{
y +=6
mplay_data_write(6,y);
}

if (keyboard_check(vk_left))
{
x -= 6
mplay_data_write(5,x);
}

if (keyboard_check(vk_right))
{
x +=6
mplay_data_write(5,x);
}
}

//Si l'autre joueur quitte
//if (mplay_player_find() < 2)
//{
// show_message('...::Le joueur adverse a quitté la session::...');
// game_end();
//}


script_update_p2
//Script de maintenance du joueur 2
//Synchronisation des déplacements
x = mplay_data_read(11);
y = mplay_data_read(12);
//Déplacements
if global.ident = 2//Si le joueur est le client
{
if (keyboard_check(vk_up))
{
y -= 6
mplay_data_write(12,y);
}

if (keyboard_check(vk_down))
{
y +=6
mplay_data_write(12,y);
}

if (keyboard_check(vk_left))
{
x -= 6
mplay_data_write(11,x);
}

if (keyboard_check(vk_right))
{
x +=6
mplay_data_write(11,x);
}
}

//Si l'autre joueur quitte
//if (mplay_player_find() < 2)
//{
// show_message('...::Le joueur adverse a quitté la session::...');
// game_end();
//}



!Nous avons créer deux scripts quasiment similaire, pour bien vous montrer qu'il faut utiliser des slots différents pour les données du joueur 1 et les données du joueur 2. En réalité il serait préférable de ne faire qu'un seul script se basant sur une variable d'identifiant de joueur associée a un objet joueur unique, mais ici c'est un anti-pattern à but pédagogique.
Prenez la 11ème ligne:
mplay_data_write(12,y);
Le 12 est le slot utilisé, et le y la valeur qui est attribué à ce slot.
On ne peut pas utilisé deux fois le même slot? bien compris? des réticences?     Non? vous êtes un bon élève. :p



Maintenant nous allons créer un groupe nommé Joueurs dans objects, nous y inclueront les objets: J1 et J2
Vous créerez aussi un groupe Joueurs dans sprite et vous y incluerez les sprites: spr_j1 et spr_j2
Suite à cela vous chargerez les sprites de votre choix et les assignerez à leurs objets respectifs, c'est à dire: spr_j1 pour J1 et spr_j2 pour J2.


Dans
J1 vous entrerez une piece of code dans step ( comme vu plus haut ) pour executer: script_update_p1
Ensuite pour
J2 dans step placez une piece of code pour executer: script_update_p2

Puis vous créerez une room nommée
Y_room .

Vous y placerez les objets
J1 , J2 et Y_control

Sauvegardez le tout puis cliquez sur la petite flèche verte qui permet de faire démarrer le jeu.
Il vous suffit après avoir sauvegardé votre gm6, de l'ouvrir deux fois et de le démarrer deux fois, entrez y dans chacun l'ip 127.0.0.1 de cettes façon vous pourrez tester le jeu en local sur votre ordinateur. ;p
Si cela ne fonctionne pas assurez vous que vous avez la version Enregistrée de GM 6 ou +, cherchez si vous ne vous êtes pas trompé quelque part, éssayez de refaire le tutorial, ou alors connectez vous sur http://lecbna.com/ direction: Le Forum, là il y aura bien quelqu'un pour vous aider ( Moi par exemple ).
Topic du tutorial: http://


§Vous en êtes là, Step Final:

Voir l'image en grand
Récapitulatif:
-Vous avez créé le script_connect
-Vous avez créé un objet Y_control
-Vous avez créé le script_update_p1
-Vous avez créé le script_update_p2
-Vous avez crée le sprite
spr_j1
-Vous avez créé le sprite spr_j2
-Vous avez crée l'objet J1
-Vous avez crée l'objet J2
-Vous avez créé le
script_update_p2

Alors après tout ça? vous trouvez toujours aussi dur de créer un jeu multijoueur?
Vous vous rendez compte, c'est tout simple, c'est même enfantin, mais ça semble faire peur à tout le monde, au moins maintenant vous savez comment faire, et vous savez que ce n'est pas difficile. ;-)

J'espère simplement que cela vous aidera à créer de super jeux multijoueurs, et si jamais vous en créez un, contactez moi: lecbna@estvideo.fr , je serais très heureux d'y jouer et de le publier sur Le CBNA.
J'ai passé un agréable moment avec vous merci, vous êtes un bon élève. :)


Buhl Damien
allias daminetreg
Fondateur du CBNA
http://lecbna.com/
@3