Menu
Coddy logo textTech

Разработка игрового персонажа

Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy — урок 86 из 87.

В этом испытании вам предстоит создать систему разработки игровых персонажей, которая демонстрирует возможности ООП в моделировании сложных интерактивных сущностей.

Спроектируйте иерархию персонажей, в которой базовый класс Character определяет общие атрибуты, такие как здоровье, имя и уровень. Специализированные классы, такие как Warrior, Mage и Archer, расширяют эту базу уникальными способностями и стилями боя.

Интерфейсы здесь работают естественным образом: Attackable может определять методы боя, в то время как Healable управляет способностями к восстановлению. Mage может реализовывать и то, и другое, в то время как Warrior сосредоточен только на атаке.

Рассмотрите возможность использования паттерна «Стратегия» (Strategy) для реализации различных типов поведения при атаке, что позволит персонажам динамически переключать стили боя. Паттерн «Состояние» (State) может управлять такими состояниями персонажа, как обычное, отравление или оглушение, которые влияют на его поведение.

Подумайте об использовании композиции для систем экипировки, где персонажи «имеют» оружие и броню, а не наследуют их. Используйте перечисления (enums) для классов персонажей или типов урона и применяйте инкапсуляцию для защиты характеристик от некорректных изменений.

challenge icon

Задание

Легко

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

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

  • 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:strength
    • CREATE_MAGE:name:maxHealth:level:intelligence:mana
    • ATTACK:attackerName:targetName
    • HEAL:mageName:amount
    • STATUS: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 ---"
        // Затем выведите статус каждого персонажа
    }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

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