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ácilConstruyamos un sistema de Desarrollo de personajes de juego en el que diferentes clases de personajes combatan usando habilidades únicas. Crearás una jerarquía de personajes con un sistema de experiencia y niveles, demostrando cómo funcionan conjuntamente la herencia, las interfaces, los traits y la encapsulación 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 garantiza que todas las habilidades puedan usarse de manera coherente, 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 dar formato coherente a sus mensajes de combate.Character.php: Incluye los archivos Ability y CombatLogger. Crea una clase abstractaCharacterque use el traitCombatLogger. Usa la promoción del constructor paraname(string, public readonly). Incluye propiedades privadas parahealth(int, comienza en 100),level(int, comienza en 1) yexperience(int, comienza 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 (restablece la XP a 0, aumenta el nivel y restaura 20 HP), y devuelve"[name] leveled up to [level]!"; de lo contrario, devuelve"[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 y usalogAction()para devolver"[COMBAT] [name] attacks [target name] for 10 damage"
Warrior.php: Incluye el archivo Character. Crea una claseWarriorque extiendaCharacter. 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 extiendaCharacter. 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 los personajes:
[{"type": "warrior", "name": "Thorin"}, {"type": "mage", "name": "Gandalf"}]Formato JSON de las 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 guárdalos en un array (índices 0, 1, etc.). Procesa cada acción:
"attack": el personaje en el índice attacker ataca al objetivo; imprime el resultado"special": el personaje usa su habilidad especial contra el objetivo; imprime el resultado"xp": el personaje gana experiencia; imprime el resultado"heal": el personaje se cura la cantidad indicada; imprime"[name] healed to [health] HP""status": imprime"[name] - Level [level], HP: [health], Alive: [Yes/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 garantizan que las habilidades sigan un contrato coherente, los traits proporcionan una funcionalidad de registro reutilizable y las clases anónimas crean implementaciones de habilidades únicas sin llenar tu base de código de 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: Crea un array para almacenar objetos de personajes
$characters = [];
// TODO: Recorre $charactersData y crea objetos Warrior o Mage
// basándote en el campo "type", almacénalos en el array $characters
// TODO: Procesa cada acción en $actionsData
// Maneja estos tipos de acción:
// - "attack": El personaje en el índice del atacante ataca al objetivo; imprime el resultado
// - "special": El personaje usa getSpecialAbility()->use() en el objetivo; imprime el resultado
// - "xp": El personaje gana experiencia; imprime el resultado
// - "heal": El personaje se cura; imprime "[name] healed to [health] HP"
// - "status": Imprime "[name] - Level [level], HP: [health], Alive: [Yes/No]"
?>Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de la POO
Archivos externosIntroducción a la POOClases frente a objetosLa palabra clave $thisMétodosPropiedadesConstructor (__construct)Destructor (__destruct)Repaso: calculadora simple4Herencia
Herencia básicaLa palabra clave parent::Sobrescritura de métodosLa palabra clave finalClases abstractasRepaso - Jerarquía de empleados7Encapsulación
Público, protegido, privadoModificadores de acceso en profundidadGetters y settersOcultación de la informaciónPromoción del constructor (8.0)Repaso: sistema de registros de estudiantes10Conceptos avanzados de OOP
Composición vs. herenciaInyección de dependenciasClases anónimasEnums (PHP 8.1)Fibras (PHP 8.1)Análisis profundo de la clonación de objetosGeneradores e iteradores13Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository2Namespaces y carga automática
Introducción a los NamespacesLa palabra clave useEstándar de carga automática PSR-4Autoloader de ComposerRepaso: proyecto organizado5Interfaces y contratos
Introducción a las interfacesImplementación de interfacesImplementación de múltiples interfacesInterfaces vs. clase abstractaTipado con interfacesRepaso - 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 __unserializeRepaso: 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)Repaso: gestor de cuentas bancarias6Polimorfismo
Repaso de la sobrescritura de métodosPolimorfismo mediante interfacesAnotaciones de tipo y tipos uniónEnlace estático tardíoRepaso: procesador de pagos9Traits
Introducción a los TraitsUso de múltiples TraitsResolución de conflictos entre TraitsMétodos abstractos en TraitsTraits frente a la 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 aprendizaje electrónicoSistema bancarioDesarrollo de personajes de videojuegosServicio de alquiler de vehículosPractica por tu cuenta: Compilador de PHP online