Après l’ajout du terrain, voici l’ajout de l’adversaire, ainsi que du serveur servant à synchroniser les données entre les deux clients (joueurs).
L’adversaire est un joueur comme le joueur principale, mais il est piloté par une autre source (pas les événements de la souris (ou tactile), mais il s’affiche de la même façon. Je réutilise donc la même classe.
Le serveur va nous servir à transmettre les informations du jeu, d’un joueur à un autre. Ayant commencé à faire mon code en JavaScript, et avec l’arrivé de node.js (depuis quelque temps), je voulais l’essayer, surtout avec le module Socket.io, qui répond tout à fait au besoin présent.
Je ne présenterais pas node.js, ni socket.io, tellement il y a des exemples, tutoriels, … et qu’il est facile de la trouver sur l’Internet en cherchant sur Google.
J’ai écrit un serveur assez simple qui lorsqu’il reçoit des informations d’un joueur les retransmets au second joueur :
var io = require('socket.io').listen(8080); // une partie function jeu() { this.joueur1 = null; this.joueur2 = null; } jeu.prototype.isReady = function() { return this.joueur1 !== null && this.joueur2 !== null; } // le serveur gere plusieurs partie de air hockey var jeuList = new Array(); // tentative d'association de joeur entre eux pour faire une partie function association(socket) { var currentJeux = null; for(var i=0;i<jeuList.length;i++) { if(!jeuList[i].isReady()) { currentJeux = jeuList[i]; } } if(currentJeux == null) { jeuList.push(new jeu()); currentJeux = jeuList[jeuList.length-1]; } if(currentJeux.joueur1 === null){ currentJeux.joueur1 = socket; } else if(currentJeux.joueur2 === null){ currentJeux.joueur2 = socket; } } // déroulement d'une partie function eventJeu(currentJeux) { currentJeux.joueur1.emit('debutJeu'); currentJeux.joueur2.emit('debutJeu'); currentJeux.joueur1.on('Bouge', function(data) { currentJeux.joueur2.emit('BougerSeul', data); }); currentJeux.joueur2.on('Bouge', function(data) { currentJeux.joueur1.emit('BougerSeul', data); }); currentJeux.joueur1.on('PaletChange', function(data) { currentJeux.joueur2.emit('ChangerPalet', data); }); currentJeux.joueur2.on('PaletChange', function(data) { currentJeux.joueur1.emit('ChangerPalet', data); }); currentJeux.joueur1.on('disconnect', function() { currentJeux.joueur1 = null; currentJeux.joueur2.emit('departAdversaire'); }); currentJeux.joueur2.on('disconnect', function() { currentJeux.joueur2 = null; currentJeux.joueur1.emit('departAdversaire'); }); } function connection(socket){ association(socket); if(jeuList.length > 0 && jeuList[jeuList.length-1].isReady()) { eventJeu(jeuList[jeuList.length-1]); } } function deconnection(socket) { var deleteIndex = -1; for(var i=0;i<jeuList.length;i++) { if(jeuList[i].joueur1 === socket) { jeuList[i].joueur1 = null; jeuList[i].joueur2.emit("departAdversaire"); } if(jeuList[i].joueur2 === socket) { jeuList[i].joueur2 = null; jeuList[i].joueur1.emit("departAdversaire"); } if(jeuList[i].joueur1 === null && jeuList[i].joueur2 === null) { deleteIndex = i; } } if(deleteIndex > -1) jeuList.splice(deleteIndex, 1); } io.sockets.on('connection', function(socket) { connection(socket); });
Les informations sont les déplacements du joueur, du palet, … c’est tout pour l’instant … mais il pourrait devrait y avoir le score aussi.
La petite subtilité c’est de géré une liste de parties, quand un joueur ce connecte, il est placé dans un partie, le joueur suivant sera dans la même partie. Le troisième joueur commencera une nouvelle partie et attendras une nouvelle connexion
Voici le code du client qui reçoit les événements du serveur :
socket = io.connect('http://localhost:8080'); socket.on('debutJeu', function(data) { alert('Debut de la partie!'); }); socket.on('BougerSeul', function(data) { adversaire.bougerSeul(data.x, data.y); }); socket.on('ChangerPalet', function(data) { var newAngle = Math.atan2(data.vy, data.vx); newAngle = 2 * Math.PI - newAngle; ballon.bougera(newAngle, data.force, true); }); socket.on('departAdversaire', function() { alert('votre adversaire est parti'); });
Cela ne fonctionne pas trop mal pour la synchronisation des joueurs, j’ai du faire quelque adaptations car j’ai considérais que le joueur jouant était forcement en bas. Il à fallu faire un changement sur les coordonnées.
// pour le retour du serveur: affichage en miroir. poussoir.prototype.bougerSeul = function(x, y) { this.x = env.width - x; this.y = env.height - y; }
Le résultat est testable ici : V3 d’un air-hockey en javascript.
J’ai un peu plus de problème sur le palet, d’un part pour le bon calcul de son angle, et surtout pour la synchro de la direction du palet. Le calcul des collisions se fait sur les deux clients et est synchroniser avec l’autre client à chaque changement de direction du palet (collision). Mais chaque client à son propre timer, qui n’est pas synchroniser. Donc entre un décalage du calcul de collisions et un mauvais report des angles de direction du palet : il fait un peu n’importe quoi.
La correction de ce problème sera une prochaine étape. Ces calculs de trajectoire et mise à jour de la position du palet se sera faite sur le serveur qui emmétra des indications aux clients lors de changement. Et les clients s’occuperont uniquement de l’affichage et de l’input des data de la capture des déplacements du joueur. Mais ceci sera pour la prochaine fois.
Ps : si quelqu’un à envie de rendre le jeu plus jolie, qu’il n’hésite à allez voir sur les sources sur github. De même que toute amélioration technique ou pour consultation










