20-04-2014, 08:28 AM
Ok ! Alors allons-y
Donc, je vais partir sur un exemple en ajax tout simple, histoire d'éviter les websockets pour le moment (mais si besoin je te ferais ça ensuite).
Admettons que tu as une table battle qui ressemble à ça :
(int) battle_id
(int) player1
(int) player2
(int) hpPlayer1
(int) hpPlayer2
(int) incomingDamages
(enum) currentStep (PLAYER1_ATTACK, PLAYER2_AVOID, PLAYER2_ATTACK, PLAYER1_AVOID)
Au début du combat, tu créé dans cette table une ligne :
Ensuite, tu lances le combat. Donc, tu vas avoir une page avec la vie des deux joueurs, quelque chose de ce genre :
Histoire de faire simple, je vais réduire au maximum le code javascript. On va donc juste actualiser à intervalle régulier la bataille (c'est pas la manière la plus propre de faire, mais c'est pour te donner une idée de base, je te laisse voir comment l'améliorer en chargeant et parsant du json par exemple )
Ça va permettre de mettre à jour la page. Maintenant, modifions un peu notre page de bataille ! On va d'abord devoir récupérer les valeurs (je considère ici que tout est dans la même page, mais si tu fais les choses proprement, c'est séparé ). On va d'abord ajouter simplement les points de vie.
Maintenant, on avance un petit peu : on veux les différentes actions possibles. Pour cela, rien de plus simple : il nous suffit d'ajouter un test sur l'état actuel du combat ! Et bien entendu, il nous faut savoir quel joueur nous sommes ; un simple test nous le dira.
Ok, notre page de combat est maintenant prête ! Il ne nous reste plus qu'à coder les pages d'attaque, d'esquive et pour passer. Commençons par la plus simple : la phase d'attaque. Ici, rien de bien difficile, on va simplement enregistrer la valeur d'attaque dans la ligne de base de données ; le but est d'éviter de diminuer les points de vie directement pour pouvoir réduire les dégâts avec l'esquive. Ça nous donne donc :
Voila pour l'attaque, dans sa forme la plus simple (et la moins sécurisée - voir mes commentaires !). Maintenant, l'esquive. Elle fonctionne presque pareil, si ce n'est qu'elle va infliger des dégâts :
Il ne nous reste enfin que la possibilité de ne rien faire. Là, un petit switch peut nous simplifier la vie. Note qu'il n'y a pas d'esquive si l'adversaire n'a pas attaqué :
Et voila ! Comme la partie concernée de la page va se recharger toute seule via ajax régulièrement, tu n'auras au final jamais d'affiché que ce qui doit l'être, mais le combat évoluera de lui-même. L'interval du setInterval déterminera la vitesse de rafraichissement (pas de push dans ce cas donc à toi de faire la part des choses entre la bande passante et le confort des joueurs !).
Note qu'une bonne partie de tout ce code (en particulier la gestion des dégats) gagnerait à être transféré dans une classe à part ; ce n'est que pour te donner une idée générale.
Donc, je vais partir sur un exemple en ajax tout simple, histoire d'éviter les websockets pour le moment (mais si besoin je te ferais ça ensuite).
Admettons que tu as une table battle qui ressemble à ça :
(int) battle_id
(int) player1
(int) player2
(int) hpPlayer1
(int) hpPlayer2
(int) incomingDamages
(enum) currentStep (PLAYER1_ATTACK, PLAYER2_AVOID, PLAYER2_ATTACK, PLAYER1_AVOID)
Au début du combat, tu créé dans cette table une ligne :
Code :
$table = new BattleTable;
$battleRow = $table->createRow();
$battleRow->player1 = $idOfPlayer1;
$battleRow->player2 = $idOfPlayer2;
$battleRow->hpPlayer1 = $initialHpOfPlayer1;
$battleRow->hpPlayer2 = $initialHpOfPlayer2;
$battleRow->currentStep = 'PLAYER1_ATTACK';
$battleRow->save();
$_SESSION['battleId'] = $battleRow->id;
Ensuite, tu lances le combat. Donc, tu vas avoir une page avec la vie des deux joueurs, quelque chose de ce genre :
Code :
<div id="battle">
Player 1's life : <span id="hpPlayer1">100</span><br />
Player 2's life : <span id="hpPlayer2">100</span><br />
<div class="action">
</div>
Histoire de faire simple, je vais réduire au maximum le code javascript. On va donc juste actualiser à intervalle régulier la bataille (c'est pas la manière la plus propre de faire, mais c'est pour te donner une idée de base, je te laisse voir comment l'améliorer en chargeant et parsant du json par exemple )
Code :
setInterval(function () {
$("#battle").load('battle.php');
}, 5000);
Ça va permettre de mettre à jour la page. Maintenant, modifions un peu notre page de bataille ! On va d'abord devoir récupérer les valeurs (je considère ici que tout est dans la même page, mais si tu fais les choses proprement, c'est séparé ). On va d'abord ajouter simplement les points de vie.
Code :
<?php
$table = new BattleTable;
$row = $table->findRowWhere('battle = ?', $_SESSION['battleId']);
?>
<div id="battle">
Player 1's life : <span id="hpPlayer1"><?php echo $row->hpPlayer1; ?></span><br />
Player 2's life : <span id="hpPlayer2"><?php echo $row->hpPlayer2; ?></span><br />
<div class="action">
</div>
Maintenant, on avance un petit peu : on veux les différentes actions possibles. Pour cela, rien de plus simple : il nous suffit d'ajouter un test sur l'état actuel du combat ! Et bien entendu, il nous faut savoir quel joueur nous sommes ; un simple test nous le dira.
Code :
<?php
$table = new BattleTable;
$row = $table->findRowWhere('battle = ?', $_SESSION['battleId']);
$isPlayer1 = $userId == $row->player1;
$canAttack = ($row->currentStep == 'PLAYER1_ATTACK' && $isPlayer1) || ($row->currentStep == 'PLAYER2_ATTACK' && $isPlayer2);
$canAvoid = ($row->currentStep == 'PLAYER1_AVOID' && $isPlayer1) || ($row->currentStep == 'PLAYER2_AVOID' && $isPlayer2);
?>
<div id="battle">
Player 1's life : <span id="hpPlayer1"><?php echo $row->hpPlayer1; ?></span><br />
Player 2's life : <span id="hpPlayer2"><?php echo $row->hpPlayer2; ?></span><br />
<div class="action">
<?php
if ($canAttack) {
?>
<a href='attack.php'>Attack</a>
<a href='pass.php'>Do nothing</a>
<?php
}
?>
<?php
if ($canAvoid) {
?>
<a href='avoid.php'>Avoid</a>
<a href='pass.php'>Do nothing</a>
<?php
}
?>
</div>
Ok, notre page de combat est maintenant prête ! Il ne nous reste plus qu'à coder les pages d'attaque, d'esquive et pour passer. Commençons par la plus simple : la phase d'attaque. Ici, rien de bien difficile, on va simplement enregistrer la valeur d'attaque dans la ligne de base de données ; le but est d'éviter de diminuer les points de vie directement pour pouvoir réduire les dégâts avec l'esquive. Ça nous donne donc :
Code :
$table = new BattleTable;
$row = $table->findRowWhere('battle = ?', $_SESSION['battleId']);
// Note : tu devrais probablement vérifier ici si c'est bien à nous de jouer !
$row->incomingDamages = $attackValue;
$row->currentStep = ($row->currentStep == 'PLAYER1_ATTACK' ? 'PLAYER2_AVOID' : 'PLAYER1_AVOID');
$row->save();
redirect('battle.php');
Voila pour l'attaque, dans sa forme la plus simple (et la moins sécurisée - voir mes commentaires !). Maintenant, l'esquive. Elle fonctionne presque pareil, si ce n'est qu'elle va infliger des dégâts :
Code :
$table = new BattleTable;
$row = $table->findRowWhere('battle = ?', $_SESSION['battleId']);
// A nouveau, il faudrait vérifier que c'est bien à nous de jouer !
$playerNumber = $row->player1 == $userId ? 1 : 2;
$otherPlayerNumber = $playerNumber == 1 ? 2 : 1;
$damagesToInflict = $row->incomingDamages - $avoidanceValue;
if ($damagesToInflict < 0)
$damagesToInflict = 0;
$columnToModify = 'hpPlayer' . $otherPlayerNumber;
$row->$columnToModify -= $damagesToInflict;
// Gérer la mort ici
$row->currentStep = "PLAYER{$otherPlayerNumber}_ATTACK";
$row->save();
redirect('battle.php');
Il ne nous reste enfin que la possibilité de ne rien faire. Là, un petit switch peut nous simplifier la vie. Note qu'il n'y a pas d'esquive si l'adversaire n'a pas attaqué :
Code :
$table = new BattleTable;
$row = $table->findRowWhere('battle = ?', $_SESSION['battleId']);
switch ($row->currentStep)
{
case 'PLAYER1_ATTACK':
$row->currentStep = 'PLAYER2_ATTACK';
break;
case 'PLAYER1_AVOID:
// Ici, on doit du coup infliger les dégâts
$row->hpPlayer1 -= $row->incomingDamage;
$row->currentStep = 'PLAYER2_ATTACK';
break;
case 'PLAYER2_ATTACK':
$row->currentStep = 'PLAYER1_ATTACK';
break;
case 'PLAYER2_AVOID':
$row->hpPlayer2 -= $row->incomingDamage;
$row->currentStep = 'PLAYER1_ATTACK';
break;
}
$row->save();
redirect('battle.php');
Et voila ! Comme la partie concernée de la page va se recharger toute seule via ajax régulièrement, tu n'auras au final jamais d'affiché que ce qui doit l'être, mais le combat évoluera de lui-même. L'interval du setInterval déterminera la vitesse de rafraichissement (pas de push dans ce cas donc à toi de faire la part des choses entre la bande passante et le confort des joueurs !).
Note qu'une bonne partie de tout ce code (en particulier la gestion des dégats) gagnerait à être transféré dans une classe à part ; ce n'est que pour te donner une idée générale.