Jeu de Tic Tac Toe multijoueurs par navigateur en React
PubNub Developer Relations
Posted on March 10, 2024
Ce billet, issu de nos archives, vous guidera à travers les étapes pour créer un jeu de Tic Tac Toe en React mais attention, les versions des bibliothèques utilisées ne sont plus les plus récentes. En particulier, cet article utilise la version 1 de notre SDK React mais toutes les étapes et les principes énumérés ci-dessous sont encore valables aujourd'hui.
Le morpion est un jeu d'enfance par excellence. Tout ce dont il a besoin, c'est d'un objet sur lequel écrire et d'un objet avec lequel écrire. Mais que se passe-t-il si vous voulez jouer avec quelqu'un qui se trouve dans un autre endroit ? Dans ce cas, vous devez utiliser une application qui vous connecte au jeu avec un autre joueur.
L'application doit offrir une expérience en temps réel, de sorte que chaque mouvement que vous faites soit vu instantanément par l'autre joueur et vice versa. Si l'application n'offre pas cette expérience, vous et de nombreuses personnes ne l'utiliserez probablement plus.
Alors, comment un développeur peut-il offrir une expérience connectée où les joueurs peuvent jouer au morpion, ou à n'importe quel jeu, où qu'ils se trouvent dans le monde ?
Concepts des jeux multijoueurs en temps réel
Il existe plusieurs façons de fournir l'infrastructure en temps réel pour les jeux multijoueurs. Vous pouvez construire votre propre infrastructure en utilisant des technologies et des protocoles open-source tels que Socket.IO, SignalR ou WebSockets.
Bien que cette voie puisse sembler attrayante, vous rencontrerez plusieurs problèmes, dont celui de l'évolutivité. Il n'est pas difficile de gérer 100 utilisateurs, mais comment gérer 100 000 utilisateurs ou plus ? Outre les problèmes d'infrastructure, vous devez encore vous préoccuper de la maintenance de votre jeu.
En fin de compte, la seule chose qui compte est d'offrir une bonne expérience aux joueurs de votre jeu. Mais comment résoudre le problème de l'infrastructure ? C'est là que PubNub intervient.
PubNub fournit l'infrastructure en temps réel pour alimenter n'importe quelle application grâce à son réseau mondial de flux de données. Avec plus de 70+ SDK, y compris les langages de programmation les plus populaires, PubNub simplifie l'envoi et la réception de messages vers n'importe quel appareil en moins de 100 ms. Il est sécurisé, évolutif et fiable, de sorte que vous n'avez pas à vous soucier de la création et de la maintenance de votre propre infrastructure.
Afin de montrer à quel point il est facile de développer un jeu multijoueur avec PubNub, nous allons construire un simple jeu React tic tac toe en utilisant le SDK React PubNub. Dans ce jeu, deux joueurs se connecteront à un canal de jeu unique où ils joueront l'un contre l'autre. Chaque mouvement effectué par un joueur sera publié sur le canal afin de mettre à jour le tableau de l'autre joueur en temps réel.
Aperçu de l'application
Voici à quoi ressemblera notre application une fois que nous l'aurons terminée.
Les joueurs rejoignent d'abord le lobby où ils peuvent créer un canal ou rejoindre un canal. Si le joueur crée un canal, il obtient un identifiant de salle à partager avec un autre joueur. Le joueur qui a créé le canal devient le joueur X et fera le premier pas lorsque le jeu commencera.
Le joueur qui rejoint un canal avec l'identifiant de salle qui lui a été attribué devient le joueur O. Les joueurs ne peuvent rejoindre un canal que s'il y a une autre personne dans le canal. S'il y a plus d'une personne, un jeu est en cours pour ce canal et le joueur ne pourra pas le rejoindre. Le jeu commence lorsqu'il y a deux joueurs dans le canal.
À la fin du jeu, le score du gagnant est augmenté d'un point. Si le jeu se termine par une égalité, aucun des deux joueurs ne se voit attribuer un point. Une fenêtre modale s'affiche pour demander au joueur X de commencer un nouveau tour ou de mettre fin au jeu. Si le joueur X continue le jeu, le tableau est réinitialisé pour le nouveau tour. Sinon, le jeu se termine et les deux joueurs retournent dans le hall.
Mise en place du lobby
Avant de configurer le lobby, créez un compte PubNub gratuit pour obtenir vos clés API Pub/Sub gratuites à partir du tableau de bord d'administration de PubNub.
Une fois que vous avez obtenu vos clés, insérez-les dans le constructeur d'App.js.
// App.js
import React, { Component } from 'react';
import Game from './Game';
import Board from './Board';
import PubNubReact from 'pubnub-react';
import Swal from "sweetalert2";
import shortid from 'shortid';
import './Game.css';
class App extends Component {
constructor(props) {
super(props);
// REPLACE with your keys
this.pubnub = new PubNubReact({
publishKey: "YOUR_PUBLISH_KEY_HERE",
subscribeKey: "YOUR_SUBSCRIBE_KEY_HERE"
});
this.state = {
piece: '', // X or O
isPlaying: false, // Set to true when 2 players are in a channel
isRoomCreator: false,
isDisabled: false,
myTurn: false,
};
this.lobbyChannel = null; // Lobby channel
this.gameChannel = null; // Game channel
this.roomId = null; // Unique id when player creates a room
this.pubnub.init(this); // Initialize PubNub
}
render() {
return ();
}
}
export default App;
C'est également dans le constructeur que les objets et les variables d'état sont initialisés. Nous reviendrons sur les objets et les variables lorsqu'ils apparaîtront dans le fichier. Enfin, nous avons initialisé PubNub à la fin du constructeur.
Dans la méthode de rendu et dans la déclaration de retour, nous ajoutons le balisage pour le composant Lobby.
return (
<div>
<div className="title">
<p> React Tic Tac Toe </p>
</div>
{
!this.state.isPlaying &&
<div className="game">
<div className="board">
<Board
squares={0}
onClick={index => null}
/>
<div className="button-container">
<button
className="create-button "
disabled={this.state.isDisabled}
onClick={(e) => this.onPressCreate()}
> Create
</button>
<button
className="join-button"
onClick={(e) => this.onPressJoin()}
> Join
</button>
</div>
</div>
</div>
}
{
this.state.isPlaying &&
<Game
pubnub={this.pubnub}
gameChannel={this.gameChannel}
piece={this.state.piece}
isRoomCreator={this.state.isRoomCreator}
myTurn={this.state.myTurn}
xUsername={this.state.xUsername}
oUsername={this.state.oUsername}
endGame={this.endGame}
/>
}
</div>
);
Le composant Lobby se compose d'un titre, d'un tableau tic tac toe vide (rien ne se passe si le joueur appuie sur les carrés) et des boutons "Create_"_ et "Join_". Ce composant n'est affiché que si la valeur d'état _isPlaying est fausse. Si elle vaut true, le jeu a commencé et le composant est remplacé par le composant Game, que nous verrons dans la deuxième partie du didacticiel.
Le composant Board fait également partie du composant Lobby. Le composant Square se trouve à l'intérieur du composant Board. Nous n'entrerons pas dans les détails de ces deux composants afin de nous concentrer sur les composants Lobby et Game.
Lorsque le joueur appuie sur le bouton "Créer", le bouton est désactivé afin que le joueur ne puisse pas créer plusieurs canaux. Le bouton "Rejoindre" n'est pas désactivé, au cas où le joueur déciderait de rejoindre un canal à la place. Lorsque le joueur appuie sur le bouton "Create", la méthode onPressCreate() est appelée.
Créer un canal
La première chose que nous faisons dans onPressCreate() est de générer un identifiant aléatoire tronqué à 5 caractères. Pour ce faire, nous utilisons shortid(). Nous ajoutons cette chaîne à 'tictactoelobby-', qui sera le canal de lobby unique auquel les joueurs s'abonneront.
// Create a room channel
onPressCreate = (e) => {
// Create a random name for the channel
this.roomId = shortid.generate().substring(0,5);
this.lobbyChannel = 'tictactoelobby--' + this.roomId; // Lobby channel name
this.pubnub.subscribe({
channels: [this.lobbyChannel],
withPresence: true // Checks the number of people in the channel
});
}
Afin d'empêcher plus de deux joueurs de rejoindre un canal donné, nous utilisons Presence. Nous verrons plus loin la logique de vérification de l'occupation du canal.
Une fois que le joueur s'est abonné au canal du lobby, une fenêtre modale s'affiche avec l'identifiant de la salle afin qu'un autre joueur puisse rejoindre ce canal.
Cette modale, et toutes les modales utilisées dans cette application, sont créées par SweetAlert2 pour remplacer les fenêtres contextuelles alert() par défaut de JavaScript.
// Inside of onPressCreate()
// Modal
Swal.fire({
position: 'top',
allowOutsideClick: false,
title: 'Share this room ID with your friend',
text: this.roomId,
width: 275,
padding: '0.7em',
// Custom CSS to change the size of the modal
customClass: {
heightAuto: false,
title: 'title-class',
popup: 'popup-class',
confirmButton: 'button-class'
}
})
A la fin de onPressCreate(), nous changeons les valeurs d'état pour refléter le nouvel état de l'application.
this.setState({
piece: 'X',
isRoomCreator: true,
isDisabled: true, // Disable the 'Create' button
myTurn: true, // Player X makes the 1st move
});
Une fois que le joueur a créé une salle, il doit attendre qu'un autre joueur la rejoigne. Examinons la logique qui permet de rejoindre une salle.
Rejoindre un canal
Lorsqu'un joueur appuie sur le bouton " Join ", la fonction onPressJoin() est appelée. Une fenêtre modale s'affiche et demande au joueur d'entrer l'identifiant de la salle dans le champ de saisie.
Si le joueur saisit l'identifiant de la salle et appuie sur le bouton "OK", la méthode joinRoom(value) est appelée, la valeur étant l'identifiant de la salle. Cette méthode n'est pas appelée si le champ de saisie est vide ou si le joueur appuie sur le bouton "Annuler".
// The 'Join' button was pressed
onPressJoin = (e) => {
Swal.fire({
position: 'top',
input: 'text',
allowOutsideClick: false,
inputPlaceholder: 'Enter the room id',
showCancelButton: true,
confirmButtonColor: 'rgb(208,33,41)',
confirmButtonText: 'OK',
width: 275,
padding: '0.7em',
customClass: {
heightAuto: false,
popup: 'popup-class',
confirmButton: 'join-button-class',
cancelButton: 'join-button-class'
}
}).then((result) => {
// Check if the user typed a value in the input field
if(result.value){
this.joinRoom(result.value);
}
})
}
La première chose que nous faisons dans joinRoom() est d'ajouter la valeur à '_tictactoelobby-',_comme nous l'avons fait dans onPressCreate().
// Join a room channel
joinRoom = (value) => {
this.roomId = value;
this.lobbyChannel = 'tictactoelobby--' + this.roomId;
}
Avant que le joueur ne s'abonne au canal de lobby, nous devons vérifier l'occupation totale du canal en utilisant hereNow(). Si l'occupation totale est inférieure à 2, le joueur peut s'abonner avec succès au canal de lobby.
// Check the number of people in the channel
this.pubnub.hereNow({
channels: [this.lobbyChannel],
}).then((response) => {
if(response.totalOccupancy < 2){
this.pubnub.subscribe({
channels: [this.lobbyChannel],
withPresence: true
});
this.setState({
piece: 'O', // Player O
});
this.pubnub.publish({
message: {
notRoomCreator: true,
},
channel: this.lobbyChannel
});
}
}).catch((error) => {
console.log(error);
});
Une fois que le joueur s'est abonné au canal de l'antichambre, la valeur d'état de la pièce passe à " O " et un message est publié sur ce canal de l'antichambre. Ce message informe le joueur X qu'un autre joueur a rejoint le canal. Nous avons configuré le récepteur de message dans componentDidUpdate(), que nous aborderons prochainement.
Si le taux d'occupation total est supérieur à 2, une partie est en cours et le joueur qui tente de rejoindre le canal se verra refuser l'accès. Le code suivant se trouve sous l'instruction if de hereNow().
// Below the if statement in hereNow()
else{
// Game in progress
Swal.fire({
position: 'top',
allowOutsideClick: false,
title: 'Error',
text: 'Game in progress. Try another room.',
width: 275,
padding: '0.7em',
customClass: {
heightAuto: false,
title: 'title-class',
popup: 'popup-class',
confirmButton: 'button-class'
}
})
}
Jetons maintenant un coup d'œil à componentDidUpdate().
Démarrer le jeu
Dans componentDidUpdate(), nous vérifions que le joueur est connecté à un canal, c'est-à-dire que this.lobbyChannel n'est pas null. Si ce n'est pas le cas, nous mettons en place un listener qui écoute tous les messages qui arrivent sur le canal.
componentDidUpdate() {
// Check that the player is connected to a channel
if(this.lobbyChannel != null){
this.pubnub.getMessage(this.lobbyChannel, (msg) => {
// Start the game once an opponent joins the channel
if(msg.message.notRoomCreator){
// Create a different channel for the game
this.gameChannel = 'tictactoegame--' + this.roomId;
this.pubnub.subscribe({
channels: [this.gameChannel]
});
}
});
}
}
Nous vérifions si le message arrivé est msg.message.notRoomCreator, qui est publié par le joueur qui rejoint le canal. Si c'est le cas, nous créons un nouveau canal, "tictactoegame-",_avec l'_identifiant de la salle ajouté à la chaîne. Le canal de jeu est utilisé pour publier tous les mouvements effectués par les joueurs, qui mettront à jour leurs tableaux.
Enfin, après avoir souscrit au canal de jeu, la valeur d'état isPlaying est fixée à true. Ce faisant, le composant lobby est remplacé par le composant jeu.
this.setState({
isPlaying: true
});
// Close the modals if they are opened
Swal.close();
}
Une fois le composant jeu affiché, nous voulons fermer toutes les fenêtres modales, si elles ont été ouvertes, à partir du composant Lobby en faisant Swal.close().
Maintenant que nous avons deux joueurs connectés à un canal de jeu unique, ils peuvent commencer à jouer au morpion ! Dans la section suivante, nous mettrons en œuvre l'interface utilisateur et la logique du composant de jeu.
Construire les fonctionnalités du jeu
La première chose que nous faisons dans Game.js est de mettre en place le constructeur de base:
// Game.js
import React from 'react';
import Board from './Board';
import Swal from "sweetalert2";
class Game extends React.Component {
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(''), // 3x3 board
xScore: 0,
oScore: 0,
whosTurn: this.props.myTurn // Player X goes first
};
this.turn = 'X';
this.gameOver = false;
this.counter = 0; // Game ends in a tie when counter is 9
}
render() {
return ();
}
}
export default Game;
Pour les objets state, nous initialisons la propriété array squares, qui est utilisée pour stocker les positions des joueurs sur le plateau. Cela sera expliqué plus loin. Nous fixons également le score des joueurs à 0 et la valeur de whosTurn à myTurn, qui est initialisé à true pour le joueur X et à false pour le joueur O.
La valeur des variables turn et counter changera tout au long de la progression du jeu. À la fin de la partie, la valeur de gameOver est fixée à true.
Ajouter l'interface utilisateur
Ensuite, nous allons mettre en place le balisage du composant Game à l'intérieur de la méthode de rendu.
render() {
let status;
// Change to current player's turn
status = `${this.state.whosTurn ? "Your turn" : "Opponent's turn"}`;
return (
<div className="game">
<div className="board">
<Board
squares={this.state.squares}
onClick={index => this.onMakeMove(index)}
/>
<p className="status-info">{status}</p>
</div>
<div className="scores-container">
<div>
<p>Player X: {this.state.xScore} </p>
</div>
<div>
<p>Player O: {this.state.oScore} </p>
</div>
</div>
</div>
);
}
Nous affichons la valeur de l'état dans l'interface utilisateur pour que les joueurs sachent si c'est leur tour de jouer ou si c'est le tour de l'autre joueur. La valeur booléenne de l'état whosTurn est mise à jour à chaque fois qu'un mouvement est effectué. Le reste de l'interface utilisateur se compose du composant Board et du score du joueur.
Ajouter la logique
Lorsque le joueur effectue un déplacement sur le plateau, un appel à onMakeMove(index) est effectué où l'index est la position de la pièce sur le plateau. Le plateau comporte 3 lignes et 3 colonnes, soit 9 cases au total. Chaque case a sa propre valeur d'index, commençant par la valeur 0 et se terminant par la valeur 8.
onMakeMove = (index) =>{
const squares = this.state.squares;
// Check if the square is empty and if it's the player's turn to make a move
if(!squares[index] && (this.turn === this.props.piece)){
squares[index] = this.props.piece;
this.setState({
squares: squares,
whosTurn: !this.state.whosTurn
});
// Other player's turn to make a move
this.turn = (this.turn === 'X') ? 'O' : 'X';
// Publish move to the channel
this.props.pubnub.publish({
message: {
index: index,
piece: this.props.piece,
turn: this.turn
},
channel: this.props.gameChannel
});
// Check if there is a winner
this.checkForWinner(squares)
}
}
Après avoir obtenu l'état des cases du tableau, une instruction conditionnelle est utilisée pour vérifier si la case que le joueur a touchée est vide et si c'est à son tour d'effectuer un déplacement. Si l'une ou les deux conditions ne sont pas remplies, le pion du joueur n'est pas placé sur la case. Dans le cas contraire, le pion du joueur est ajouté au tableau des cases de l'index sur lequel le pion a été placé.
Par exemple, si le joueur X effectue un déplacement sur la ligne 0, colonne 2 et que la condition est remplie, le tableau cases[2] aura la valeur "X".Ensuite, l'état est modifié pour refléter le nouvel état du jeu et le tour est mis à jour pour que l'autre joueur puisse jouer son coup. Pour que le plateau de l'autre joueur soit mis à jour avec les données actuelles, nous publions les données sur le canal de jeu. Tout ceci se passe en temps réel, donc les deux joueurs verront immédiatement leur plateau se mettre à jour dès qu'un coup valide est effectué. La dernière chose à faire dans cette méthode est d'appeler checkForWinner(squares) pour vérifier s'il y a un gagnant.
Avant cela, jetons un coup d'œil à componentDidMount() où nous configurons l'écouteur pour les nouveaux messages qui arrivent dans le canal du jeu.
componentDidMount(){
this.props.pubnub.getMessage(this.props.gameChannel, (msg) => {
// Update other player's board
if(msg.message.turn === this.props.piece){
this.publishMove(msg.message.index, msg.message.piece);
}
});
}
Comme les deux joueurs sont connectés au même canal de jeu, ils recevront tous les deux ce message. La méthode publishMove(index, piece) est appelée, où index est la position à laquelle la pièce a été placée et piece est la pièce du joueur qui a effectué le déplacement. Cette méthode met à jour le plateau avec le coup en cours et vérifie s'il y a un gagnant. Pour éviter que le joueur qui a effectué le déplacement en cours n'ait à recommencer ce processus, l'instruction if vérifie si la pièce du joueur correspond à la valeur de turn. Si c'est le cas, son plateau est mis à jour.
// Opponent's move is published to the board
publishMove = (index, piece) => {
const squares = this.state.squares;
squares[index] = piece;
this.turn = (squares[index] === 'X')? 'O' : 'X';
this.setState({
squares: squares,
whosTurn: !this.state.whosTurn
});
this.checkForWinner(squares)
}
La logique de mise à jour du plateau est la même que celle de onMakeMove(). Passons maintenant à checkForWinner().
checkForWinner = (squares) => {
// Possible winning combinations
const possibleCombinations = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
// Iterate every combination to see if there is a match
for (let i = 0; i < possibleCombinations.length; i += 1) {
const [a, b, c] = possibleCombinations[i];
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
this.announceWinner(squares[a]);
return;
}
}
}
Toutes les combinaisons gagnantes sont dans le double tableau possibleCombinations, où chaque tableau est une combinaison possible pour gagner le jeu. Chaque tableau dans possibleCombinations est comparé au tableau squares. S'il y a une correspondance, il y a un gagnant. Prenons un exemple pour mieux comprendre.
Supposons que le joueur X joue un coup gagnant dans la ligne 2 colonne 0. L'index de cette position est 6. Le tableau ressemble maintenant à ceci :
La combinaison gagnante pour le joueur X est [2,4,6]. Le tableau des cases est mis à jour : ["O", "", "X", "O", "X", "", "X", "", ""].
Dans la boucle for , lorsque [a,b,c] a les valeurs [2,4,6], l'instruction if de la boucle for est vraie puisque [2,4,6] ont tous la même valeur de X. Le score du gagnant doit être mis à jour, et la*fonction announceWinner()* est donc appelée pour récompenser le joueur gagnant.
Si le jeu se termine par une égalité, il n'y a pas de gagnant pour ce tour. Pour vérifier s'il y a égalité, nous utilisons un compteur qui s'incrémente de un à chaque fois qu'un mouvement est effectué sur le plateau.
// Below the for loop in checkForWinner()
// Check if the game ends in a draw
this.counter++;
// The board is filled up and there is no winner
if(this.counter === 9){
this.gameOver = true;
this.newRound(null);
}
Si le compteur atteint 9, la partie se termine par un match nul parce que le joueur n'a pas joué un coup gagnant sur la dernière case du plateau. Dans ce cas, la méthode newRound() est appelée avec un argument null puisqu'il n'y a pas de gagnant.
Avant de passer à cette méthode, revenons àannounceWinner().
// Update score for the winner
announceWinner = (winner) => {
let pieces = {
'X': this.state.xScore,
'O': this.state.oScore
}
if(winner === 'X'){
pieces['X'] += 1;
this.setState({
xScore: pieces['X']
});
}
else{
pieces['O'] += 1;
this.setState({
oScore: pieces['O']
});
}
// End the game once there is a winner
this.gameOver = true;
this.newRound(winner);
}
Le paramètre de cette méthode est le gagnant, qui est le joueur qui a gagné la partie. Nous vérifions si le gagnant est 'X' ou 'O' et incrémentons son score d'un point. Puisque le jeu est terminé, la variable gameOver est fixée à true et la méthode newRound() est appelée.
Commencer un nouveau tour
Le_joueur X_ a la possibilité de jouer un nouveau tour ou de mettre fin au jeu et de retourner dans le lobby.
L'autre joueur doit attendre que le joueur X décide de ce qu'il va faire.
Une fois que le joueur X a pris sa décision, un message est publié sur le canal du jeu pour en informer l'autre joueur. L'interface utilisateur est alors mise à jour.
newRound = (winner) => {
// Announce the winner or announce a tie game
let title = (winner === null) ? 'Tie game!' : `Player ${winner} won!`;
// Show this to Player O
if((this.props.isRoomCreator === false) && this.gameOver){
Swal.fire({
position: 'top',
allowOutsideClick: false,
title: title,
text: 'Waiting for a new round...',
confirmButtonColor: 'rgb(208,33,41)',
width: 275,
customClass: {
heightAuto: false,
title: 'title-class',
popup: 'popup-class',
confirmButton: 'button-class',
} ,
});
this.turn = 'X'; // Set turn to X so Player O can't make a move
}
// Show this to Player X
else if(this.props.isRoomCreator && this.gameOver){
Swal.fire({
position: 'top',
allowOutsideClick: false,
title: title,
text: 'Continue Playing?',
showCancelButton: true,
confirmButtonColor: 'rgb(208,33,41)',
cancelButtonColor: '#aaa',
cancelButtonText: 'Nope',
confirmButtonText: 'Yea!',
width: 275,
customClass: {
heightAuto: false,
title: 'title-class',
popup: 'popup-class',
confirmButton: 'button-class',
cancelButton: 'button-class'
} ,
}).then((result) => {
// Start a new round
if (result.value) {
this.props.pubnub.publish({
message: {
reset: true
},
channel: this.props.gameChannel
});
}
else{
// End the game
this.props.pubnub.publish({
message: {
endGame: true
},
channel: this.props.gameChannel
});
}
})
}
}
Si le message est réinitialisé, toutes les valeurs et variables d'état, à l'exception du score des joueurs, sont ramenées à leur valeur initiale. Toutes les fenêtres modales encore ouvertes sont fermées et un nouveau tour commence pour les deux joueurs.
Pour le message endGame, toutes les fenêtres modales sont fermées et la méthode endGame() est appelée. Cette méthode se trouve dans App.js.
// Reset everything
endGame = () => {
this.setState({
piece: '',
isPlaying: false,
isRoomCreator: false,
isDisabled: false,
myTurn: false,
});
this.lobbyChannel = null;
this.gameChannel = null;
this.roomId = null;
this.pubnub.unsubscribe({
channels : [this.lobbyChannel, this.gameChannel]
});
}
Toutes les valeurs et variables d'état sont réinitialisées à leurs valeurs initiales. Les noms des canaux sont remis à zéro car un nouveau nom est généré chaque fois qu'un joueur crée une salle. Comme les noms des canaux ne seront plus utiles, les joueurs se désinscrivent du lobby et du canal de jeu. La valeur de isPlaying est réinitialisée à false, de sorte que le composant de jeu sera remplacé par le composant de lobby.
La dernière méthode à inclure dans App.js est componentWillUnmount(), qui désinscrit les joueurs des deux canaux.
componentWillUnmount() {
this.pubnub.unsubscribe({
channels : [this.lobbyChannel, this.gameChannel]
});
}
C'est tout ce que nous avons à faire pour que le jeu fonctionne ! Vous pouvez obtenir le fichier CSS pour le jeu dans le repo. Maintenant, faisons fonctionner le jeu.
Lancer le jeu
Il y a quelques petites étapes à franchir avant de lancer le jeu. Tout d'abord, nous devons activer la fonctionnalité Presence car nous l'utilisons pour obtenir le nombre de personnes dans le canal (nous avons utilisé withPresence lors de l'abonnement au canal lobby). Allez dans le PubNub Admin Dashboard et cliquez sur votre application. Cliquez sur Keyset et descendez jusqu'à Application add-ons. Activez le commutateur Presence . Conservez les valeurs par défaut.
Pour installer les trois dépendances utilisées dans l'application et pour lancer l'application, vous pouvez exécuter le script dependencies.sh qui se trouve dans le répertoire racine de l'application.
# dependencies.sh
npm install --save pubnub pubnub-react
npm install --save shortid
npm install --save sweetalert2
npm start
Dans le terminal, allez dans le répertoire racine de l'application et tapez la commande suivante pour rendre le script exécutable:
chmod +x dependencies.sh
Exécutez le script avec cette commande :
./dependencies.sh
L'application s'ouvrira à l'adresse http://localhost:3000 avec le composant lobby affiché.Ouvrez un autre onglet, ou de préférence une fenêtre, et copiez et collez http://localhost:3000. Dans une fenêtre, créez un canal en cliquant sur le bouton "Créer". Une fenêtre modale s'ouvre et affiche l'identifiant de la salle. Copiez et collez cet identifiant. Allez dans l'autre fenêtre et cliquez sur le bouton "Rejoindre". Lorsque la fenêtre s'affiche, saisissez l'identifiant de la salle dans le champ de saisie et cliquez sur le bouton "OK".
Une fois que les joueurs sont connectés, le jeu commence. La fenêtre que vous avez utilisée pour créer le canal joue le premier coup. Appuyez sur n'importe quelle case du plateau et voyez la pièce X s'afficher sur le plateau en temps réel pour les deux fenêtres. Si vous essayez d'appuyer sur une autre case du même plateau, rien ne se passera car ce n'est plus votre tour de jouer. Dans l'autre fenêtre, appuyez sur n'importe quelle case de l'échiquier et la pièce O sera placée sur la case.
Continuez à jouer jusqu'à ce qu'il y ait un gagnant ou une égalité. Une fenêtre modale s'affiche alors pour annoncer le vainqueur du tour ou pour annoncer que la partie s'est terminée par une égalité. Dans la même fenêtre, le joueur X devra décider s'il continue à jouer ou s'il quitte le jeu. La fenêtre modale du joueur O lui dira d'attendre un nouveau tour.
Tout, sauf le score, est remis à zéro si le joueur X continue le jeu. Dans le cas contraire, les deux joueurs sont renvoyés dans le lobby où ils peuvent créer ou rejoindre de nouveaux canaux. Découvrez la démo du jeu ci-dessous :
Vous avez des suggestions ou des questions concernant le contenu de cet article ? N'hésitez pas à nous contacter à l'adresse devrel@pubnub.com.
Sommaire
Concepts du jeu multijoueur en tempsréelVue d'ensemble de l'applicationConfigurer lelobbyCréerun canalJoindre uncanalDémarrerle jeuConstruire lesfonctionnalités du jeuAjouterl'UIAAjouter lalogiqueDémarrerun nouveau roundFaire tourner lejeu
Comment PubNub peut-il vous aider ?
Cet article a été publié à l'origine sur PubNub.com
Notre plateforme aide les développeurs à construire, livrer et gérer l'interactivité en temps réel pour les applications web, les applications mobiles et les appareils IoT.
La base de notre plateforme est le réseau de messagerie en temps réel le plus grand et le plus évolutif de l'industrie. Avec plus de 15 points de présence dans le monde, 800 millions d'utilisateurs actifs mensuels et une fiabilité de 99,999 %, vous n'aurez jamais à vous soucier des pannes, des limites de concurrence ou des problèmes de latence causés par les pics de trafic.
Découvrez PubNub
Découvrez le Live Tour pour comprendre les concepts essentiels de chaque application alimentée par PubNub en moins de 5 minutes.
S'installer
Créez un compte PubNub pour un accès immédiat et gratuit aux clés PubNub.
Commencer
La documentation PubNub vous permettra de démarrer, quel que soit votre cas d'utilisation ou votre SDK.
Posted on March 10, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 29, 2024