Desarrollo de personajes de videojuegos
Parte de la sección Programación Orientada a Objetos del Journey de PHP de Coddy — lección 90 de 91.
Desafío
FácilVamos a construir un sistema de Desarrollo de Personajes de Juego donde diferentes clases de personajes luchan usando habilidades únicas. Crearás una jerarquía de personajes con un sistema de experiencia y niveles, demostrando cómo la herencia, las interfaces, los traits y el encapsulamiento trabajan juntos en el contexto de un juego.
Organizarás tu código en seis archivos:
Ability.php— Define una interfazAbilitycon dos métodos:getName(): stringyuse(Character $target): string. Este contrato asegura que todas las habilidades puedan usarse de manera consistente independientemente de sus efectos específicos.CombatLogger.php— Crea un traitCombatLoggerque proporcione un métodologAction(string $action): string. Este método debe devolver la cadena de acción con el prefijo"[COMBAT] ". Los personajes usarán este trait para formatear sus mensajes de combate de manera consistente.Character.php— Incluye los archivos Ability y CombatLogger. Crea una clase abstractaCharacterque use el traitCombatLogger. Usa la promoción de constructor paraname(string, public readonly). Incluye propiedades privadas parahealth(int, comenzando en 100),level(int, comenzando en 1) yexperience(int, comenzando en 0). Implementa:getHealth(): intygetLevel(): int— getters para las propiedades privadastakeDamage(int $amount): void— reduce la salud pero nunca por debajo de 0heal(int $amount): void— aumenta la salud pero nunca por encima de 100gainExperience(int $xp): string— añade XP; si la experiencia llega a 100 o más, sube de nivel (reinicia XP a 0, aumenta el nivel, cura 20 HP), devuelve"{$this->name} leveled up to {$this->level}!"; de lo contrario, devuelve"{$this->name} gained {$xp} XP"isAlive(): bool— devuelve true si la salud es mayor que 0abstract getSpecialAbility(): Ability— cada tipo de personaje proporciona su habilidad únicaattack(Character $target): string— inflige 10 de daño al objetivo, usalogAction()para devolver"[COMBAT] {$this->name} attacks {$target->name} for 10 damage"
Warrior.php— Incluye el archivo Character. Crea una claseWarriorque extienda deCharacter. ImplementagetSpecialAbility()para devolver una clase anónima que implementeAbility:getName()devuelve"Shield Bash"use()inflige 25 de daño y devuelve"[COMBAT] Shield Bash hits {$target->name} for 25 damage!"(usa ellogAction()del trait)
Mage.php— Incluye el archivo Character. Crea una claseMageque extienda deCharacter. ImplementagetSpecialAbility()para devolver una clase anónima que implementeAbility:getName()devuelve"Fireball"use()inflige 35 de daño y devuelve"[COMBAT] Fireball engulfs {$target->name} for 35 damage!"
main.php— Incluye los archivos Warrior y Mage. Recibirás dos entradas: datos de personajes (JSON) y una secuencia de acciones de combate (JSON).Formato JSON de personajes:
[{"type": "warrior", "name": "Thorin"}, {"type": "mage", "name": "Gandalf"}]Formato JSON de acciones:
[{"action": "attack", "attacker": 0, "target": 1}, {"action": "special", "attacker": 1, "target": 0}, {"action": "xp", "character": 0, "amount": 100}, {"action": "status", "character": 0}]Crea todos los personajes y almacénalos en un array (índice 0, 1, etc.). Procesa cada acción:
"attack"— El personaje en el índice atacante ataca al objetivo; imprime el resultado"special"— El personaje usa su habilidad especial sobre el objetivo; imprime el resultado"xp"— El personaje gana experiencia; imprime el resultado"heal"— El personaje se cura por la cantidad dada; imprime"{$character->name} healed to {$character->getHealth()} HP""status"— Imprime"{$character->name} - Level {$character->getLevel()}, HP: {$character->getHealth()}, Alive: {$alive}"(donde$alivees'Yes'o'No')
Imprime cada resultado en una línea nueva.
Este sistema demuestra cómo las clases abstractas definen el comportamiento compartido de los personajes, las interfaces aseguran que las habilidades sigan un contrato consistente, los traits proporcionan funcionalidad de registro reutilizable y las clases anónimas crean implementaciones de habilidades únicas sin saturar tu base de código con clases de un solo uso.
Pruébalo tú mismo
<?php
require_once 'Warrior.php';
require_once 'Mage.php';
// Leer la entrada
$charactersJson = trim(fgets(STDIN));
$actionsJson = trim(fgets(STDIN));
// Analizar las entradas JSON
$charactersData = (array)json_decode($charactersJson, true);
$actionsData = (array)json_decode($actionsJson, true);
// TODO: Crear un array para almacenar los objetos de los personajes
$characters = [];
// TODO: Recorrer $charactersData y crear objetos Warrior o Mage
// basándose en el campo "type", almacenarlos en el array $characters
// TODO: Procesar cada acción en $actionsData
// Manejar estos tipos de acciones:
// - "attack": El personaje en el índice del atacante ataca al objetivo; imprimir resultado
// - "special": El personaje usa getSpecialAbility()->use() en el objetivo; imprimir resultado
// - "xp": El personaje gana experiencia; imprimir resultado
// - "heal": El personaje se cura; imprimir "[name] healed to [health] HP"
// - "status": Imprimir "[name] - Level [level], HP: [health], Alive: [Yes/No]"
?>Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosIntroducción a OOPClases vs ObjetosLa palabra clave $thisMétodosPropiedadesConstructor (__construct)Destructor (__destruct)Resumen - Calculadora simple4Herencia
Herencia básicaLa palabra clave parent::Sobrescritura de métodosLa palabra clave finalClases abstractasResumen - Jerarquía de empleados7Encapsulamiento
Público, Protegido, PrivadoModificadores de acceso a fondoGetters y SettersOcultamiento de informaciónPromoción de constructor (8.0)Resumen - Sistema de registros de estudiantes10Conceptos avanzados de POO
Composición vs. HerenciaInyección de dependenciasClases anónimasEnums (PHP 8.1)Fibers (PHP 8.1)Clonación de objetos a fondoGeneradores e Iteradores13Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository2Espacios de nombres y Autoloading
Introducción a los espacios de nombresLa palabra clave useEstándar de Autoloading PSR-4Autoloader de ComposerResumen - Proyecto organizado5Interfaces y Contratos
Introducción a las InterfacesImplementación de InterfacesImplementación de Múltiples InterfacesInterfaz vs Clase AbstractaType Hinting con InterfacesResumen - Calculadora de Formas8Métodos mágicos
Introducción a los métodos mágicos__toString y __debugInfo__get, __set, __isset, __unset__call y __callStatic__clone y clonación de objetos__serialize y __unserializeResumen - Colección personalizada3Propiedades de clase
Propiedades de instancia vs. estáticasConstantes en clasesMétodos y propiedades estáticosPropiedades privadas y protegidasPropiedades de solo lectura (PHP 8.1)Resumen - Gestor de cuenta bancaria6Polimorfismo
Sobrescritura de métodos revisadaPolimorfismo mediante interfacesType Hinting y tipos de uniónEnlace estático tardíoResumen - Procesador de pagos9Traits
Introducción a los TraitsUso de múltiples TraitsResolución de conflictos de TraitsMétodos abstractos en TraitsTraits frente a herencia12Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy15Desafíos finales
Plataforma de E-LearningSistema bancarioDesarrollo de personajes de videojuegosServicio de alquiler de vehículos