Menu
Coddy logo textTech

Система игровых персонажей

Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy. Урок 107 из 107.

challenge icon

Задание

Легко

Давайте создадим систему игровых персонажей, объединяющую встраивание структур, интерфейсы и паттерн Strategy для создания гибкой боевой механики! Вы спроектируете разные типы персонажей, которые смогут уникальным образом атаковать и защищаться, а их способности можно будет заменять во время выполнения программы.

Вы организуете код в пяти файлах:

  • character.go: определите базовую структуру Character с общими полями: Name (string), Health (int) и MaxHealth (int). Добавьте конструктор NewCharacter и методы:
    • IsAlive() bool: возвращает true, если здоровье больше 0
    • Status() string: возвращает формат: [Name]: [Health]/[MaxHealth] HP
  • interfaces.go: определите боевые интерфейсы, обеспечивающие полиморфизм:
    • интерфейс Attacker с методом Attack() int: возвращает нанесённый урон
    • интерфейс Defender с методом TakeDamage(damage int) int: применяет уменьшение урона и возвращает фактически полученный урон
    • интерфейс Ability с методом Use() string: возвращает описание эффекта способности
  • characters.go: создайте три типа персонажей, которые встраивают Character и реализуют оба интерфейса — Attacker и Defender:

    Warrior: имеет поля Strength (int) и Armor (int). Attack возвращает Strength в качестве урона. TakeDamage уменьшает входящий урон на значение Armor (минимальный полученный урон — 1).

    Mage: имеет поля Intelligence (int) и MagicResist (int). Attack возвращает Intelligence * 2 в качестве урона. TakeDamage уменьшает входящий урон на MagicResist / 2 (минимальный полученный урон — 1).

    Archer: имеет поля Agility (int) и Evasion (int). Attack возвращает Agility + 5 в качестве урона. TakeDamage: если Evasion > 10, уменьшает урон на 25% (с целочисленным делением), иначе персонаж получает полный урон (минимальный полученный урон — 1).

    Добавьте конструкторы для каждого типа: NewWarrior, NewMage, NewArcher, принимающие имя, здоровье и значения специфичных для типа характеристик.

  • abilities.go: реализуйте паттерн Strategy со сменными способностями:

    структура FireSpell с полем Power (int). Её метод Use() возвращает: Casts fireball for [Power] damage

    структура IceSpell с полем Power (int). Её метод Use() возвращает: Casts ice shard for [Power] damage

    структура PowerStrike с полем Multiplier (int). Её метод Use() возвращает: Performs power strike at [Multiplier]x damage

    Добавьте в структуру Mage поле ability типа Ability, а также методы SetAbility(a Ability) и UseAbility() string. UseAbility возвращает No ability set, если ability равно nil.

  • main.go: создайте персонажей и продемонстрируйте боевую механику.

    Сначала прочитайте тип персонажа (warrior, mage или archer), затем имя персонажа, здоровье и специфичные для типа характеристики. Создайте соответствующего персонажа.

    Затем прочитайте количество действий. Каждое действие является одной из следующих команд:

    • status: выведите статус персонажа
    • attack: выведите [Name] attacks for [damage] damage
    • defend [amount]: примените урон и выведите [Name] takes [actual] damage
    • setability [type] [power]: только для магов — установите способность (type — это fire, ice или strike)
    • useability: только для магов — выведите результат Use() способности

Будут предоставлены следующие входные данные:

  • Тип персонажа, имя, здоровье и специфичные для типа характеристики
  • Количество действий, затем каждое действие в отдельной строке

Например, для следующих данных:

warrior
Thorin
100
15
8
5
status
attack
defend 20
status
defend 100

Ваш вывод должен быть следующим:

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

А для следующих данных:

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

Ваш вывод должен быть следующим:

Gandalf attacks for 50 damage
No ability set
Casts fireball for 30 damage
Casts ice shard for 25 damage
Gandalf takes 35 damage

А для следующих данных:

archer
Legolas
90
18
15
4
status
attack
defend 24
status

Ваш вывод должен быть следующим:

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

Обратите внимание, как встраивание структур позволяет каждому типу персонажа совместно использовать базовые поля и методы Character, а интерфейсы обеспечивают полиморфный бой, в котором любой Attacker может наносить урон, а любой Defender — получать его. Паттерн Strategy особенно хорошо проявляет себя в сменных способностях Mage: один и тот же персонаж может использовать разные заклинания без изменения своей основной реализации!

Попробуйте сами

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)

	// Прочитать тип персонажа
	scanner.Scan()
	charType := strings.TrimSpace(scanner.Text())

	// Прочитать имя персонажа
	scanner.Scan()
	name := strings.TrimSpace(scanner.Text())

	// Прочитать здоровье
	scanner.Scan()
	health, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))

	// Прочитать первую характеристику, специфичную для типа
	scanner.Scan()
	stat1, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))

	// Прочитать вторую характеристику, специфичную для типа
	scanner.Scan()
	stat2, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))

	// TODO: Создать соответствующего персонажа на основе charType
	// Использовать переменные: charType, name, health, stat1, stat2
	// Для warrior: stat1 = Strength, stat2 = Armor
	// Для mage: stat1 = Intelligence, stat2 = MagicResist
	// Для archer: stat1 = Agility, stat2 = Evasion

	// Прочитать количество действий
	scanner.Scan()
	numActions, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))

	// Обработать каждое действие
	for i := 0; i < numActions; i++ {
		scanner.Scan()
		line := strings.TrimSpace(scanner.Text())
		parts := strings.Fields(line)
		action := parts[0]

		// TODO: Обработать каждый тип действия:
		// - "status": вывести Status() персонажа
		// - "attack": вывести "[Name] attacks for [damage] damage"
		// - "defend [amount]": применить урон и вывести "[Name] takes [actual] damage"
		// - "setability [type] [power]": для магов установить способность (fire, ice или strike)
		// - "useability": для магов вывести результат UseAbility()

		_ = action // Удалить эту строку при реализации
		_ = fmt.Println // Удалить эту строку при реализации
	}
}

Все уроки раздела Объектно-ориентированное программирование

16Финальные испытания

Платформа онлайн-обученияБанковская системаСистема игровых персонажей

Потренируйтесь самостоятельно: Онлайн-компилятор Go