Menu
Coddy logo textTech

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.

challenge icon

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 base Character con campos comunes: Name (string), Health (int) y MaxHealth (int). Incluye un constructor NewCharacter y métodos:
    • IsAlive() bool: devuelve true si la salud es mayor que 0
    • Status() string: devuelve el formato: [Name]: [Health]/[MaxHealth] HP
  • interfaces.go: Define las interfaces de combate que permiten el polimorfismo:
    • La interfaz Attacker con Attack() int: devuelve el daño infligido
    • La interfaz Defender con TakeDamage(damage int) int: aplica la reducción de daño y devuelve el daño recibido real
    • La interfaz Ability con Use() string: devuelve una descripción del efecto de la habilidad
  • characters.go: Crea tres tipos de personajes que incrusten Character e implementen tanto Attacker como Defender:

    Warrior: tiene los campos Strength (int) y Armor (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 campos Intelligence (int) y MagicResist (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 campos Agility (int) y Evasion (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, NewMage y NewArcher, 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 FireSpell con Power (int). Su Use() devuelve: Casts fireball for [Power] damage

    Struct IceSpell con Power (int). Su Use() devuelve: Casts ice shard for [Power] damage

    Struct PowerStrike con Multiplier (int). Su Use() devuelve: Performs power strike at [Multiplier]x damage

    Añade un campo ability (de tipo Ability) al struct Mage, con los métodos SetAbility(a Ability) y UseAbility() string. UseAbility devuelve No ability set si ability es nil.

  • main.go: Crea personajes y muestra las mecánicas de combate.

    Lee el tipo de personaje (warrior, mage o archer); 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 personaje
    • attack: imprime [Name] attacks for [damage] damage
    • defend [amount]: aplica el daño e imprime [Name] takes [actual] damage
    • setability [type] [power]: solo para magos, establece la habilidad (type es fire, ice o strike)
    • 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 100

Tu salida debería ser:

Thorin: 100/100 HP
Thorin attacks for 15 damage
Thorin takes 12 damage
Thorin: 88/100 HP
Thorin takes 92 damage

Y dado:

mage
Gandalf
80
25
10
6
attack
useability
setability fire 30
useability
setability ice 25
useability
defend 40

Tu 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 damage

Y dado:

archer
Legolas
90
18
15
4
status
attack
defend 24
status

Tu salida debería ser:

Legolas: 90/90 HP
Legolas attacks for 23 damage
Legolas takes 18 damage
Legolas: 72/90 HP

Observa 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

Practica por tu cuenta: Compilador de Go online