Login to bookmark this video
Buy Access to Course
04.

Implementar más acciones

|

Share this awesome video!

|

¡Muy bien! Estamos listos para añadir más acciones a nuestro juego y permitir que los jugadores elijan sus acciones.

Primero, necesitamos crear una interfaz para nuestros comandos. Para ello, dentro del directorio ActionCommand, vamos a crear un nuevo archivo PHP y lo llamaremos ActionCommandInterface. Dentro, añadiremos un único método llamado execute() sin argumentos.

// ... lines 1 - 4
interface ActionCommandInterface
{
public function execute(): void;
}

¡Interfaz terminada! A continuación, abramos AttackCommand y hagamos que implemente ActionCommandInterface. El método execute() ya está implementado aquí, así que ya está listo. ¡Qué bien!

Si te has descargado el código del curso, podemos ahorrarnos algo de tiempo cogiendo el resto de acciones que necesitamos en nuestro directorio tutorial en la raíz de nuestro proyecto. Copia los archivos HealCommand y SurrenderCommand en el directorio ActionCommand.

Vamos a comprobarlos. Dentro de HealCommand, podemos ver que tiene un constructor que sólo se preocupa del objeto jugador.

29 lines | src/ActionCommand/HealCommand.php
// ... lines 1 - 4
use App\Character\Character;
// ... lines 6 - 8
class HealCommand implements ActionCommandInterface
{
public function __construct(private readonly Character $player)
{
}
// ... lines 14 - 28
}

Y en el método execute(), tenemos algo de código que calcula cuánto daño se curará el jugador, y luego ajusta la salud del jugador a la nueva cantidad (sin exceder su salud máxima). Por último, imprime un mensaje en la pantalla.

29 lines | src/ActionCommand/HealCommand.php
// ... lines 1 - 14
public function execute(): void
{
$healAmount = Dice::roll(20) + $this->player->getLevel() * 3;
$newAmount = $this->player->getCurrentHealth() + $healAmount;
$newAmount = min($newAmount, $this->player->getMaxHealth());
$this->player->setHealth($newAmount);
$this->player->setStamina(Character::MAX_STAMINA);
GameApplication::$printer->writeln(sprintf(
'You healed %d damage',
$healAmount
));
}

Si echamos un vistazo a SurrenderCommand, el constructor aquí es el mismo que el de HealCommand - sólo se preocupa del objeto jugador. Y en el método execute(), he hecho un poco de trampa porque no hay una forma adecuada de terminar una batalla, así que me he limitado a poner la salud del jugador en 0. Genial, ¿verdad?

21 lines | src/ActionCommand/SurrenderCommand.php
// ... lines 1 - 4
use App\Character\Character;
use App\GameApplication;
class SurrenderCommand implements ActionCommandInterface
{
public function __construct(private readonly Character $player)
{
}
public function execute(): void
{
$this->player->setHealth(0);
GameApplication::$printer->block('You\'ve surrendered! Better luck next time!');
}
}

Pedir al jugador que elija una acción

¡Muy bien! ¡Es hora de pedir al jugador que elija una acción! Antes cerraré algunos archivos. Bien, vuelve a GameApplication... y justo antes de definir $playerAction, escribe $actionChoice y ponlo en GameApplication::$printer->choice(), donde la pregunta es Your Turn, y las opciones son Attack, Heal y Surrender.

200 lines | src/GameApplication.php
// ... lines 1 - 12
class GameApplication
{
// ... lines 15 - 26
public function play(Character $player, Character $ai, FightResultSet $fightResultSet): void
{
while (true) {
// ... lines 30 - 35
// Player's turn
$actionChoice = GameApplication::$printer->choice('Your turn', [
'Attack',
'Heal',
'Surrender',
]);
// ... lines 42 - 66
}
}
// ... lines 69 - 198
}

A continuación, sustituiremos la instanciación AttackCommand por una expresión match, pero cópiala primero, porque la necesitaremos dentro de un momento. Ahora escribe match ($actionChoice). Dentro, el primer caso que queremos añadir es Attack, y ahora... pega. Para el segundo caso, escribe Heal y ponlo en new HealCommand($player). El tercer y último caso es Surrender, y lo pondremos en new SurrenderCommand($player). ¡Perfecto!

200 lines | src/GameApplication.php
// ... lines 1 - 26
public function play(Character $player, Character $ai, FightResultSet $fightResultSet): void
{
while (true) {
// ... lines 30 - 42
$playerAction = match ($actionChoice) {
'Attack' => new AttackCommand($player, $ai, $fightResultSet),
'Heal' => new HealCommand($player),
'Surrender' => new SurrenderCommand($player),
};
// ... lines 48 - 66
}
}
// ... lines 69 - 200

Vamos a probarlo. Gira hasta tu terminal y ejecuta:

php bin/console app:game:play

Esta vez, seré un "mago arquero", y... ¡mira eso! ¡Nos pregunta qué hacer! Ataquemos primero, y... ¡genial! Hicimos 12 puntos de daño y recibimos 10, así que nuestra salud actual es 40 de 50. Intentemos curarnos a continuación. Y... ¡fíjate! Curamos 8 puntos, y la IA hizo 0 puntos de daño porque bloqueamos su ataque, así que nuestra salud actual es 48. ¡La acción "curar" funciona como se esperaba! Por último, intentemos rendirnos. Elige la opción 2 y... ¡fantástico! Nos rendimos y perdemos la partida. Rendirse no es algo que normalmente celebraríamos, pero en este caso, significa que nuestra acción "rendirse" está funcionando como se supone que debe hacerlo.

¡Choca esos cinco con tu patito de goma porque hemos conseguido que nuestro juego sea más interactivo! Pero... ¿no sería genial poder deshacer nuestra última acción si, digamos... la IA tuviera un poco de suerte? ¡Eso a continuación!