Система игровых персонажей
Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy — урок 107 из 107.
Задание
ЛегкоДавайте создадим систему игровых персонажей, которая объединяет встраивание структур, интерфейсы и паттерн «Стратегия» для создания гибкой механики боя! Вы разработаете различные типы персонажей, которые могут атаковать и защищаться уникальными способами, а также способности, которые можно менять во время выполнения программы.
Вы организуете свой код в пяти файлах:
character.go: Определите базовую структуруCharacterс общими полями:Name(string),Health(int) иMaxHealth(int). Включите конструкторNewCharacterи методы:IsAlive() bool— возвращает true, если здоровье больше 0Status() 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: Реализуйте паттерн «Стратегия» со сменными способностями:Структура
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Добавьте поле
ability(типаAbility) в структуру Mage, а также методыSetAbility(a Ability)иUseAbility() string. UseAbility возвращаетNo ability set, если способность не установлена (nil).main.go: Создайте персонажей и продемонстрируйте механику боя.Считайте тип персонажа (
warrior,mageилиarcher), затем считайте имя персонажа, здоровье и специфические для типа характеристики. Создайте соответствующего персонажа.Затем считайте количество действий. Каждое действие представляет собой одно из следующих:
status— вывести статус персонажаattack— вывести[Name] attacks for [damage] damagedefend [amount]— применить урон и вывести[Name] takes [actual] damagesetability [type] [power]— только для магов, установить способность (тип: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 — получать его. Паттерн «Стратегия» отлично проявляет себя в сменных способностях мага — один и тот же персонаж может использовать разные заклинания без изменения своей основной реализации!
Попробуйте сами
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 // Удалите эту строку при реализации
}
}
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП в Go
Внешние файлыРабочее пространство и модули GoПакеты и импортыЭкспортируемые и неэкспортируемые именаВведение в ООП в GoСтруктуры как классыОпределение методов структурПолучатели-указатели и получатели-значенияИнициализация структурФункции-конструкторыИтоги — Простой калькулятор4Интерфейсы
Введение в интерфейсыНеявная реализацияИнтерфейс как контрактПустой интерфейс (any)Утверждение типаПереключатель типовКомпозиция интерфейсовИнтерфейсы Stringer и ErrorПовторение: Калькулятор фигур7Инкапсуляция
Экспортируемые и неэкспортируемые поляИнкапсуляция на уровне пакетовГеттеры и сеттерыСокрытие информации в GoИтоги — Записи о студентах10Обобщения (Generics) (Go 1.18+)
Введение в GenericsПараметры типовОграничения типовОбобщенные структурыОбходной путь для обобщенных методовИтоги — Обобщенная коллекция13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн Abstract FactoryПаттерн ObserverПаттерн Strategy2Глубокое погружение в типы и структуры
Базовые и составные типыОпределение пользовательских типовТеги структурАнонимные структурыВложенные структурыНулевые значения и значения по умолчаниюПовторение — Контактная книга5Композиция вместо наследования
Почему в Go нет наследованияОсновы встраивания структурПродвижение методовВстраивание нескольких структурВстраивание против агрегацииЗатенение встроенных методовИтоги — Иерархия сотрудников8Обработка ошибок и ООП
Интерфейс errorПользовательские типы ошибокОбертывание ошибок (fmt.Errorf)Sentinel-ошибкиerrors.Is() и errors.As()Panic, Defer и RecoverИтоги — Парсер файлов11Стандартная библиотека и ООП
io.Reader и io.Writersort.InterfaceИнтерфейс fmt.Stringerencoding/json со структурамиИнтерфейс http.HandlerПовторение: модели REST API14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикMiddleware как Декоратор3Указатели и память
Основы указателей в GoУказатели на структурыПередача по значению и по ссылкеФункция new()Сборка мусора в GoПовторение: Конструктор связного списка6Полиморфизм в Go
Полиморфизм через интерфейсыУтиная типизация в GoПравила реализации интерфейсовПолиморфные коллекцииВнедрение зависимостейИтоги — Обработчик платежей9Конкурентность и ООП
Основы горутинКаналы и взаимодействиеБуферизованные и небуферизованные каналыОператор selectsync.Mutex и sync.RWMutexsync.WaitGroupПроектирование потокобезопасных структурПовторение — Worker Pool