Разработка игрового персонажа
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy — урок 86 из 87.
В этом испытании вам предстоит создать систему разработки игровых персонажей, которая демонстрирует возможности ООП в моделировании сложных интерактивных сущностей.
Спроектируйте иерархию персонажей, в которой базовый класс Character определяет общие атрибуты, такие как здоровье, имя и уровень. Специализированные классы, такие как Warrior, Mage и Archer, расширяют эту базу уникальными способностями и стилями боя.
Интерфейсы здесь работают естественным образом: Attackable может определять методы боя, в то время как Healable управляет способностями к восстановлению. Mage может реализовывать и то, и другое, в то время как Warrior сосредоточен только на атаке.
Рассмотрите возможность использования паттерна «Стратегия» (Strategy) для реализации различных типов поведения при атаке, что позволит персонажам динамически переключать стили боя. Паттерн «Состояние» (State) может управлять такими состояниями персонажа, как обычное, отравление или оглушение, которые влияют на его поведение.
Подумайте об использовании композиции для систем экипировки, где персонажи «имеют» оружие и броню, а не наследуют их. Используйте перечисления (enums) для классов персонажей или типов урона и применяйте инкапсуляцию для защиты характеристик от некорректных изменений.
Задание
ЛегкоДавайте создадим систему разработки игровых персонажей, которая продемонстрирует мощь ООП при моделировании сложных интерактивных игровых сущностей! Вы создадите иерархию персонажей с различными стилями боя, специальными способностями и системой состояний, которая влияет на поведение персонажей.
Вы организуете свой код в семи файлах:
DamageType.java: Создайте перечисление (enum), представляющее различные типы урона в игре. Включите значенияPHYSICAL,MAGICALиRANGED. Добавьте приватное полеdescription(String), конструктор, который его устанавливает, и геттер. Физический урон должен иметь описание "brute force", магический — "arcane energy", а дальнобойный — "precision strike".Attackable.java: Создайте интерфейс, определяющий боевые возможности. Объявите методыattack(Character target), который возвращает String с описанием атаки, иgetDamageType(), который возвращает DamageType.Healable.java: Создайте интерфейс для способностей к исцелению. Объявите методheal(int amount), который возвращает String с описанием действия исцеления.Character.java: Создайте абстрактный базовый класс для всех игровых персонажей. Включите приватные поля дляname(String),health(int),maxHealth(int) иlevel(int). Конструктор принимает name, maxHealth и level, изначально устанавливая health равным maxHealth. Включите геттеры для всех полей. Добавьте защищенный методsetHealth(int health), который гарантирует, что здоровье остается в пределах от 0 до maxHealth. Создайте методtakeDamage(int damage), который уменьшает здоровье и возвращает"[name] takes [damage] damage! Health: [health]/[maxHealth]". Добавьте методisAlive(), возвращающий true, если здоровье больше 0. Объявите абстрактный методgetCharacterClass(), возвращающий String.Warrior.java: Создайте класс, расширяющий Character и реализующий Attackable. Добавьте приватное полеstrength(int). Конструктор принимает name, maxHealth, level и strength. РеализуйтеgetCharacterClass(), чтобы он возвращал"Warrior". РеализуйтеgetDamageType(), чтобы он возвращалPHYSICAL. Реализуйтеattack(Character target), чтобы наносить урон, равный strength плюс level, вызывать метод takeDamage цели и возвращать"[name] strikes with [damageType description] for [damage] damage!", за которым следует символ новой строки и результат takeDamage.Mage.java: Создайте класс, расширяющий Character и реализующий как Attackable, так и Healable. Добавьте приватные поляintelligence(int) иmana(int). Конструктор принимает name, maxHealth, level, intelligence и mana. РеализуйтеgetCharacterClass(), чтобы он возвращал"Mage". РеализуйтеgetDamageType(), чтобы он возвращалMAGICAL. Реализуйтеattack(Character target), чтобы наносить урон, равный intelligence умноженному на 2, следуя тому же формату, что и Warrior. Реализуйтеheal(int amount)для восстановления здоровья (используя setHealth) и возврата"[name] channels healing magic! Health: [health]/[maxHealth]".Main.java: Оживите вашу игровую систему! Вы получите строку команд, разделенных запятыми:CREATE_WARRIOR:name:maxHealth:level:strengthCREATE_MAGE:name:maxHealth:level:intelligence:manaATTACK:attackerName:targetNameHEAL:mageName:amountSTATUS:characterName
Поддерживайте коллекцию персонажей. Обработайте каждую команду и выведите:
- CREATE_WARRIOR/CREATE_MAGE:
[name] the [characterClass] joins the battle! - ATTACK: Выведите результат атаки (строку, возвращаемую методом attack)
- HEAL: Выведите результат исцеления или
[name] cannot heal, если персонаж не является магом (Mage) - STATUS:
[name] ([characterClass]) - Level [level] - Health: [health]/[maxHealth] - [Alive/Defeated]
После всех команд выведите
--- Battle Summary ---, а затем статус каждого персонажа.
Вы получите один входной параметр: строку команд, разделенных запятыми.
Например, при вводе CREATE_WARRIOR:Thorin:100:5:15,CREATE_MAGE:Gandalf:80:7:12:50,ATTACK:Thorin:Gandalf,HEAL:Gandalf:25,STATUS:Gandalf, ваш вывод будет следующим:
Thorin the Warrior joins the battle!
Gandalf the Mage joins the battle!
Thorin strikes with brute force for 20 damage!
Gandalf takes 20 damage! Health: 60/80
Gandalf channels healing magic! Health: 80/80
Gandalf (Mage) - Level 7 - Health: 80/80 - Alive
--- Battle Summary ---
Thorin (Warrior) - Level 5 - Health: 100/100 - Alive
Gandalf (Mage) - Level 7 - Health: 80/80 - AliveЭта задача объединяет наследование (иерархия Character), реализацию нескольких интерфейсов (Mage реализует и Attackable, и Healable), перечисления с методами (DamageType), полиморфизм (единообразная работа с различными типами персонажей) и инкапсуляцию (защищенное управление здоровьем) в увлекательную игровую систему!
Шпаргалка
Объектно-ориентированное программирование (ООП) позволяет моделировать сложные системы с помощью классов, наследования, интерфейсов и паттернов проектирования.
Иерархия классов
Создайте базовый класс с общими атрибутами и расширьте его специализированными классами:
public abstract class Character {
private String name;
private int health;
private int maxHealth;
private int level;
public Character(String name, int maxHealth, int level) {
this.name = name;
this.maxHealth = maxHealth;
this.health = maxHealth;
this.level = level;
}
protected void setHealth(int health) {
this.health = Math.max(0, Math.min(health, maxHealth));
}
public abstract String getCharacterClass();
}Интерфейсы
Определяйте контракты для конкретных поведений, которые могут реализовывать классы:
public interface Attackable {
String attack(Character target);
DamageType getDamageType();
}
public interface Healable {
String heal(int amount);
}Перечисления (Enums) с полями
Перечисления могут иметь поля, конструкторы и методы:
public enum DamageType {
PHYSICAL("brute force"),
MAGICAL("arcane energy"),
RANGED("precision strike");
private String description;
private DamageType(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}Реализация нескольких интерфейсов
Класс может реализовывать несколько интерфейсов:
public class Mage extends Character implements Attackable, Healable {
private int intelligence;
private int mana;
@Override
public String attack(Character target) {
// Реализация
}
@Override
public String heal(int amount) {
// Реализация
}
}Инкапсуляция
Используйте приватные поля с защищенными сеттерами для управления доступом и валидации данных:
protected void setHealth(int health) {
this.health = Math.max(0, Math.min(health, maxHealth));
}Полиморфизм
Работайте с различными типами персонажей единообразно через их общий базовый класс или интерфейсы, что позволяет использовать гибкие коллекции и вызовы методов.
Попробуйте сами
import java.util.Scanner;
import java.util.HashMap;
import java.util.Map;
import java.util.LinkedHashMap;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
// TODO: Используйте коллекцию для хранения персонажей (LinkedHashMap сохраняет порядок вставки)
// LinkedHashMap<String, Character> characters = new LinkedHashMap<>();
// TODO: Разделите входные данные запятой, чтобы получить отдельные команды
// String[] commands = input.split(",");
// TODO: Обработайте каждую команду:
// - CREATE_WARRIOR:name:maxHealth:level:strength
// Выведите: "[name] the Warrior joins the battle!"
//
// - CREATE_MAGE:name:maxHealth:level:intelligence:mana
// Выведите: "[name] the Mage joins the battle!"
//
// - ATTACK:attackerName:targetName
// Выведите результат атаки из метода attack
//
// - HEAL:mageName:amount
// Выведите результат исцеления или "[name] cannot heal", если это не Mage
//
// - STATUS:characterName
// Выведите: "[name] ([characterClass]) - Level [level] - Health: [health]/[maxHealth] - [Alive/Defeated]"
// TODO: После всех команд выведите "--- Battle Summary ---"
// Затем выведите статус каждого персонажа
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово thisМетодыПоля (атрибуты)Метод-конструкторПерегрузка конструкторовИтоги — Простой калькулятор4Наследование
Основы наследования (extends)Ключевое слово superПереопределение методов (@Override)Цепочка конструкторовКласс ObjectОдиночное и многоуровневое наследованиеПочему нет множественного наследования классовИтоги — Иерархия сотрудников7Специальные методы и класс Object
Метод toString()equals() и hashCode()Метод clone()compareTo() и ComparableИнтерфейс ComparatorПовторение — Кастомная сортировка2Модификаторы доступа и инкапсуляция
Обзор уровней доступаМетоды геттеры и сеттерыСокрытие данныхКлючевое слово finalИтоги — Менеджер банковского счета5Полиморфизм
Основы перегрузки методовПереопределение методов (Run-Time)Upcasting и DowncastingОператор instanceofАбстрактные классы и методыИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияАгрегация против композицииВнутренние, вложенные и анонимные классыEnums и методы перечисленийRecords (Java 16+)Sealed-классы (Java 17+)11Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy14Финальные испытания
Платформа онлайн-обученияБанковская системаРазработка игрового персонажаСервис аренды транспорта3Свойства класса и статические члены
Переменные экземпляра и статические переменныеСтатические методыСтатические блокиКонстанты (static final)Итоги: Счетчик и утилиты6Интерфейсы и абстрактные классы
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовDefault и Static методы в интерфейсахАбстрактные классы vs ИнтерфейсыФункциональные интерфейсыИтоги — Платежная система9Обобщения
Введение в обобщенияОбобщенные классыОбобщенные методыОграниченные параметры типаСимволы подстановки (Wildcards: ?, extends, super)Итоги — Обобщенный контейнер12Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»