Sistema de personajes de juego
Parte de la sección Programación Orientada a Objetos del Journey de GO de Coddy. Lección 107 de 107.
Desafío
Fácil¡Construyamos un sistema de personajes de juego que combine la incrustación de structs, las interfaces y el patrón Strategy para crear mecánicas de combate flexibles! Diseñarás distintos tipos de personajes que podrán atacar y defenderse de maneras únicas, con habilidades que se pueden intercambiar durante la ejecución.
Organizarás tu código en cinco archivos:
character.go: Define un struct baseCharactercon campos comunes:Name(string),Health(int) yMaxHealth(int). Incluye un constructorNewCharactery métodos:IsAlive() bool: devuelve true si la salud es mayor que 0Status() string: devuelve el formato:[Name]: [Health]/[MaxHealth] HP
interfaces.go: Define las interfaces de combate que permiten el polimorfismo:- La interfaz
AttackerconAttack() int: devuelve el daño infligido - La interfaz
DefenderconTakeDamage(damage int) int: aplica la reducción de daño y devuelve el daño recibido real - La interfaz
AbilityconUse() string: devuelve una descripción del efecto de la habilidad
- La interfaz
characters.go: Crea tres tipos de personajes que incrustenCharactere implementen tantoAttackercomoDefender:Warrior: tiene los camposStrength(int) yArmor(int). Attack devuelve Strength como daño. TakeDamage reduce el daño recibido en función de Armor (se recibe un daño mínimo de 1).Mage: tiene los camposIntelligence(int) yMagicResist(int). Attack devuelve Intelligence * 2 como daño. TakeDamage reduce el daño recibido en función de MagicResist / 2 (se recibe un daño mínimo de 1).Archer: tiene los camposAgility(int) yEvasion(int). Attack devuelve Agility + 5 como daño. TakeDamage: si Evasion > 10, reduce el daño en un 25 % (división entera); de lo contrario, recibe el daño completo (se recibe un daño mínimo de 1).Incluye constructores para cada uno:
NewWarrior,NewMageyNewArcher, que reciban el nombre, la salud y los valores de sus estadísticas específicas.abilities.go: Implementa el patrón Strategy con habilidades intercambiables:Struct
FireSpellconPower(int). SuUse()devuelve:Casts fireball for [Power] damageStruct
IceSpellconPower(int). SuUse()devuelve:Casts ice shard for [Power] damageStruct
PowerStrikeconMultiplier(int). SuUse()devuelve:Performs power strike at [Multiplier]x damageAñade un campo
ability(de tipoAbility) al struct Mage, con los métodosSetAbility(a Ability)yUseAbility() string. UseAbility devuelveNo ability setsi ability es nil.main.go: Crea personajes y muestra las mecánicas de combate.Lee el tipo de personaje (
warrior,mageoarcher); después, lee el nombre, la salud y las estadísticas específicas del tipo de personaje. Crea el personaje correspondiente.Después, lee el número de acciones. Cada acción es una de las siguientes:
status: imprime el estado del personajeattack: imprime[Name] attacks for [damage] damagedefend [amount]: aplica el daño e imprime[Name] takes [actual] damagesetability [type] [power]: solo para magos, establece la habilidad (type esfire,iceostrike)useability: solo para magos, imprime el resultado de Use() de la habilidad
Se proporcionarán las siguientes entradas:
- Tipo de personaje, nombre, salud y estadísticas específicas del tipo
- Número de acciones y, después, cada acción en una línea separada
Por ejemplo, dado:
warrior
Thorin
100
15
8
5
status
attack
defend 20
status
defend 100Tu salida debería ser:
Thorin: 100/100 HP
Thorin attacks for 15 damage
Thorin takes 12 damage
Thorin: 88/100 HP
Thorin takes 92 damageY dado:
mage
Gandalf
80
25
10
6
attack
useability
setability fire 30
useability
setability ice 25
useability
defend 40Tu salida debería ser:
Gandalf attacks for 50 damage
No ability set
Casts fireball for 30 damage
Casts ice shard for 25 damage
Gandalf takes 35 damageY dado:
archer
Legolas
90
18
15
4
status
attack
defend 24
statusTu salida debería ser:
Legolas: 90/90 HP
Legolas attacks for 23 damage
Legolas takes 18 damage
Legolas: 72/90 HPObserva cómo la incrustación de structs permite que cada tipo de personaje comparta los campos y métodos del Character base, mientras que las interfaces permiten un combate polimórfico en el que cualquier Attacker puede infligir daño y cualquier Defender puede recibirlo. ¡El patrón Strategy destaca con las habilidades intercambiables del Mage: el mismo personaje puede usar distintos hechizos sin cambiar su implementación principal!
Pruébalo tú mismo
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Leer tipo de personaje
scanner.Scan()
charType := strings.TrimSpace(scanner.Text())
// Leer nombre del personaje
scanner.Scan()
name := strings.TrimSpace(scanner.Text())
// Leer salud
scanner.Scan()
health, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// Leer primera estadística específica del tipo
scanner.Scan()
stat1, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// Leer segunda estadística específica del tipo
scanner.Scan()
stat2, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// TODO: Crear el personaje apropiado basándose en charType
// Usar las variables: charType, name, health, stat1, stat2
// Para warrior: stat1 = Strength, stat2 = Armor
// Para mage: stat1 = Intelligence, stat2 = MagicResist
// Para archer: stat1 = Agility, stat2 = Evasion
// Leer el número de acciones
scanner.Scan()
numActions, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// Procesar cada acción
for i := 0; i < numActions; i++ {
scanner.Scan()
line := strings.TrimSpace(scanner.Text())
parts := strings.Fields(line)
action := parts[0]
// TODO: Maneja cada tipo de acción:
// - "status": imprime el Status() del personaje
// - "attack": imprime "[Name] attacks for [damage] damage"
// - "defend [amount]": aplica el daño e imprime "[Name] takes [actual] damage"
// - "setability [type] [power]": para magos, establece la habilidad (fire, ice, or strike)
// - "useability": para magos, imprime el resultado de UseAbility()
_ = action // Elimina esta línea al implementar
_ = fmt.Println // Elimina esta línea al implementar
}
}
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de POO en Go
Archivos externosEspacio de trabajo y módulos de GoPaquetes e importacionesNombres exportados vs. no exportadosIntroducción a la POO en GoStructs como clasesDefinición de métodos en structsReceptores de puntero vs. de valorInicialización de structsFunciones constructorasResumen - Calculadora simple4Interfaces
Introducción a las interfacesImplementación implícitaLa interfaz como contratoInterfaz vacía (any)Type AssertionType SwitchComposición de interfacesInterfaces Stringer y ErrorResumen: Calculadora de figuras7Encapsulamiento
Campos exportados vs. no exportadosEncapsulamiento a nivel de paqueteMétodos Getter y SetterOcultamiento de información en GoResumen - Registros de estudiantes10Genéricos (Go 1.18+)
Introducción a los GenéricosParámetros de tipoRestricciones de tipoStructs genéricosSolución alternativa para métodos genéricosResumen - Colección genérica13Patrones de diseño - Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón Abstract FactoryPatrón ObserverPatrón Strategy2Inmersión profunda en Tipos y Structs
Tipos básicos y compuestosDefiniciones de tipos personalizadosEtiquetas de StructsStructs anónimosStructs anidadosValores cero y por defectoRepaso - Libreta de contactos5Composición sobre herencia
Por qué Go no tiene herenciaConceptos básicos de incrustación de structsPromoción de métodosIncrustación de múltiples structsIncrustación vs AgregaciónShadowing de métodos incrustadosResumen - Jerarquía de empleados8Manejo de Errores y OOP
La interfaz errorTipos de errores personalizadosEnvoltura de errores (fmt.Errorf)Errores centinelaerrors.Is() y errors.As()Panic, Defer y RecoverResumen - Analizador de archivos3Punteros y Memoria
Fundamentos de punteros en GoPunteros a StructsPaso por valor vs referenciaLa función new()Garbage Collection en GoResumen - Constructor de Linked List6Polimorfismo en Go
Polimorfismo mediante interfacesDuck Typing en GoReglas de satisfacción de interfacesColecciones polimórficasInyección de dependenciasResumen - Procesador de pagos9Concurrencia y POO
Fundamentos de GoroutinesChannels y comunicaciónChannels con buffer vs. sin bufferSentencia Selectsync.Mutex y sync.RWMutexsync.WaitGroupDiseño de estructuras Thread-SafeResumen - Worker PoolPractica por tu cuenta: Compilador de Go online